blob: ae8cd8926456b51763e029ba541984ed9f663d06 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
David Howells17926a72007-04-26 15:48:28 -07002/* Kerberos-based RxRPC security
3 *
4 * Copyright (C) 2007 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
David Howells17926a72007-04-26 15:48:28 -07006 */
7
Joe Perches9b6d5392016-06-02 12:08:52 -07008#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9
Herbert Xu1afe5932016-01-24 21:19:01 +080010#include <crypto/skcipher.h>
David Howells17926a72007-04-26 15:48:28 -070011#include <linux/module.h>
12#include <linux/net.h>
13#include <linux/skbuff.h>
14#include <linux/udp.h>
David Howells17926a72007-04-26 15:48:28 -070015#include <linux/scatterlist.h>
16#include <linux/ctype.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090017#include <linux/slab.h>
David Howells17926a72007-04-26 15:48:28 -070018#include <net/sock.h>
19#include <net/af_rxrpc.h>
David Howells33941282009-09-14 01:17:35 +000020#include <keys/rxrpc-type.h>
David Howells17926a72007-04-26 15:48:28 -070021#include "ar-internal.h"
22
23#define RXKAD_VERSION 2
24#define MAXKRB5TICKETLEN 1024
25#define RXKAD_TKT_TYPE_KERBEROS_V5 256
26#define ANAME_SZ 40 /* size of authentication name */
27#define INST_SZ 40 /* size of principal's instance */
28#define REALM_SZ 40 /* size of principal's auth domain */
29#define SNAME_SZ 40 /* size of service name */
30
David Howells17926a72007-04-26 15:48:28 -070031struct rxkad_level1_hdr {
32 __be32 data_size; /* true data size (excluding padding) */
33};
34
35struct rxkad_level2_hdr {
36 __be32 data_size; /* true data size (excluding padding) */
37 __be32 checksum; /* decrypted data checksum */
38};
39
David Howells17926a72007-04-26 15:48:28 -070040/*
41 * this holds a pinned cipher so that keventd doesn't get called by the cipher
42 * alloc routine, but since we have it to hand, we use it to decrypt RESPONSE
43 * packets
44 */
Kees Cook69d826f2018-09-18 19:10:47 -070045static struct crypto_sync_skcipher *rxkad_ci;
David Howells17926a72007-04-26 15:48:28 -070046static DEFINE_MUTEX(rxkad_ci_mutex);
47
48/*
49 * initialise connection security
50 */
51static int rxkad_init_connection_security(struct rxrpc_connection *conn)
52{
Kees Cook69d826f2018-09-18 19:10:47 -070053 struct crypto_sync_skcipher *ci;
David Howells33941282009-09-14 01:17:35 +000054 struct rxrpc_key_token *token;
David Howells17926a72007-04-26 15:48:28 -070055 int ret;
56
David Howells19ffa012016-04-04 14:00:36 +010057 _enter("{%d},{%x}", conn->debug_id, key_serial(conn->params.key));
David Howells17926a72007-04-26 15:48:28 -070058
David Howells19ffa012016-04-04 14:00:36 +010059 token = conn->params.key->payload.data[0];
David Howells33941282009-09-14 01:17:35 +000060 conn->security_ix = token->security_index;
David Howells17926a72007-04-26 15:48:28 -070061
Kees Cook69d826f2018-09-18 19:10:47 -070062 ci = crypto_alloc_sync_skcipher("pcbc(fcrypt)", 0, 0);
David Howells17926a72007-04-26 15:48:28 -070063 if (IS_ERR(ci)) {
64 _debug("no cipher");
65 ret = PTR_ERR(ci);
66 goto error;
67 }
68
Kees Cook69d826f2018-09-18 19:10:47 -070069 if (crypto_sync_skcipher_setkey(ci, token->kad->session_key,
Herbert Xu1afe5932016-01-24 21:19:01 +080070 sizeof(token->kad->session_key)) < 0)
David Howells17926a72007-04-26 15:48:28 -070071 BUG();
72
David Howells19ffa012016-04-04 14:00:36 +010073 switch (conn->params.security_level) {
David Howells17926a72007-04-26 15:48:28 -070074 case RXRPC_SECURITY_PLAIN:
75 break;
76 case RXRPC_SECURITY_AUTH:
77 conn->size_align = 8;
78 conn->security_size = sizeof(struct rxkad_level1_hdr);
David Howells17926a72007-04-26 15:48:28 -070079 break;
80 case RXRPC_SECURITY_ENCRYPT:
81 conn->size_align = 8;
82 conn->security_size = sizeof(struct rxkad_level2_hdr);
David Howells17926a72007-04-26 15:48:28 -070083 break;
84 default:
85 ret = -EKEYREJECTED;
86 goto error;
87 }
88
89 conn->cipher = ci;
90 ret = 0;
91error:
92 _leave(" = %d", ret);
93 return ret;
94}
95
96/*
97 * prime the encryption state with the invariant parts of a connection's
98 * description
99 */
Herbert Xua2636292016-06-26 14:55:24 -0700100static int rxkad_prime_packet_security(struct rxrpc_connection *conn)
David Howells17926a72007-04-26 15:48:28 -0700101{
David Howells33941282009-09-14 01:17:35 +0000102 struct rxrpc_key_token *token;
Kees Cook69d826f2018-09-18 19:10:47 -0700103 SYNC_SKCIPHER_REQUEST_ON_STACK(req, conn->cipher);
Herbert Xua2636292016-06-26 14:55:24 -0700104 struct scatterlist sg;
David Howells17926a72007-04-26 15:48:28 -0700105 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700106 __be32 *tmpbuf;
107 size_t tmpsize = 4 * sizeof(__be32);
David Howells17926a72007-04-26 15:48:28 -0700108
109 _enter("");
110
David Howells19ffa012016-04-04 14:00:36 +0100111 if (!conn->params.key)
Herbert Xua2636292016-06-26 14:55:24 -0700112 return 0;
113
114 tmpbuf = kmalloc(tmpsize, GFP_KERNEL);
115 if (!tmpbuf)
116 return -ENOMEM;
David Howells17926a72007-04-26 15:48:28 -0700117
David Howells19ffa012016-04-04 14:00:36 +0100118 token = conn->params.key->payload.data[0];
David Howells33941282009-09-14 01:17:35 +0000119 memcpy(&iv, token->kad->session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700120
Herbert Xua2636292016-06-26 14:55:24 -0700121 tmpbuf[0] = htonl(conn->proto.epoch);
122 tmpbuf[1] = htonl(conn->proto.cid);
123 tmpbuf[2] = 0;
124 tmpbuf[3] = htonl(conn->security_ix);
David Howells17926a72007-04-26 15:48:28 -0700125
Herbert Xua2636292016-06-26 14:55:24 -0700126 sg_init_one(&sg, tmpbuf, tmpsize);
Kees Cook69d826f2018-09-18 19:10:47 -0700127 skcipher_request_set_sync_tfm(req, conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800128 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700129 skcipher_request_set_crypt(req, &sg, &sg, tmpsize, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800130 crypto_skcipher_encrypt(req);
131 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700132
Herbert Xua2636292016-06-26 14:55:24 -0700133 memcpy(&conn->csum_iv, tmpbuf + 2, sizeof(conn->csum_iv));
134 kfree(tmpbuf);
135 _leave(" = 0");
136 return 0;
David Howells17926a72007-04-26 15:48:28 -0700137}
138
139/*
140 * partially encrypt a packet (level 1 security)
141 */
142static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
143 struct sk_buff *skb,
144 u32 data_size,
Kees Cook54424d32018-08-03 10:15:25 +0100145 void *sechdr,
146 struct skcipher_request *req)
David Howells17926a72007-04-26 15:48:28 -0700147{
David Howellsfb46f6e2017-04-06 10:12:00 +0100148 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
Herbert Xua2636292016-06-26 14:55:24 -0700149 struct rxkad_level1_hdr hdr;
David Howells17926a72007-04-26 15:48:28 -0700150 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700151 struct scatterlist sg;
David Howells17926a72007-04-26 15:48:28 -0700152 u16 check;
153
David Howells17926a72007-04-26 15:48:28 -0700154 _enter("");
155
David Howells5a924b82016-09-22 00:29:31 +0100156 check = sp->hdr.seq ^ call->call_id;
David Howells0d12f8a2016-03-04 15:53:46 +0000157 data_size |= (u32)check << 16;
David Howells17926a72007-04-26 15:48:28 -0700158
Herbert Xua2636292016-06-26 14:55:24 -0700159 hdr.data_size = htonl(data_size);
160 memcpy(sechdr, &hdr, sizeof(hdr));
David Howells17926a72007-04-26 15:48:28 -0700161
162 /* start the encryption afresh */
163 memset(&iv, 0, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700164
Herbert Xua2636292016-06-26 14:55:24 -0700165 sg_init_one(&sg, sechdr, 8);
Kees Cook69d826f2018-09-18 19:10:47 -0700166 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800167 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700168 skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800169 crypto_skcipher_encrypt(req);
170 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700171
David Howells17926a72007-04-26 15:48:28 -0700172 _leave(" = 0");
173 return 0;
174}
175
176/*
177 * wholly encrypt a packet (level 2 security)
178 */
179static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
David Howellsb4f13422016-03-04 15:56:19 +0000180 struct sk_buff *skb,
181 u32 data_size,
Kees Cook54424d32018-08-03 10:15:25 +0100182 void *sechdr,
183 struct skcipher_request *req)
David Howells17926a72007-04-26 15:48:28 -0700184{
David Howells33941282009-09-14 01:17:35 +0000185 const struct rxrpc_key_token *token;
Herbert Xua2636292016-06-26 14:55:24 -0700186 struct rxkad_level2_hdr rxkhdr;
David Howells17926a72007-04-26 15:48:28 -0700187 struct rxrpc_skb_priv *sp;
David Howells17926a72007-04-26 15:48:28 -0700188 struct rxrpc_crypt iv;
189 struct scatterlist sg[16];
190 struct sk_buff *trailer;
Eric Dumazet95c96172012-04-15 05:58:06 +0000191 unsigned int len;
David Howells17926a72007-04-26 15:48:28 -0700192 u16 check;
193 int nsg;
Herbert Xu1afe5932016-01-24 21:19:01 +0800194 int err;
David Howells17926a72007-04-26 15:48:28 -0700195
196 sp = rxrpc_skb(skb);
197
198 _enter("");
199
David Howells5a924b82016-09-22 00:29:31 +0100200 check = sp->hdr.seq ^ call->call_id;
David Howells17926a72007-04-26 15:48:28 -0700201
David Howells0d12f8a2016-03-04 15:53:46 +0000202 rxkhdr.data_size = htonl(data_size | (u32)check << 16);
David Howells17926a72007-04-26 15:48:28 -0700203 rxkhdr.checksum = 0;
Herbert Xua2636292016-06-26 14:55:24 -0700204 memcpy(sechdr, &rxkhdr, sizeof(rxkhdr));
David Howells17926a72007-04-26 15:48:28 -0700205
206 /* encrypt from the session key */
David Howells19ffa012016-04-04 14:00:36 +0100207 token = call->conn->params.key->payload.data[0];
David Howells33941282009-09-14 01:17:35 +0000208 memcpy(&iv, token->kad->session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700209
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700210 sg_init_one(&sg[0], sechdr, sizeof(rxkhdr));
Kees Cook69d826f2018-09-18 19:10:47 -0700211 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800212 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700213 skcipher_request_set_crypt(req, &sg[0], &sg[0], sizeof(rxkhdr), iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800214 crypto_skcipher_encrypt(req);
David Howells17926a72007-04-26 15:48:28 -0700215
216 /* we want to encrypt the skbuff in-place */
217 nsg = skb_cow_data(skb, 0, &trailer);
Herbert Xu1afe5932016-01-24 21:19:01 +0800218 err = -ENOMEM;
David Howells17926a72007-04-26 15:48:28 -0700219 if (nsg < 0 || nsg > 16)
Herbert Xu1afe5932016-01-24 21:19:01 +0800220 goto out;
David Howells17926a72007-04-26 15:48:28 -0700221
222 len = data_size + call->conn->size_align - 1;
223 len &= ~(call->conn->size_align - 1);
224
David S. Miller51c739d2007-10-30 21:29:29 -0700225 sg_init_table(sg, nsg);
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200226 err = skb_to_sgvec(skb, sg, 0, len);
227 if (unlikely(err < 0))
228 goto out;
Herbert Xu1afe5932016-01-24 21:19:01 +0800229 skcipher_request_set_crypt(req, sg, sg, len, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800230 crypto_skcipher_encrypt(req);
David Howells17926a72007-04-26 15:48:28 -0700231
232 _leave(" = 0");
Herbert Xu1afe5932016-01-24 21:19:01 +0800233 err = 0;
234
235out:
236 skcipher_request_zero(req);
237 return err;
David Howells17926a72007-04-26 15:48:28 -0700238}
239
240/*
241 * checksum an RxRPC packet header
242 */
Herbert Xua2636292016-06-26 14:55:24 -0700243static int rxkad_secure_packet(struct rxrpc_call *call,
David Howellsb4f13422016-03-04 15:56:19 +0000244 struct sk_buff *skb,
245 size_t data_size,
246 void *sechdr)
David Howells17926a72007-04-26 15:48:28 -0700247{
248 struct rxrpc_skb_priv *sp;
Kees Cook69d826f2018-09-18 19:10:47 -0700249 SYNC_SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
David Howells17926a72007-04-26 15:48:28 -0700250 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700251 struct scatterlist sg;
David Howells0d12f8a2016-03-04 15:53:46 +0000252 u32 x, y;
David Howells17926a72007-04-26 15:48:28 -0700253 int ret;
254
255 sp = rxrpc_skb(skb);
256
257 _enter("{%d{%x}},{#%u},%zu,",
David Howells19ffa012016-04-04 14:00:36 +0100258 call->debug_id, key_serial(call->conn->params.key),
259 sp->hdr.seq, data_size);
David Howells17926a72007-04-26 15:48:28 -0700260
261 if (!call->conn->cipher)
262 return 0;
263
David Howells19ffa012016-04-04 14:00:36 +0100264 ret = key_validate(call->conn->params.key);
David Howells17926a72007-04-26 15:48:28 -0700265 if (ret < 0)
266 return ret;
267
268 /* continue encrypting from where we left off */
269 memcpy(&iv, call->conn->csum_iv.x, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700270
271 /* calculate the security checksum */
David Howells01a90a42016-08-23 15:27:24 +0100272 x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
David Howells0d12f8a2016-03-04 15:53:46 +0000273 x |= sp->hdr.seq & 0x3fffffff;
David Howells5a924b82016-09-22 00:29:31 +0100274 call->crypto_buf[0] = htonl(call->call_id);
Herbert Xua2636292016-06-26 14:55:24 -0700275 call->crypto_buf[1] = htonl(x);
David Howells17926a72007-04-26 15:48:28 -0700276
Herbert Xua2636292016-06-26 14:55:24 -0700277 sg_init_one(&sg, call->crypto_buf, 8);
Kees Cook69d826f2018-09-18 19:10:47 -0700278 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800279 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700280 skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800281 crypto_skcipher_encrypt(req);
282 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700283
Herbert Xua2636292016-06-26 14:55:24 -0700284 y = ntohl(call->crypto_buf[1]);
Al Viro91e916c2008-03-29 03:08:38 +0000285 y = (y >> 16) & 0xffff;
286 if (y == 0)
287 y = 1; /* zero checksums are not permitted */
David Howells0d12f8a2016-03-04 15:53:46 +0000288 sp->hdr.cksum = y;
David Howells17926a72007-04-26 15:48:28 -0700289
David Howells19ffa012016-04-04 14:00:36 +0100290 switch (call->conn->params.security_level) {
David Howells17926a72007-04-26 15:48:28 -0700291 case RXRPC_SECURITY_PLAIN:
292 ret = 0;
293 break;
294 case RXRPC_SECURITY_AUTH:
Kees Cook54424d32018-08-03 10:15:25 +0100295 ret = rxkad_secure_packet_auth(call, skb, data_size, sechdr,
296 req);
David Howells17926a72007-04-26 15:48:28 -0700297 break;
298 case RXRPC_SECURITY_ENCRYPT:
299 ret = rxkad_secure_packet_encrypt(call, skb, data_size,
Kees Cook54424d32018-08-03 10:15:25 +0100300 sechdr, req);
David Howells17926a72007-04-26 15:48:28 -0700301 break;
302 default:
303 ret = -EPERM;
304 break;
305 }
306
Al Viro91e916c2008-03-29 03:08:38 +0000307 _leave(" = %d [set %hx]", ret, y);
David Howells17926a72007-04-26 15:48:28 -0700308 return ret;
309}
310
311/*
312 * decrypt partial encryption on a packet (level 1 security)
313 */
David Howells5a429762016-09-06 22:19:51 +0100314static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
David Howells248f2192016-09-08 11:10:12 +0100315 unsigned int offset, unsigned int len,
Kees Cook54424d32018-08-03 10:15:25 +0100316 rxrpc_seq_t seq,
317 struct skcipher_request *req)
David Howells17926a72007-04-26 15:48:28 -0700318{
319 struct rxkad_level1_hdr sechdr;
David Howells17926a72007-04-26 15:48:28 -0700320 struct rxrpc_crypt iv;
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700321 struct scatterlist sg[16];
David Howells17926a72007-04-26 15:48:28 -0700322 struct sk_buff *trailer;
David Howellsfb46f6e2017-04-06 10:12:00 +0100323 bool aborted;
David Howells17926a72007-04-26 15:48:28 -0700324 u32 data_size, buf;
325 u16 check;
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200326 int nsg, ret;
David Howells17926a72007-04-26 15:48:28 -0700327
328 _enter("");
329
David Howells248f2192016-09-08 11:10:12 +0100330 if (len < 8) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100331 aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_hdr", "V1H",
332 RXKADSEALEDINCON);
David Howells5a429762016-09-06 22:19:51 +0100333 goto protocol_error;
334 }
David Howells17926a72007-04-26 15:48:28 -0700335
David Howells248f2192016-09-08 11:10:12 +0100336 /* Decrypt the skbuff in-place. TODO: We really want to decrypt
337 * directly into the target buffer.
338 */
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700339 nsg = skb_cow_data(skb, 0, &trailer);
340 if (nsg < 0 || nsg > 16)
David Howells17926a72007-04-26 15:48:28 -0700341 goto nomem;
342
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700343 sg_init_table(sg, nsg);
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200344 ret = skb_to_sgvec(skb, sg, offset, 8);
345 if (unlikely(ret < 0))
346 return ret;
David Howells17926a72007-04-26 15:48:28 -0700347
348 /* start the decryption afresh */
349 memset(&iv, 0, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700350
Kees Cook69d826f2018-09-18 19:10:47 -0700351 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800352 skcipher_request_set_callback(req, 0, NULL, NULL);
353 skcipher_request_set_crypt(req, sg, sg, 8, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800354 crypto_skcipher_decrypt(req);
355 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700356
David Howells5a429762016-09-06 22:19:51 +0100357 /* Extract the decrypted packet length */
David Howells248f2192016-09-08 11:10:12 +0100358 if (skb_copy_bits(skb, offset, &sechdr, sizeof(sechdr)) < 0) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100359 aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_len", "XV1",
360 RXKADDATALEN);
David Howells5a429762016-09-06 22:19:51 +0100361 goto protocol_error;
362 }
David Howells248f2192016-09-08 11:10:12 +0100363 offset += sizeof(sechdr);
364 len -= sizeof(sechdr);
David Howells17926a72007-04-26 15:48:28 -0700365
366 buf = ntohl(sechdr.data_size);
367 data_size = buf & 0xffff;
368
369 check = buf >> 16;
David Howells5a429762016-09-06 22:19:51 +0100370 check ^= seq ^ call->call_id;
David Howells17926a72007-04-26 15:48:28 -0700371 check &= 0xffff;
372 if (check != 0) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100373 aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_check", "V1C",
374 RXKADSEALEDINCON);
David Howells17926a72007-04-26 15:48:28 -0700375 goto protocol_error;
376 }
377
David Howells248f2192016-09-08 11:10:12 +0100378 if (data_size > len) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100379 aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_datalen", "V1L",
380 RXKADDATALEN);
David Howells5a429762016-09-06 22:19:51 +0100381 goto protocol_error;
382 }
David Howells17926a72007-04-26 15:48:28 -0700383
384 _leave(" = 0 [dlen=%x]", data_size);
385 return 0;
386
David Howells17926a72007-04-26 15:48:28 -0700387protocol_error:
David Howellsfb46f6e2017-04-06 10:12:00 +0100388 if (aborted)
389 rxrpc_send_abort_packet(call);
David Howells17926a72007-04-26 15:48:28 -0700390 return -EPROTO;
391
392nomem:
393 _leave(" = -ENOMEM");
394 return -ENOMEM;
395}
396
397/*
398 * wholly decrypt a packet (level 2 security)
399 */
David Howells5a429762016-09-06 22:19:51 +0100400static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
David Howells248f2192016-09-08 11:10:12 +0100401 unsigned int offset, unsigned int len,
Kees Cook54424d32018-08-03 10:15:25 +0100402 rxrpc_seq_t seq,
403 struct skcipher_request *req)
David Howells17926a72007-04-26 15:48:28 -0700404{
David Howells33941282009-09-14 01:17:35 +0000405 const struct rxrpc_key_token *token;
David Howells17926a72007-04-26 15:48:28 -0700406 struct rxkad_level2_hdr sechdr;
David Howells17926a72007-04-26 15:48:28 -0700407 struct rxrpc_crypt iv;
408 struct scatterlist _sg[4], *sg;
409 struct sk_buff *trailer;
David Howellsfb46f6e2017-04-06 10:12:00 +0100410 bool aborted;
David Howells17926a72007-04-26 15:48:28 -0700411 u32 data_size, buf;
412 u16 check;
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200413 int nsg, ret;
David Howells17926a72007-04-26 15:48:28 -0700414
415 _enter(",{%d}", skb->len);
416
David Howells248f2192016-09-08 11:10:12 +0100417 if (len < 8) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100418 aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_hdr", "V2H",
419 RXKADSEALEDINCON);
David Howells5a429762016-09-06 22:19:51 +0100420 goto protocol_error;
421 }
David Howells17926a72007-04-26 15:48:28 -0700422
David Howells248f2192016-09-08 11:10:12 +0100423 /* Decrypt the skbuff in-place. TODO: We really want to decrypt
424 * directly into the target buffer.
425 */
David Howells17926a72007-04-26 15:48:28 -0700426 nsg = skb_cow_data(skb, 0, &trailer);
427 if (nsg < 0)
428 goto nomem;
429
430 sg = _sg;
431 if (unlikely(nsg > 4)) {
Kees Cook6da2ec52018-06-12 13:55:00 -0700432 sg = kmalloc_array(nsg, sizeof(*sg), GFP_NOIO);
David Howells17926a72007-04-26 15:48:28 -0700433 if (!sg)
434 goto nomem;
435 }
436
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700437 sg_init_table(sg, nsg);
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200438 ret = skb_to_sgvec(skb, sg, offset, len);
439 if (unlikely(ret < 0)) {
440 if (sg != _sg)
441 kfree(sg);
442 return ret;
443 }
David Howells17926a72007-04-26 15:48:28 -0700444
445 /* decrypt from the session key */
David Howells19ffa012016-04-04 14:00:36 +0100446 token = call->conn->params.key->payload.data[0];
David Howells33941282009-09-14 01:17:35 +0000447 memcpy(&iv, token->kad->session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700448
Kees Cook69d826f2018-09-18 19:10:47 -0700449 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800450 skcipher_request_set_callback(req, 0, NULL, NULL);
David Howells248f2192016-09-08 11:10:12 +0100451 skcipher_request_set_crypt(req, sg, sg, len, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800452 crypto_skcipher_decrypt(req);
453 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700454 if (sg != _sg)
455 kfree(sg);
456
David Howells5a429762016-09-06 22:19:51 +0100457 /* Extract the decrypted packet length */
David Howells248f2192016-09-08 11:10:12 +0100458 if (skb_copy_bits(skb, offset, &sechdr, sizeof(sechdr)) < 0) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100459 aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_len", "XV2",
460 RXKADDATALEN);
David Howells5a429762016-09-06 22:19:51 +0100461 goto protocol_error;
462 }
David Howells248f2192016-09-08 11:10:12 +0100463 offset += sizeof(sechdr);
464 len -= sizeof(sechdr);
David Howells17926a72007-04-26 15:48:28 -0700465
466 buf = ntohl(sechdr.data_size);
467 data_size = buf & 0xffff;
468
469 check = buf >> 16;
David Howells5a429762016-09-06 22:19:51 +0100470 check ^= seq ^ call->call_id;
David Howells17926a72007-04-26 15:48:28 -0700471 check &= 0xffff;
472 if (check != 0) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100473 aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_check", "V2C",
474 RXKADSEALEDINCON);
David Howells17926a72007-04-26 15:48:28 -0700475 goto protocol_error;
476 }
477
David Howells248f2192016-09-08 11:10:12 +0100478 if (data_size > len) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100479 aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_datalen", "V2L",
480 RXKADDATALEN);
David Howells5a429762016-09-06 22:19:51 +0100481 goto protocol_error;
482 }
David Howells17926a72007-04-26 15:48:28 -0700483
484 _leave(" = 0 [dlen=%x]", data_size);
485 return 0;
486
David Howells17926a72007-04-26 15:48:28 -0700487protocol_error:
David Howellsfb46f6e2017-04-06 10:12:00 +0100488 if (aborted)
489 rxrpc_send_abort_packet(call);
David Howells17926a72007-04-26 15:48:28 -0700490 return -EPROTO;
491
492nomem:
493 _leave(" = -ENOMEM");
494 return -ENOMEM;
495}
496
497/*
David Howells5a429762016-09-06 22:19:51 +0100498 * Verify the security on a received packet or subpacket (if part of a
499 * jumbo packet).
David Howells17926a72007-04-26 15:48:28 -0700500 */
David Howells5a429762016-09-06 22:19:51 +0100501static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb,
David Howells248f2192016-09-08 11:10:12 +0100502 unsigned int offset, unsigned int len,
David Howells5a429762016-09-06 22:19:51 +0100503 rxrpc_seq_t seq, u16 expected_cksum)
David Howells17926a72007-04-26 15:48:28 -0700504{
Kees Cook69d826f2018-09-18 19:10:47 -0700505 SYNC_SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
David Howells17926a72007-04-26 15:48:28 -0700506 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700507 struct scatterlist sg;
David Howellsfb46f6e2017-04-06 10:12:00 +0100508 bool aborted;
David Howells0d12f8a2016-03-04 15:53:46 +0000509 u16 cksum;
510 u32 x, y;
David Howells17926a72007-04-26 15:48:28 -0700511
512 _enter("{%d{%x}},{#%u}",
David Howells5a429762016-09-06 22:19:51 +0100513 call->debug_id, key_serial(call->conn->params.key), seq);
David Howells17926a72007-04-26 15:48:28 -0700514
515 if (!call->conn->cipher)
516 return 0;
517
David Howells17926a72007-04-26 15:48:28 -0700518 /* continue encrypting from where we left off */
519 memcpy(&iv, call->conn->csum_iv.x, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700520
521 /* validate the security checksum */
David Howells01a90a42016-08-23 15:27:24 +0100522 x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
David Howells5a429762016-09-06 22:19:51 +0100523 x |= seq & 0x3fffffff;
Herbert Xua2636292016-06-26 14:55:24 -0700524 call->crypto_buf[0] = htonl(call->call_id);
525 call->crypto_buf[1] = htonl(x);
David Howells17926a72007-04-26 15:48:28 -0700526
Herbert Xua2636292016-06-26 14:55:24 -0700527 sg_init_one(&sg, call->crypto_buf, 8);
Kees Cook69d826f2018-09-18 19:10:47 -0700528 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800529 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700530 skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800531 crypto_skcipher_encrypt(req);
532 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700533
Herbert Xua2636292016-06-26 14:55:24 -0700534 y = ntohl(call->crypto_buf[1]);
David Howells0d12f8a2016-03-04 15:53:46 +0000535 cksum = (y >> 16) & 0xffff;
536 if (cksum == 0)
537 cksum = 1; /* zero checksums are not permitted */
David Howells17926a72007-04-26 15:48:28 -0700538
David Howells5a429762016-09-06 22:19:51 +0100539 if (cksum != expected_cksum) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100540 aborted = rxrpc_abort_eproto(call, skb, "rxkad_csum", "VCK",
541 RXKADSEALEDINCON);
542 goto protocol_error;
David Howells17926a72007-04-26 15:48:28 -0700543 }
544
David Howells19ffa012016-04-04 14:00:36 +0100545 switch (call->conn->params.security_level) {
David Howells17926a72007-04-26 15:48:28 -0700546 case RXRPC_SECURITY_PLAIN:
David Howells5a429762016-09-06 22:19:51 +0100547 return 0;
David Howells17926a72007-04-26 15:48:28 -0700548 case RXRPC_SECURITY_AUTH:
Kees Cook54424d32018-08-03 10:15:25 +0100549 return rxkad_verify_packet_1(call, skb, offset, len, seq, req);
David Howells17926a72007-04-26 15:48:28 -0700550 case RXRPC_SECURITY_ENCRYPT:
Kees Cook54424d32018-08-03 10:15:25 +0100551 return rxkad_verify_packet_2(call, skb, offset, len, seq, req);
David Howells17926a72007-04-26 15:48:28 -0700552 default:
David Howells5a429762016-09-06 22:19:51 +0100553 return -ENOANO;
David Howells17926a72007-04-26 15:48:28 -0700554 }
David Howellsfb46f6e2017-04-06 10:12:00 +0100555
556protocol_error:
557 if (aborted)
558 rxrpc_send_abort_packet(call);
559 return -EPROTO;
David Howells17926a72007-04-26 15:48:28 -0700560}
561
562/*
David Howells248f2192016-09-08 11:10:12 +0100563 * Locate the data contained in a packet that was partially encrypted.
564 */
565static void rxkad_locate_data_1(struct rxrpc_call *call, struct sk_buff *skb,
566 unsigned int *_offset, unsigned int *_len)
567{
568 struct rxkad_level1_hdr sechdr;
569
570 if (skb_copy_bits(skb, *_offset, &sechdr, sizeof(sechdr)) < 0)
571 BUG();
572 *_offset += sizeof(sechdr);
573 *_len = ntohl(sechdr.data_size) & 0xffff;
574}
575
576/*
577 * Locate the data contained in a packet that was completely encrypted.
578 */
579static void rxkad_locate_data_2(struct rxrpc_call *call, struct sk_buff *skb,
580 unsigned int *_offset, unsigned int *_len)
581{
582 struct rxkad_level2_hdr sechdr;
583
584 if (skb_copy_bits(skb, *_offset, &sechdr, sizeof(sechdr)) < 0)
585 BUG();
586 *_offset += sizeof(sechdr);
587 *_len = ntohl(sechdr.data_size) & 0xffff;
588}
589
590/*
591 * Locate the data contained in an already decrypted packet.
592 */
593static void rxkad_locate_data(struct rxrpc_call *call, struct sk_buff *skb,
594 unsigned int *_offset, unsigned int *_len)
595{
596 switch (call->conn->params.security_level) {
597 case RXRPC_SECURITY_AUTH:
598 rxkad_locate_data_1(call, skb, _offset, _len);
599 return;
600 case RXRPC_SECURITY_ENCRYPT:
601 rxkad_locate_data_2(call, skb, _offset, _len);
602 return;
603 default:
604 return;
605 }
606}
607
608/*
David Howells17926a72007-04-26 15:48:28 -0700609 * issue a challenge
610 */
611static int rxkad_issue_challenge(struct rxrpc_connection *conn)
612{
613 struct rxkad_challenge challenge;
David Howells0d12f8a2016-03-04 15:53:46 +0000614 struct rxrpc_wire_header whdr;
David Howells17926a72007-04-26 15:48:28 -0700615 struct msghdr msg;
616 struct kvec iov[2];
617 size_t len;
David Howells0d12f8a2016-03-04 15:53:46 +0000618 u32 serial;
David Howells17926a72007-04-26 15:48:28 -0700619 int ret;
620
David Howells19ffa012016-04-04 14:00:36 +0100621 _enter("{%d,%x}", conn->debug_id, key_serial(conn->params.key));
David Howells17926a72007-04-26 15:48:28 -0700622
David Howells19ffa012016-04-04 14:00:36 +0100623 ret = key_validate(conn->params.key);
David Howells17926a72007-04-26 15:48:28 -0700624 if (ret < 0)
625 return ret;
626
627 get_random_bytes(&conn->security_nonce, sizeof(conn->security_nonce));
628
629 challenge.version = htonl(2);
630 challenge.nonce = htonl(conn->security_nonce);
631 challenge.min_level = htonl(0);
632 challenge.__padding = 0;
633
David Howells7b674e32017-08-29 10:18:37 +0100634 msg.msg_name = &conn->params.peer->srx.transport;
635 msg.msg_namelen = conn->params.peer->srx.transport_len;
David Howells17926a72007-04-26 15:48:28 -0700636 msg.msg_control = NULL;
637 msg.msg_controllen = 0;
638 msg.msg_flags = 0;
639
David Howells19ffa012016-04-04 14:00:36 +0100640 whdr.epoch = htonl(conn->proto.epoch);
641 whdr.cid = htonl(conn->proto.cid);
David Howells0d12f8a2016-03-04 15:53:46 +0000642 whdr.callNumber = 0;
643 whdr.seq = 0;
644 whdr.type = RXRPC_PACKET_TYPE_CHALLENGE;
645 whdr.flags = conn->out_clientflag;
646 whdr.userStatus = 0;
647 whdr.securityIndex = conn->security_ix;
648 whdr._rsvd = 0;
David Howells68d6d1a2017-06-05 14:30:49 +0100649 whdr.serviceId = htons(conn->service_id);
David Howells17926a72007-04-26 15:48:28 -0700650
David Howells0d12f8a2016-03-04 15:53:46 +0000651 iov[0].iov_base = &whdr;
652 iov[0].iov_len = sizeof(whdr);
David Howells17926a72007-04-26 15:48:28 -0700653 iov[1].iov_base = &challenge;
654 iov[1].iov_len = sizeof(challenge);
655
656 len = iov[0].iov_len + iov[1].iov_len;
657
David Howells0d12f8a2016-03-04 15:53:46 +0000658 serial = atomic_inc_return(&conn->serial);
659 whdr.serial = htonl(serial);
660 _proto("Tx CHALLENGE %%%u", serial);
David Howells17926a72007-04-26 15:48:28 -0700661
David Howells85f32272016-04-04 14:00:36 +0100662 ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len);
David Howells17926a72007-04-26 15:48:28 -0700663 if (ret < 0) {
David Howells6b47fe12018-05-10 23:26:01 +0100664 trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
David Howells4764c0d2018-07-23 17:18:37 +0100665 rxrpc_tx_point_rxkad_challenge);
David Howells17926a72007-04-26 15:48:28 -0700666 return -EAGAIN;
667 }
668
David Howells330bdcf2018-08-08 11:30:02 +0100669 conn->params.peer->last_tx_at = ktime_get_seconds();
David Howells4764c0d2018-07-23 17:18:37 +0100670 trace_rxrpc_tx_packet(conn->debug_id, &whdr,
671 rxrpc_tx_point_rxkad_challenge);
David Howells17926a72007-04-26 15:48:28 -0700672 _leave(" = 0");
673 return 0;
674}
675
676/*
677 * send a Kerberos security response
678 */
679static int rxkad_send_response(struct rxrpc_connection *conn,
David Howells0d12f8a2016-03-04 15:53:46 +0000680 struct rxrpc_host_header *hdr,
David Howells17926a72007-04-26 15:48:28 -0700681 struct rxkad_response *resp,
682 const struct rxkad_key *s2)
683{
David Howells0d12f8a2016-03-04 15:53:46 +0000684 struct rxrpc_wire_header whdr;
David Howells17926a72007-04-26 15:48:28 -0700685 struct msghdr msg;
686 struct kvec iov[3];
687 size_t len;
David Howells0d12f8a2016-03-04 15:53:46 +0000688 u32 serial;
David Howells17926a72007-04-26 15:48:28 -0700689 int ret;
690
691 _enter("");
692
David Howells7b674e32017-08-29 10:18:37 +0100693 msg.msg_name = &conn->params.peer->srx.transport;
694 msg.msg_namelen = conn->params.peer->srx.transport_len;
David Howells17926a72007-04-26 15:48:28 -0700695 msg.msg_control = NULL;
696 msg.msg_controllen = 0;
697 msg.msg_flags = 0;
698
David Howells0d12f8a2016-03-04 15:53:46 +0000699 memset(&whdr, 0, sizeof(whdr));
700 whdr.epoch = htonl(hdr->epoch);
701 whdr.cid = htonl(hdr->cid);
702 whdr.type = RXRPC_PACKET_TYPE_RESPONSE;
703 whdr.flags = conn->out_clientflag;
704 whdr.securityIndex = hdr->securityIndex;
705 whdr.serviceId = htons(hdr->serviceId);
David Howells17926a72007-04-26 15:48:28 -0700706
David Howells0d12f8a2016-03-04 15:53:46 +0000707 iov[0].iov_base = &whdr;
708 iov[0].iov_len = sizeof(whdr);
David Howells17926a72007-04-26 15:48:28 -0700709 iov[1].iov_base = resp;
710 iov[1].iov_len = sizeof(*resp);
David Howells0d12f8a2016-03-04 15:53:46 +0000711 iov[2].iov_base = (void *)s2->ticket;
David Howells17926a72007-04-26 15:48:28 -0700712 iov[2].iov_len = s2->ticket_len;
713
714 len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
715
David Howells0d12f8a2016-03-04 15:53:46 +0000716 serial = atomic_inc_return(&conn->serial);
717 whdr.serial = htonl(serial);
718 _proto("Tx RESPONSE %%%u", serial);
David Howells17926a72007-04-26 15:48:28 -0700719
David Howells85f32272016-04-04 14:00:36 +0100720 ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 3, len);
David Howells17926a72007-04-26 15:48:28 -0700721 if (ret < 0) {
David Howells6b47fe12018-05-10 23:26:01 +0100722 trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
David Howells4764c0d2018-07-23 17:18:37 +0100723 rxrpc_tx_point_rxkad_response);
David Howells17926a72007-04-26 15:48:28 -0700724 return -EAGAIN;
725 }
726
David Howells330bdcf2018-08-08 11:30:02 +0100727 conn->params.peer->last_tx_at = ktime_get_seconds();
David Howells17926a72007-04-26 15:48:28 -0700728 _leave(" = 0");
729 return 0;
730}
731
732/*
733 * calculate the response checksum
734 */
735static void rxkad_calc_response_checksum(struct rxkad_response *response)
736{
737 u32 csum = 1000003;
738 int loop;
739 u8 *p = (u8 *) response;
740
741 for (loop = sizeof(*response); loop > 0; loop--)
742 csum = csum * 0x10204081 + *p++;
743
744 response->encrypted.checksum = htonl(csum);
745}
746
747/*
David Howells17926a72007-04-26 15:48:28 -0700748 * encrypt the response packet
749 */
750static void rxkad_encrypt_response(struct rxrpc_connection *conn,
751 struct rxkad_response *resp,
752 const struct rxkad_key *s2)
753{
Kees Cook69d826f2018-09-18 19:10:47 -0700754 SYNC_SKCIPHER_REQUEST_ON_STACK(req, conn->cipher);
David Howells17926a72007-04-26 15:48:28 -0700755 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700756 struct scatterlist sg[1];
David Howells17926a72007-04-26 15:48:28 -0700757
758 /* continue encrypting from where we left off */
759 memcpy(&iv, s2->session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700760
Herbert Xua2636292016-06-26 14:55:24 -0700761 sg_init_table(sg, 1);
762 sg_set_buf(sg, &resp->encrypted, sizeof(resp->encrypted));
Kees Cook69d826f2018-09-18 19:10:47 -0700763 skcipher_request_set_sync_tfm(req, conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800764 skcipher_request_set_callback(req, 0, NULL, NULL);
765 skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800766 crypto_skcipher_encrypt(req);
767 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700768}
769
770/*
771 * respond to a challenge packet
772 */
773static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
774 struct sk_buff *skb,
775 u32 *_abort_code)
776{
David Howells33941282009-09-14 01:17:35 +0000777 const struct rxrpc_key_token *token;
David Howells17926a72007-04-26 15:48:28 -0700778 struct rxkad_challenge challenge;
David Howells8c2f8262018-02-08 15:59:07 +0000779 struct rxkad_response *resp;
David Howells248f2192016-09-08 11:10:12 +0100780 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
David Howellsfb46f6e2017-04-06 10:12:00 +0100781 const char *eproto;
David Howells17926a72007-04-26 15:48:28 -0700782 u32 version, nonce, min_level, abort_code;
783 int ret;
784
David Howells19ffa012016-04-04 14:00:36 +0100785 _enter("{%d,%x}", conn->debug_id, key_serial(conn->params.key));
David Howells17926a72007-04-26 15:48:28 -0700786
David Howellsfb46f6e2017-04-06 10:12:00 +0100787 eproto = tracepoint_string("chall_no_key");
David Howellsef686222017-04-06 10:11:59 +0100788 abort_code = RX_PROTOCOL_ERROR;
789 if (!conn->params.key)
790 goto protocol_error;
David Howells17926a72007-04-26 15:48:28 -0700791
David Howellsef686222017-04-06 10:11:59 +0100792 abort_code = RXKADEXPIRED;
David Howells19ffa012016-04-04 14:00:36 +0100793 ret = key_validate(conn->params.key);
David Howellsef686222017-04-06 10:11:59 +0100794 if (ret < 0)
795 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700796
David Howellsfb46f6e2017-04-06 10:12:00 +0100797 eproto = tracepoint_string("chall_short");
David Howells17926a72007-04-26 15:48:28 -0700798 abort_code = RXKADPACKETSHORT;
David Howells775e5b72016-09-30 13:26:03 +0100799 if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
800 &challenge, sizeof(challenge)) < 0)
David Howells17926a72007-04-26 15:48:28 -0700801 goto protocol_error;
802
803 version = ntohl(challenge.version);
804 nonce = ntohl(challenge.nonce);
805 min_level = ntohl(challenge.min_level);
806
807 _proto("Rx CHALLENGE %%%u { v=%u n=%u ml=%u }",
David Howells0d12f8a2016-03-04 15:53:46 +0000808 sp->hdr.serial, version, nonce, min_level);
David Howells17926a72007-04-26 15:48:28 -0700809
David Howellsfb46f6e2017-04-06 10:12:00 +0100810 eproto = tracepoint_string("chall_ver");
David Howells17926a72007-04-26 15:48:28 -0700811 abort_code = RXKADINCONSISTENCY;
812 if (version != RXKAD_VERSION)
813 goto protocol_error;
814
815 abort_code = RXKADLEVELFAIL;
David Howellsef686222017-04-06 10:11:59 +0100816 ret = -EACCES;
David Howells19ffa012016-04-04 14:00:36 +0100817 if (conn->params.security_level < min_level)
David Howellsef686222017-04-06 10:11:59 +0100818 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700819
David Howells19ffa012016-04-04 14:00:36 +0100820 token = conn->params.key->payload.data[0];
David Howells17926a72007-04-26 15:48:28 -0700821
822 /* build the response packet */
David Howells8c2f8262018-02-08 15:59:07 +0000823 resp = kzalloc(sizeof(struct rxkad_response), GFP_NOFS);
824 if (!resp)
825 return -ENOMEM;
David Howells17926a72007-04-26 15:48:28 -0700826
David Howells8c2f8262018-02-08 15:59:07 +0000827 resp->version = htonl(RXKAD_VERSION);
828 resp->encrypted.epoch = htonl(conn->proto.epoch);
829 resp->encrypted.cid = htonl(conn->proto.cid);
830 resp->encrypted.securityIndex = htonl(conn->security_ix);
831 resp->encrypted.inc_nonce = htonl(nonce + 1);
832 resp->encrypted.level = htonl(conn->params.security_level);
833 resp->kvno = htonl(token->kad->kvno);
834 resp->ticket_len = htonl(token->kad->ticket_len);
835 resp->encrypted.call_id[0] = htonl(conn->channels[0].call_counter);
836 resp->encrypted.call_id[1] = htonl(conn->channels[1].call_counter);
837 resp->encrypted.call_id[2] = htonl(conn->channels[2].call_counter);
838 resp->encrypted.call_id[3] = htonl(conn->channels[3].call_counter);
David Howells17926a72007-04-26 15:48:28 -0700839
840 /* calculate the response checksum and then do the encryption */
David Howells8c2f8262018-02-08 15:59:07 +0000841 rxkad_calc_response_checksum(resp);
842 rxkad_encrypt_response(conn, resp, token->kad);
843 ret = rxkad_send_response(conn, &sp->hdr, resp, token->kad);
844 kfree(resp);
845 return ret;
David Howells17926a72007-04-26 15:48:28 -0700846
847protocol_error:
David Howellsfb46f6e2017-04-06 10:12:00 +0100848 trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
David Howellsef686222017-04-06 10:11:59 +0100849 ret = -EPROTO;
850other_error:
David Howells17926a72007-04-26 15:48:28 -0700851 *_abort_code = abort_code;
David Howellsef686222017-04-06 10:11:59 +0100852 return ret;
David Howells17926a72007-04-26 15:48:28 -0700853}
854
855/*
856 * decrypt the kerberos IV ticket in the response
857 */
858static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
David Howellsfb46f6e2017-04-06 10:12:00 +0100859 struct sk_buff *skb,
David Howells17926a72007-04-26 15:48:28 -0700860 void *ticket, size_t ticket_len,
861 struct rxrpc_crypt *_session_key,
Baolin Wang10674a02017-08-29 10:15:40 +0100862 time64_t *_expiry,
David Howells17926a72007-04-26 15:48:28 -0700863 u32 *_abort_code)
864{
Herbert Xu1afe5932016-01-24 21:19:01 +0800865 struct skcipher_request *req;
David Howellsfb46f6e2017-04-06 10:12:00 +0100866 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
David Howells17926a72007-04-26 15:48:28 -0700867 struct rxrpc_crypt iv, key;
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700868 struct scatterlist sg[1];
David Howells17926a72007-04-26 15:48:28 -0700869 struct in_addr addr;
Eric Dumazet95c96172012-04-15 05:58:06 +0000870 unsigned int life;
David Howellsfb46f6e2017-04-06 10:12:00 +0100871 const char *eproto;
Baolin Wang10674a02017-08-29 10:15:40 +0100872 time64_t issue, now;
David Howells17926a72007-04-26 15:48:28 -0700873 bool little_endian;
874 int ret;
David Howellsfb46f6e2017-04-06 10:12:00 +0100875 u32 abort_code;
David Howells17926a72007-04-26 15:48:28 -0700876 u8 *p, *q, *name, *end;
877
878 _enter("{%d},{%x}", conn->debug_id, key_serial(conn->server_key));
879
880 *_expiry = 0;
881
882 ret = key_validate(conn->server_key);
883 if (ret < 0) {
884 switch (ret) {
885 case -EKEYEXPIRED:
David Howellsfb46f6e2017-04-06 10:12:00 +0100886 abort_code = RXKADEXPIRED;
David Howellsef686222017-04-06 10:11:59 +0100887 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700888 default:
David Howellsfb46f6e2017-04-06 10:12:00 +0100889 abort_code = RXKADNOAUTH;
David Howellsef686222017-04-06 10:11:59 +0100890 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700891 }
892 }
893
David Howells146aa8b2015-10-21 14:04:48 +0100894 ASSERT(conn->server_key->payload.data[0] != NULL);
David Howells17926a72007-04-26 15:48:28 -0700895 ASSERTCMP((unsigned long) ticket & 7UL, ==, 0);
896
David Howells146aa8b2015-10-21 14:04:48 +0100897 memcpy(&iv, &conn->server_key->payload.data[2], sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700898
David Howellsef686222017-04-06 10:11:59 +0100899 ret = -ENOMEM;
Herbert Xu1afe5932016-01-24 21:19:01 +0800900 req = skcipher_request_alloc(conn->server_key->payload.data[0],
901 GFP_NOFS);
David Howellsef686222017-04-06 10:11:59 +0100902 if (!req)
903 goto temporary_error;
David Howells17926a72007-04-26 15:48:28 -0700904
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700905 sg_init_one(&sg[0], ticket, ticket_len);
Herbert Xu1afe5932016-01-24 21:19:01 +0800906 skcipher_request_set_callback(req, 0, NULL, NULL);
907 skcipher_request_set_crypt(req, sg, sg, ticket_len, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800908 crypto_skcipher_decrypt(req);
909 skcipher_request_free(req);
David Howells17926a72007-04-26 15:48:28 -0700910
911 p = ticket;
912 end = p + ticket_len;
913
David Howellsfb46f6e2017-04-06 10:12:00 +0100914#define Z(field) \
David Howells17926a72007-04-26 15:48:28 -0700915 ({ \
916 u8 *__str = p; \
David Howellsfb46f6e2017-04-06 10:12:00 +0100917 eproto = tracepoint_string("rxkad_bad_"#field); \
David Howells17926a72007-04-26 15:48:28 -0700918 q = memchr(p, 0, end - p); \
David Howellsfb46f6e2017-04-06 10:12:00 +0100919 if (!q || q - p > (field##_SZ)) \
David Howells17926a72007-04-26 15:48:28 -0700920 goto bad_ticket; \
921 for (; p < q; p++) \
922 if (!isprint(*p)) \
923 goto bad_ticket; \
924 p++; \
925 __str; \
926 })
927
928 /* extract the ticket flags */
929 _debug("KIV FLAGS: %x", *p);
930 little_endian = *p & 1;
931 p++;
932
933 /* extract the authentication name */
David Howellsfb46f6e2017-04-06 10:12:00 +0100934 name = Z(ANAME);
David Howells17926a72007-04-26 15:48:28 -0700935 _debug("KIV ANAME: %s", name);
936
937 /* extract the principal's instance */
David Howellsfb46f6e2017-04-06 10:12:00 +0100938 name = Z(INST);
David Howells17926a72007-04-26 15:48:28 -0700939 _debug("KIV INST : %s", name);
940
941 /* extract the principal's authentication domain */
David Howellsfb46f6e2017-04-06 10:12:00 +0100942 name = Z(REALM);
David Howells17926a72007-04-26 15:48:28 -0700943 _debug("KIV REALM: %s", name);
944
David Howellsfb46f6e2017-04-06 10:12:00 +0100945 eproto = tracepoint_string("rxkad_bad_len");
David Howells17926a72007-04-26 15:48:28 -0700946 if (end - p < 4 + 8 + 4 + 2)
947 goto bad_ticket;
948
949 /* get the IPv4 address of the entity that requested the ticket */
950 memcpy(&addr, p, sizeof(addr));
951 p += 4;
Harvey Harrison21454aa2008-10-31 00:54:56 -0700952 _debug("KIV ADDR : %pI4", &addr);
David Howells17926a72007-04-26 15:48:28 -0700953
954 /* get the session key from the ticket */
955 memcpy(&key, p, sizeof(key));
956 p += 8;
957 _debug("KIV KEY : %08x %08x", ntohl(key.n[0]), ntohl(key.n[1]));
958 memcpy(_session_key, &key, sizeof(key));
959
960 /* get the ticket's lifetime */
961 life = *p++ * 5 * 60;
962 _debug("KIV LIFE : %u", life);
963
964 /* get the issue time of the ticket */
965 if (little_endian) {
966 __le32 stamp;
967 memcpy(&stamp, p, 4);
Baolin Wang10674a02017-08-29 10:15:40 +0100968 issue = rxrpc_u32_to_time64(le32_to_cpu(stamp));
David Howells17926a72007-04-26 15:48:28 -0700969 } else {
970 __be32 stamp;
971 memcpy(&stamp, p, 4);
Baolin Wang10674a02017-08-29 10:15:40 +0100972 issue = rxrpc_u32_to_time64(be32_to_cpu(stamp));
David Howells17926a72007-04-26 15:48:28 -0700973 }
974 p += 4;
Baolin Wang10674a02017-08-29 10:15:40 +0100975 now = ktime_get_real_seconds();
976 _debug("KIV ISSUE: %llx [%llx]", issue, now);
David Howells17926a72007-04-26 15:48:28 -0700977
978 /* check the ticket is in date */
979 if (issue > now) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100980 abort_code = RXKADNOAUTH;
David Howells17926a72007-04-26 15:48:28 -0700981 ret = -EKEYREJECTED;
David Howellsef686222017-04-06 10:11:59 +0100982 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700983 }
984
985 if (issue < now - life) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100986 abort_code = RXKADEXPIRED;
David Howells17926a72007-04-26 15:48:28 -0700987 ret = -EKEYEXPIRED;
David Howellsef686222017-04-06 10:11:59 +0100988 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700989 }
990
991 *_expiry = issue + life;
992
993 /* get the service name */
David Howellsfb46f6e2017-04-06 10:12:00 +0100994 name = Z(SNAME);
David Howells17926a72007-04-26 15:48:28 -0700995 _debug("KIV SNAME: %s", name);
996
997 /* get the service instance name */
David Howellsfb46f6e2017-04-06 10:12:00 +0100998 name = Z(INST);
David Howells17926a72007-04-26 15:48:28 -0700999 _debug("KIV SINST: %s", name);
David Howellsef686222017-04-06 10:11:59 +01001000 return 0;
David Howells17926a72007-04-26 15:48:28 -07001001
1002bad_ticket:
David Howellsfb46f6e2017-04-06 10:12:00 +01001003 trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
1004 abort_code = RXKADBADTICKET;
David Howellsef686222017-04-06 10:11:59 +01001005 ret = -EPROTO;
1006other_error:
David Howellsfb46f6e2017-04-06 10:12:00 +01001007 *_abort_code = abort_code;
David Howellsef686222017-04-06 10:11:59 +01001008 return ret;
1009temporary_error:
1010 return ret;
David Howells17926a72007-04-26 15:48:28 -07001011}
1012
1013/*
1014 * decrypt the response packet
1015 */
1016static void rxkad_decrypt_response(struct rxrpc_connection *conn,
1017 struct rxkad_response *resp,
1018 const struct rxrpc_crypt *session_key)
1019{
Kees Cook69d826f2018-09-18 19:10:47 -07001020 SYNC_SKCIPHER_REQUEST_ON_STACK(req, rxkad_ci);
Herbert Xua2636292016-06-26 14:55:24 -07001021 struct scatterlist sg[1];
David Howells17926a72007-04-26 15:48:28 -07001022 struct rxrpc_crypt iv;
1023
1024 _enter(",,%08x%08x",
1025 ntohl(session_key->n[0]), ntohl(session_key->n[1]));
1026
1027 ASSERT(rxkad_ci != NULL);
1028
1029 mutex_lock(&rxkad_ci_mutex);
Kees Cook69d826f2018-09-18 19:10:47 -07001030 if (crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
Herbert Xu1afe5932016-01-24 21:19:01 +08001031 sizeof(*session_key)) < 0)
David Howells17926a72007-04-26 15:48:28 -07001032 BUG();
1033
1034 memcpy(&iv, session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -07001035
Herbert Xua2636292016-06-26 14:55:24 -07001036 sg_init_table(sg, 1);
1037 sg_set_buf(sg, &resp->encrypted, sizeof(resp->encrypted));
Kees Cook69d826f2018-09-18 19:10:47 -07001038 skcipher_request_set_sync_tfm(req, rxkad_ci);
Herbert Xu1afe5932016-01-24 21:19:01 +08001039 skcipher_request_set_callback(req, 0, NULL, NULL);
1040 skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +08001041 crypto_skcipher_decrypt(req);
1042 skcipher_request_zero(req);
1043
David Howells17926a72007-04-26 15:48:28 -07001044 mutex_unlock(&rxkad_ci_mutex);
1045
1046 _leave("");
1047}
1048
1049/*
1050 * verify a response
1051 */
1052static int rxkad_verify_response(struct rxrpc_connection *conn,
1053 struct sk_buff *skb,
1054 u32 *_abort_code)
1055{
David Howells8c2f8262018-02-08 15:59:07 +00001056 struct rxkad_response *response;
David Howells248f2192016-09-08 11:10:12 +01001057 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
David Howells17926a72007-04-26 15:48:28 -07001058 struct rxrpc_crypt session_key;
David Howellsfb46f6e2017-04-06 10:12:00 +01001059 const char *eproto;
Baolin Wang10674a02017-08-29 10:15:40 +01001060 time64_t expiry;
David Howells17926a72007-04-26 15:48:28 -07001061 void *ticket;
Al Viro91e916c2008-03-29 03:08:38 +00001062 u32 abort_code, version, kvno, ticket_len, level;
1063 __be32 csum;
David Howellsa1399f82016-06-27 14:39:44 +01001064 int ret, i;
David Howells17926a72007-04-26 15:48:28 -07001065
1066 _enter("{%d,%x}", conn->debug_id, key_serial(conn->server_key));
1067
David Howells8c2f8262018-02-08 15:59:07 +00001068 ret = -ENOMEM;
1069 response = kzalloc(sizeof(struct rxkad_response), GFP_NOFS);
1070 if (!response)
1071 goto temporary_error;
1072
David Howellsfb46f6e2017-04-06 10:12:00 +01001073 eproto = tracepoint_string("rxkad_rsp_short");
David Howells17926a72007-04-26 15:48:28 -07001074 abort_code = RXKADPACKETSHORT;
David Howells775e5b72016-09-30 13:26:03 +01001075 if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
David Howells8c2f8262018-02-08 15:59:07 +00001076 response, sizeof(*response)) < 0)
David Howells17926a72007-04-26 15:48:28 -07001077 goto protocol_error;
David Howells8c2f8262018-02-08 15:59:07 +00001078 if (!pskb_pull(skb, sizeof(*response)))
David Howells17926a72007-04-26 15:48:28 -07001079 BUG();
1080
David Howells8c2f8262018-02-08 15:59:07 +00001081 version = ntohl(response->version);
1082 ticket_len = ntohl(response->ticket_len);
1083 kvno = ntohl(response->kvno);
David Howells17926a72007-04-26 15:48:28 -07001084 _proto("Rx RESPONSE %%%u { v=%u kv=%u tl=%u }",
David Howells0d12f8a2016-03-04 15:53:46 +00001085 sp->hdr.serial, version, kvno, ticket_len);
David Howells17926a72007-04-26 15:48:28 -07001086
David Howellsfb46f6e2017-04-06 10:12:00 +01001087 eproto = tracepoint_string("rxkad_rsp_ver");
David Howells17926a72007-04-26 15:48:28 -07001088 abort_code = RXKADINCONSISTENCY;
1089 if (version != RXKAD_VERSION)
David Howells4aa9cb32007-12-07 04:31:47 -08001090 goto protocol_error;
David Howells17926a72007-04-26 15:48:28 -07001091
David Howellsfb46f6e2017-04-06 10:12:00 +01001092 eproto = tracepoint_string("rxkad_rsp_tktlen");
David Howells17926a72007-04-26 15:48:28 -07001093 abort_code = RXKADTICKETLEN;
1094 if (ticket_len < 4 || ticket_len > MAXKRB5TICKETLEN)
1095 goto protocol_error;
1096
David Howellsfb46f6e2017-04-06 10:12:00 +01001097 eproto = tracepoint_string("rxkad_rsp_unkkey");
David Howells17926a72007-04-26 15:48:28 -07001098 abort_code = RXKADUNKNOWNKEY;
1099 if (kvno >= RXKAD_TKT_TYPE_KERBEROS_V5)
1100 goto protocol_error;
1101
1102 /* extract the kerberos ticket and decrypt and decode it */
David Howellsef686222017-04-06 10:11:59 +01001103 ret = -ENOMEM;
David Howells17926a72007-04-26 15:48:28 -07001104 ticket = kmalloc(ticket_len, GFP_NOFS);
1105 if (!ticket)
David Howellsef686222017-04-06 10:11:59 +01001106 goto temporary_error;
David Howells17926a72007-04-26 15:48:28 -07001107
David Howellsfb46f6e2017-04-06 10:12:00 +01001108 eproto = tracepoint_string("rxkad_tkt_short");
David Howells17926a72007-04-26 15:48:28 -07001109 abort_code = RXKADPACKETSHORT;
David Howells775e5b72016-09-30 13:26:03 +01001110 if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
1111 ticket, ticket_len) < 0)
David Howells17926a72007-04-26 15:48:28 -07001112 goto protocol_error_free;
1113
David Howellsfb46f6e2017-04-06 10:12:00 +01001114 ret = rxkad_decrypt_ticket(conn, skb, ticket, ticket_len, &session_key,
David Howellsef686222017-04-06 10:11:59 +01001115 &expiry, _abort_code);
1116 if (ret < 0)
David Howells8c2f8262018-02-08 15:59:07 +00001117 goto temporary_error_free_resp;
David Howells17926a72007-04-26 15:48:28 -07001118
1119 /* use the session key from inside the ticket to decrypt the
1120 * response */
David Howells8c2f8262018-02-08 15:59:07 +00001121 rxkad_decrypt_response(conn, response, &session_key);
David Howells17926a72007-04-26 15:48:28 -07001122
David Howellsfb46f6e2017-04-06 10:12:00 +01001123 eproto = tracepoint_string("rxkad_rsp_param");
David Howells17926a72007-04-26 15:48:28 -07001124 abort_code = RXKADSEALEDINCON;
David Howells8c2f8262018-02-08 15:59:07 +00001125 if (ntohl(response->encrypted.epoch) != conn->proto.epoch)
David Howells17926a72007-04-26 15:48:28 -07001126 goto protocol_error_free;
David Howells8c2f8262018-02-08 15:59:07 +00001127 if (ntohl(response->encrypted.cid) != conn->proto.cid)
David Howells17926a72007-04-26 15:48:28 -07001128 goto protocol_error_free;
David Howells8c2f8262018-02-08 15:59:07 +00001129 if (ntohl(response->encrypted.securityIndex) != conn->security_ix)
David Howells17926a72007-04-26 15:48:28 -07001130 goto protocol_error_free;
David Howells8c2f8262018-02-08 15:59:07 +00001131 csum = response->encrypted.checksum;
1132 response->encrypted.checksum = 0;
1133 rxkad_calc_response_checksum(response);
David Howellsfb46f6e2017-04-06 10:12:00 +01001134 eproto = tracepoint_string("rxkad_rsp_csum");
David Howells8c2f8262018-02-08 15:59:07 +00001135 if (response->encrypted.checksum != csum)
David Howells17926a72007-04-26 15:48:28 -07001136 goto protocol_error_free;
1137
David Howellsa1399f82016-06-27 14:39:44 +01001138 spin_lock(&conn->channel_lock);
1139 for (i = 0; i < RXRPC_MAXCALLS; i++) {
1140 struct rxrpc_call *call;
David Howells8c2f8262018-02-08 15:59:07 +00001141 u32 call_id = ntohl(response->encrypted.call_id[i]);
David Howellsa1399f82016-06-27 14:39:44 +01001142
David Howellsfb46f6e2017-04-06 10:12:00 +01001143 eproto = tracepoint_string("rxkad_rsp_callid");
David Howellsa1399f82016-06-27 14:39:44 +01001144 if (call_id > INT_MAX)
1145 goto protocol_error_unlock;
1146
David Howellsfb46f6e2017-04-06 10:12:00 +01001147 eproto = tracepoint_string("rxkad_rsp_callctr");
David Howellsa1399f82016-06-27 14:39:44 +01001148 if (call_id < conn->channels[i].call_counter)
1149 goto protocol_error_unlock;
David Howellsfb46f6e2017-04-06 10:12:00 +01001150
1151 eproto = tracepoint_string("rxkad_rsp_callst");
David Howellsa1399f82016-06-27 14:39:44 +01001152 if (call_id > conn->channels[i].call_counter) {
1153 call = rcu_dereference_protected(
1154 conn->channels[i].call,
1155 lockdep_is_held(&conn->channel_lock));
1156 if (call && call->state < RXRPC_CALL_COMPLETE)
1157 goto protocol_error_unlock;
1158 conn->channels[i].call_counter = call_id;
1159 }
1160 }
1161 spin_unlock(&conn->channel_lock);
David Howells17926a72007-04-26 15:48:28 -07001162
David Howellsfb46f6e2017-04-06 10:12:00 +01001163 eproto = tracepoint_string("rxkad_rsp_seq");
David Howells17926a72007-04-26 15:48:28 -07001164 abort_code = RXKADOUTOFSEQUENCE;
David Howells8c2f8262018-02-08 15:59:07 +00001165 if (ntohl(response->encrypted.inc_nonce) != conn->security_nonce + 1)
David Howells17926a72007-04-26 15:48:28 -07001166 goto protocol_error_free;
1167
David Howellsfb46f6e2017-04-06 10:12:00 +01001168 eproto = tracepoint_string("rxkad_rsp_level");
David Howells17926a72007-04-26 15:48:28 -07001169 abort_code = RXKADLEVELFAIL;
David Howells8c2f8262018-02-08 15:59:07 +00001170 level = ntohl(response->encrypted.level);
David Howells17926a72007-04-26 15:48:28 -07001171 if (level > RXRPC_SECURITY_ENCRYPT)
1172 goto protocol_error_free;
David Howells19ffa012016-04-04 14:00:36 +01001173 conn->params.security_level = level;
David Howells17926a72007-04-26 15:48:28 -07001174
1175 /* create a key to hold the security data and expiration time - after
1176 * this the connection security can be handled in exactly the same way
1177 * as for a client connection */
1178 ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno);
David Howellsef686222017-04-06 10:11:59 +01001179 if (ret < 0)
David Howells8c2f8262018-02-08 15:59:07 +00001180 goto temporary_error_free_ticket;
David Howells17926a72007-04-26 15:48:28 -07001181
1182 kfree(ticket);
David Howells8c2f8262018-02-08 15:59:07 +00001183 kfree(response);
David Howells17926a72007-04-26 15:48:28 -07001184 _leave(" = 0");
1185 return 0;
1186
David Howellsa1399f82016-06-27 14:39:44 +01001187protocol_error_unlock:
1188 spin_unlock(&conn->channel_lock);
David Howells17926a72007-04-26 15:48:28 -07001189protocol_error_free:
1190 kfree(ticket);
1191protocol_error:
David Howells8c2f8262018-02-08 15:59:07 +00001192 kfree(response);
David Howellsfb46f6e2017-04-06 10:12:00 +01001193 trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
David Howells17926a72007-04-26 15:48:28 -07001194 *_abort_code = abort_code;
David Howells17926a72007-04-26 15:48:28 -07001195 return -EPROTO;
David Howellsef686222017-04-06 10:11:59 +01001196
David Howells8c2f8262018-02-08 15:59:07 +00001197temporary_error_free_ticket:
David Howellsef686222017-04-06 10:11:59 +01001198 kfree(ticket);
David Howells8c2f8262018-02-08 15:59:07 +00001199temporary_error_free_resp:
1200 kfree(response);
David Howellsef686222017-04-06 10:11:59 +01001201temporary_error:
1202 /* Ignore the response packet if we got a temporary error such as
1203 * ENOMEM. We just want to send the challenge again. Note that we
1204 * also come out this way if the ticket decryption fails.
1205 */
1206 return ret;
David Howells17926a72007-04-26 15:48:28 -07001207}
1208
1209/*
1210 * clear the connection security
1211 */
1212static void rxkad_clear(struct rxrpc_connection *conn)
1213{
1214 _enter("");
1215
1216 if (conn->cipher)
Kees Cook69d826f2018-09-18 19:10:47 -07001217 crypto_free_sync_skcipher(conn->cipher);
David Howells17926a72007-04-26 15:48:28 -07001218}
1219
1220/*
David Howells648af7f2016-04-07 17:23:51 +01001221 * Initialise the rxkad security service.
1222 */
1223static int rxkad_init(void)
1224{
1225 /* pin the cipher we need so that the crypto layer doesn't invoke
1226 * keventd to go get it */
Kees Cook69d826f2018-09-18 19:10:47 -07001227 rxkad_ci = crypto_alloc_sync_skcipher("pcbc(fcrypt)", 0, 0);
Wu Fengguangfa54cc72016-06-05 07:17:19 +08001228 return PTR_ERR_OR_ZERO(rxkad_ci);
David Howells648af7f2016-04-07 17:23:51 +01001229}
1230
1231/*
1232 * Clean up the rxkad security service.
1233 */
1234static void rxkad_exit(void)
1235{
1236 if (rxkad_ci)
Kees Cook69d826f2018-09-18 19:10:47 -07001237 crypto_free_sync_skcipher(rxkad_ci);
David Howells648af7f2016-04-07 17:23:51 +01001238}
1239
1240/*
David Howells17926a72007-04-26 15:48:28 -07001241 * RxRPC Kerberos-based security
1242 */
David Howells648af7f2016-04-07 17:23:51 +01001243const struct rxrpc_security rxkad = {
David Howells17926a72007-04-26 15:48:28 -07001244 .name = "rxkad",
David Howells8b815472009-09-14 01:17:30 +00001245 .security_index = RXRPC_SECURITY_RXKAD,
David Howells648af7f2016-04-07 17:23:51 +01001246 .init = rxkad_init,
1247 .exit = rxkad_exit,
David Howells17926a72007-04-26 15:48:28 -07001248 .init_connection_security = rxkad_init_connection_security,
1249 .prime_packet_security = rxkad_prime_packet_security,
1250 .secure_packet = rxkad_secure_packet,
1251 .verify_packet = rxkad_verify_packet,
David Howells248f2192016-09-08 11:10:12 +01001252 .locate_data = rxkad_locate_data,
David Howells17926a72007-04-26 15:48:28 -07001253 .issue_challenge = rxkad_issue_challenge,
1254 .respond_to_challenge = rxkad_respond_to_challenge,
1255 .verify_response = rxkad_verify_response,
1256 .clear = rxkad_clear,
1257};