blob: c60c520fde7c0a57850d53886e0fce9fc622f58c [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];
Eric Dumazet95c96172012-04-15 05:58:06 +0000190 unsigned int len;
David Howells17926a72007-04-26 15:48:28 -0700191 u16 check;
Herbert Xu1afe5932016-01-24 21:19:01 +0800192 int err;
David Howells17926a72007-04-26 15:48:28 -0700193
194 sp = rxrpc_skb(skb);
195
196 _enter("");
197
David Howells5a924b82016-09-22 00:29:31 +0100198 check = sp->hdr.seq ^ call->call_id;
David Howells17926a72007-04-26 15:48:28 -0700199
David Howells0d12f8a2016-03-04 15:53:46 +0000200 rxkhdr.data_size = htonl(data_size | (u32)check << 16);
David Howells17926a72007-04-26 15:48:28 -0700201 rxkhdr.checksum = 0;
Herbert Xua2636292016-06-26 14:55:24 -0700202 memcpy(sechdr, &rxkhdr, sizeof(rxkhdr));
David Howells17926a72007-04-26 15:48:28 -0700203
204 /* encrypt from the session key */
David Howells19ffa012016-04-04 14:00:36 +0100205 token = call->conn->params.key->payload.data[0];
David Howells33941282009-09-14 01:17:35 +0000206 memcpy(&iv, token->kad->session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700207
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700208 sg_init_one(&sg[0], sechdr, sizeof(rxkhdr));
Kees Cook69d826f2018-09-18 19:10:47 -0700209 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800210 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700211 skcipher_request_set_crypt(req, &sg[0], &sg[0], sizeof(rxkhdr), iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800212 crypto_skcipher_encrypt(req);
David Howells17926a72007-04-26 15:48:28 -0700213
214 /* we want to encrypt the skbuff in-place */
David Howellsd0d5c0c2019-08-27 10:13:46 +0100215 err = -EMSGSIZE;
216 if (skb_shinfo(skb)->nr_frags > 16)
Herbert Xu1afe5932016-01-24 21:19:01 +0800217 goto out;
David Howells17926a72007-04-26 15:48:28 -0700218
219 len = data_size + call->conn->size_align - 1;
220 len &= ~(call->conn->size_align - 1);
221
David Howellsd0d5c0c2019-08-27 10:13:46 +0100222 sg_init_table(sg, ARRAY_SIZE(sg));
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200223 err = skb_to_sgvec(skb, sg, 0, len);
224 if (unlikely(err < 0))
225 goto out;
Herbert Xu1afe5932016-01-24 21:19:01 +0800226 skcipher_request_set_crypt(req, sg, sg, len, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800227 crypto_skcipher_encrypt(req);
David Howells17926a72007-04-26 15:48:28 -0700228
229 _leave(" = 0");
Herbert Xu1afe5932016-01-24 21:19:01 +0800230 err = 0;
231
232out:
233 skcipher_request_zero(req);
234 return err;
David Howells17926a72007-04-26 15:48:28 -0700235}
236
237/*
238 * checksum an RxRPC packet header
239 */
Herbert Xua2636292016-06-26 14:55:24 -0700240static int rxkad_secure_packet(struct rxrpc_call *call,
David Howellsb4f13422016-03-04 15:56:19 +0000241 struct sk_buff *skb,
242 size_t data_size,
243 void *sechdr)
David Howells17926a72007-04-26 15:48:28 -0700244{
245 struct rxrpc_skb_priv *sp;
Kees Cook69d826f2018-09-18 19:10:47 -0700246 SYNC_SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
David Howells17926a72007-04-26 15:48:28 -0700247 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700248 struct scatterlist sg;
David Howells0d12f8a2016-03-04 15:53:46 +0000249 u32 x, y;
David Howells17926a72007-04-26 15:48:28 -0700250 int ret;
251
252 sp = rxrpc_skb(skb);
253
254 _enter("{%d{%x}},{#%u},%zu,",
David Howells19ffa012016-04-04 14:00:36 +0100255 call->debug_id, key_serial(call->conn->params.key),
256 sp->hdr.seq, data_size);
David Howells17926a72007-04-26 15:48:28 -0700257
258 if (!call->conn->cipher)
259 return 0;
260
David Howells19ffa012016-04-04 14:00:36 +0100261 ret = key_validate(call->conn->params.key);
David Howells17926a72007-04-26 15:48:28 -0700262 if (ret < 0)
263 return ret;
264
265 /* continue encrypting from where we left off */
266 memcpy(&iv, call->conn->csum_iv.x, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700267
268 /* calculate the security checksum */
David Howells01a90a42016-08-23 15:27:24 +0100269 x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
David Howells0d12f8a2016-03-04 15:53:46 +0000270 x |= sp->hdr.seq & 0x3fffffff;
David Howells5a924b82016-09-22 00:29:31 +0100271 call->crypto_buf[0] = htonl(call->call_id);
Herbert Xua2636292016-06-26 14:55:24 -0700272 call->crypto_buf[1] = htonl(x);
David Howells17926a72007-04-26 15:48:28 -0700273
Herbert Xua2636292016-06-26 14:55:24 -0700274 sg_init_one(&sg, call->crypto_buf, 8);
Kees Cook69d826f2018-09-18 19:10:47 -0700275 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800276 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700277 skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800278 crypto_skcipher_encrypt(req);
279 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700280
Herbert Xua2636292016-06-26 14:55:24 -0700281 y = ntohl(call->crypto_buf[1]);
Al Viro91e916c2008-03-29 03:08:38 +0000282 y = (y >> 16) & 0xffff;
283 if (y == 0)
284 y = 1; /* zero checksums are not permitted */
David Howells0d12f8a2016-03-04 15:53:46 +0000285 sp->hdr.cksum = y;
David Howells17926a72007-04-26 15:48:28 -0700286
David Howells19ffa012016-04-04 14:00:36 +0100287 switch (call->conn->params.security_level) {
David Howells17926a72007-04-26 15:48:28 -0700288 case RXRPC_SECURITY_PLAIN:
289 ret = 0;
290 break;
291 case RXRPC_SECURITY_AUTH:
Kees Cook54424d32018-08-03 10:15:25 +0100292 ret = rxkad_secure_packet_auth(call, skb, data_size, sechdr,
293 req);
David Howells17926a72007-04-26 15:48:28 -0700294 break;
295 case RXRPC_SECURITY_ENCRYPT:
296 ret = rxkad_secure_packet_encrypt(call, skb, data_size,
Kees Cook54424d32018-08-03 10:15:25 +0100297 sechdr, req);
David Howells17926a72007-04-26 15:48:28 -0700298 break;
299 default:
300 ret = -EPERM;
301 break;
302 }
303
Al Viro91e916c2008-03-29 03:08:38 +0000304 _leave(" = %d [set %hx]", ret, y);
David Howells17926a72007-04-26 15:48:28 -0700305 return ret;
306}
307
308/*
309 * decrypt partial encryption on a packet (level 1 security)
310 */
David Howells5a429762016-09-06 22:19:51 +0100311static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
David Howells248f2192016-09-08 11:10:12 +0100312 unsigned int offset, unsigned int len,
Kees Cook54424d32018-08-03 10:15:25 +0100313 rxrpc_seq_t seq,
314 struct skcipher_request *req)
David Howells17926a72007-04-26 15:48:28 -0700315{
316 struct rxkad_level1_hdr sechdr;
David Howells17926a72007-04-26 15:48:28 -0700317 struct rxrpc_crypt iv;
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700318 struct scatterlist sg[16];
David Howellsfb46f6e2017-04-06 10:12:00 +0100319 bool aborted;
David Howells17926a72007-04-26 15:48:28 -0700320 u32 data_size, buf;
321 u16 check;
David Howellsd0d5c0c2019-08-27 10:13:46 +0100322 int ret;
David Howells17926a72007-04-26 15:48:28 -0700323
324 _enter("");
325
David Howells248f2192016-09-08 11:10:12 +0100326 if (len < 8) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100327 aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_hdr", "V1H",
328 RXKADSEALEDINCON);
David Howells5a429762016-09-06 22:19:51 +0100329 goto protocol_error;
330 }
David Howells17926a72007-04-26 15:48:28 -0700331
David Howells248f2192016-09-08 11:10:12 +0100332 /* Decrypt the skbuff in-place. TODO: We really want to decrypt
333 * directly into the target buffer.
334 */
David Howellsd0d5c0c2019-08-27 10:13:46 +0100335 sg_init_table(sg, ARRAY_SIZE(sg));
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200336 ret = skb_to_sgvec(skb, sg, offset, 8);
337 if (unlikely(ret < 0))
338 return ret;
David Howells17926a72007-04-26 15:48:28 -0700339
340 /* start the decryption afresh */
341 memset(&iv, 0, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700342
Kees Cook69d826f2018-09-18 19:10:47 -0700343 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800344 skcipher_request_set_callback(req, 0, NULL, NULL);
345 skcipher_request_set_crypt(req, sg, sg, 8, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800346 crypto_skcipher_decrypt(req);
347 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700348
David Howells5a429762016-09-06 22:19:51 +0100349 /* Extract the decrypted packet length */
David Howells248f2192016-09-08 11:10:12 +0100350 if (skb_copy_bits(skb, offset, &sechdr, sizeof(sechdr)) < 0) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100351 aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_len", "XV1",
352 RXKADDATALEN);
David Howells5a429762016-09-06 22:19:51 +0100353 goto protocol_error;
354 }
David Howells248f2192016-09-08 11:10:12 +0100355 offset += sizeof(sechdr);
356 len -= sizeof(sechdr);
David Howells17926a72007-04-26 15:48:28 -0700357
358 buf = ntohl(sechdr.data_size);
359 data_size = buf & 0xffff;
360
361 check = buf >> 16;
David Howells5a429762016-09-06 22:19:51 +0100362 check ^= seq ^ call->call_id;
David Howells17926a72007-04-26 15:48:28 -0700363 check &= 0xffff;
364 if (check != 0) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100365 aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_check", "V1C",
366 RXKADSEALEDINCON);
David Howells17926a72007-04-26 15:48:28 -0700367 goto protocol_error;
368 }
369
David Howells248f2192016-09-08 11:10:12 +0100370 if (data_size > len) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100371 aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_datalen", "V1L",
372 RXKADDATALEN);
David Howells5a429762016-09-06 22:19:51 +0100373 goto protocol_error;
374 }
David Howells17926a72007-04-26 15:48:28 -0700375
376 _leave(" = 0 [dlen=%x]", data_size);
377 return 0;
378
David Howells17926a72007-04-26 15:48:28 -0700379protocol_error:
David Howellsfb46f6e2017-04-06 10:12:00 +0100380 if (aborted)
381 rxrpc_send_abort_packet(call);
David Howells17926a72007-04-26 15:48:28 -0700382 return -EPROTO;
David Howells17926a72007-04-26 15:48:28 -0700383}
384
385/*
386 * wholly decrypt a packet (level 2 security)
387 */
David Howells5a429762016-09-06 22:19:51 +0100388static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
David Howells248f2192016-09-08 11:10:12 +0100389 unsigned int offset, unsigned int len,
Kees Cook54424d32018-08-03 10:15:25 +0100390 rxrpc_seq_t seq,
391 struct skcipher_request *req)
David Howells17926a72007-04-26 15:48:28 -0700392{
David Howells33941282009-09-14 01:17:35 +0000393 const struct rxrpc_key_token *token;
David Howells17926a72007-04-26 15:48:28 -0700394 struct rxkad_level2_hdr sechdr;
David Howells17926a72007-04-26 15:48:28 -0700395 struct rxrpc_crypt iv;
396 struct scatterlist _sg[4], *sg;
David Howellsfb46f6e2017-04-06 10:12:00 +0100397 bool aborted;
David Howells17926a72007-04-26 15:48:28 -0700398 u32 data_size, buf;
399 u16 check;
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200400 int nsg, ret;
David Howells17926a72007-04-26 15:48:28 -0700401
402 _enter(",{%d}", skb->len);
403
David Howells248f2192016-09-08 11:10:12 +0100404 if (len < 8) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100405 aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_hdr", "V2H",
406 RXKADSEALEDINCON);
David Howells5a429762016-09-06 22:19:51 +0100407 goto protocol_error;
408 }
David Howells17926a72007-04-26 15:48:28 -0700409
David Howells248f2192016-09-08 11:10:12 +0100410 /* Decrypt the skbuff in-place. TODO: We really want to decrypt
411 * directly into the target buffer.
412 */
David Howells17926a72007-04-26 15:48:28 -0700413 sg = _sg;
David Howellsd0d5c0c2019-08-27 10:13:46 +0100414 nsg = skb_shinfo(skb)->nr_frags;
415 if (nsg <= 4) {
416 nsg = 4;
417 } else {
Kees Cook6da2ec52018-06-12 13:55:00 -0700418 sg = kmalloc_array(nsg, sizeof(*sg), GFP_NOIO);
David Howells17926a72007-04-26 15:48:28 -0700419 if (!sg)
420 goto nomem;
421 }
422
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700423 sg_init_table(sg, nsg);
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200424 ret = skb_to_sgvec(skb, sg, offset, len);
425 if (unlikely(ret < 0)) {
426 if (sg != _sg)
427 kfree(sg);
428 return ret;
429 }
David Howells17926a72007-04-26 15:48:28 -0700430
431 /* decrypt from the session key */
David Howells19ffa012016-04-04 14:00:36 +0100432 token = call->conn->params.key->payload.data[0];
David Howells33941282009-09-14 01:17:35 +0000433 memcpy(&iv, token->kad->session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700434
Kees Cook69d826f2018-09-18 19:10:47 -0700435 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800436 skcipher_request_set_callback(req, 0, NULL, NULL);
David Howells248f2192016-09-08 11:10:12 +0100437 skcipher_request_set_crypt(req, sg, sg, len, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800438 crypto_skcipher_decrypt(req);
439 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700440 if (sg != _sg)
441 kfree(sg);
442
David Howells5a429762016-09-06 22:19:51 +0100443 /* Extract the decrypted packet length */
David Howells248f2192016-09-08 11:10:12 +0100444 if (skb_copy_bits(skb, offset, &sechdr, sizeof(sechdr)) < 0) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100445 aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_len", "XV2",
446 RXKADDATALEN);
David Howells5a429762016-09-06 22:19:51 +0100447 goto protocol_error;
448 }
David Howells248f2192016-09-08 11:10:12 +0100449 offset += sizeof(sechdr);
450 len -= sizeof(sechdr);
David Howells17926a72007-04-26 15:48:28 -0700451
452 buf = ntohl(sechdr.data_size);
453 data_size = buf & 0xffff;
454
455 check = buf >> 16;
David Howells5a429762016-09-06 22:19:51 +0100456 check ^= seq ^ call->call_id;
David Howells17926a72007-04-26 15:48:28 -0700457 check &= 0xffff;
458 if (check != 0) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100459 aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_check", "V2C",
460 RXKADSEALEDINCON);
David Howells17926a72007-04-26 15:48:28 -0700461 goto protocol_error;
462 }
463
David Howells248f2192016-09-08 11:10:12 +0100464 if (data_size > len) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100465 aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_datalen", "V2L",
466 RXKADDATALEN);
David Howells5a429762016-09-06 22:19:51 +0100467 goto protocol_error;
468 }
David Howells17926a72007-04-26 15:48:28 -0700469
470 _leave(" = 0 [dlen=%x]", data_size);
471 return 0;
472
David Howells17926a72007-04-26 15:48:28 -0700473protocol_error:
David Howellsfb46f6e2017-04-06 10:12:00 +0100474 if (aborted)
475 rxrpc_send_abort_packet(call);
David Howells17926a72007-04-26 15:48:28 -0700476 return -EPROTO;
477
478nomem:
479 _leave(" = -ENOMEM");
480 return -ENOMEM;
481}
482
483/*
David Howells5a429762016-09-06 22:19:51 +0100484 * Verify the security on a received packet or subpacket (if part of a
485 * jumbo packet).
David Howells17926a72007-04-26 15:48:28 -0700486 */
David Howells5a429762016-09-06 22:19:51 +0100487static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb,
David Howells248f2192016-09-08 11:10:12 +0100488 unsigned int offset, unsigned int len,
David Howells5a429762016-09-06 22:19:51 +0100489 rxrpc_seq_t seq, u16 expected_cksum)
David Howells17926a72007-04-26 15:48:28 -0700490{
Kees Cook69d826f2018-09-18 19:10:47 -0700491 SYNC_SKCIPHER_REQUEST_ON_STACK(req, call->conn->cipher);
David Howells17926a72007-04-26 15:48:28 -0700492 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700493 struct scatterlist sg;
David Howellsfb46f6e2017-04-06 10:12:00 +0100494 bool aborted;
David Howells0d12f8a2016-03-04 15:53:46 +0000495 u16 cksum;
496 u32 x, y;
David Howells17926a72007-04-26 15:48:28 -0700497
498 _enter("{%d{%x}},{#%u}",
David Howells5a429762016-09-06 22:19:51 +0100499 call->debug_id, key_serial(call->conn->params.key), seq);
David Howells17926a72007-04-26 15:48:28 -0700500
501 if (!call->conn->cipher)
502 return 0;
503
David Howells17926a72007-04-26 15:48:28 -0700504 /* continue encrypting from where we left off */
505 memcpy(&iv, call->conn->csum_iv.x, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700506
507 /* validate the security checksum */
David Howells01a90a42016-08-23 15:27:24 +0100508 x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
David Howells5a429762016-09-06 22:19:51 +0100509 x |= seq & 0x3fffffff;
Herbert Xua2636292016-06-26 14:55:24 -0700510 call->crypto_buf[0] = htonl(call->call_id);
511 call->crypto_buf[1] = htonl(x);
David Howells17926a72007-04-26 15:48:28 -0700512
Herbert Xua2636292016-06-26 14:55:24 -0700513 sg_init_one(&sg, call->crypto_buf, 8);
Kees Cook69d826f2018-09-18 19:10:47 -0700514 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800515 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700516 skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800517 crypto_skcipher_encrypt(req);
518 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700519
Herbert Xua2636292016-06-26 14:55:24 -0700520 y = ntohl(call->crypto_buf[1]);
David Howells0d12f8a2016-03-04 15:53:46 +0000521 cksum = (y >> 16) & 0xffff;
522 if (cksum == 0)
523 cksum = 1; /* zero checksums are not permitted */
David Howells17926a72007-04-26 15:48:28 -0700524
David Howells5a429762016-09-06 22:19:51 +0100525 if (cksum != expected_cksum) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100526 aborted = rxrpc_abort_eproto(call, skb, "rxkad_csum", "VCK",
527 RXKADSEALEDINCON);
528 goto protocol_error;
David Howells17926a72007-04-26 15:48:28 -0700529 }
530
David Howells19ffa012016-04-04 14:00:36 +0100531 switch (call->conn->params.security_level) {
David Howells17926a72007-04-26 15:48:28 -0700532 case RXRPC_SECURITY_PLAIN:
David Howells5a429762016-09-06 22:19:51 +0100533 return 0;
David Howells17926a72007-04-26 15:48:28 -0700534 case RXRPC_SECURITY_AUTH:
Kees Cook54424d32018-08-03 10:15:25 +0100535 return rxkad_verify_packet_1(call, skb, offset, len, seq, req);
David Howells17926a72007-04-26 15:48:28 -0700536 case RXRPC_SECURITY_ENCRYPT:
Kees Cook54424d32018-08-03 10:15:25 +0100537 return rxkad_verify_packet_2(call, skb, offset, len, seq, req);
David Howells17926a72007-04-26 15:48:28 -0700538 default:
David Howells5a429762016-09-06 22:19:51 +0100539 return -ENOANO;
David Howells17926a72007-04-26 15:48:28 -0700540 }
David Howellsfb46f6e2017-04-06 10:12:00 +0100541
542protocol_error:
543 if (aborted)
544 rxrpc_send_abort_packet(call);
545 return -EPROTO;
David Howells17926a72007-04-26 15:48:28 -0700546}
547
548/*
David Howells248f2192016-09-08 11:10:12 +0100549 * Locate the data contained in a packet that was partially encrypted.
550 */
551static void rxkad_locate_data_1(struct rxrpc_call *call, struct sk_buff *skb,
552 unsigned int *_offset, unsigned int *_len)
553{
554 struct rxkad_level1_hdr sechdr;
555
556 if (skb_copy_bits(skb, *_offset, &sechdr, sizeof(sechdr)) < 0)
557 BUG();
558 *_offset += sizeof(sechdr);
559 *_len = ntohl(sechdr.data_size) & 0xffff;
560}
561
562/*
563 * Locate the data contained in a packet that was completely encrypted.
564 */
565static void rxkad_locate_data_2(struct rxrpc_call *call, struct sk_buff *skb,
566 unsigned int *_offset, unsigned int *_len)
567{
568 struct rxkad_level2_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 an already decrypted packet.
578 */
579static void rxkad_locate_data(struct rxrpc_call *call, struct sk_buff *skb,
580 unsigned int *_offset, unsigned int *_len)
581{
582 switch (call->conn->params.security_level) {
583 case RXRPC_SECURITY_AUTH:
584 rxkad_locate_data_1(call, skb, _offset, _len);
585 return;
586 case RXRPC_SECURITY_ENCRYPT:
587 rxkad_locate_data_2(call, skb, _offset, _len);
588 return;
589 default:
590 return;
591 }
592}
593
594/*
David Howells17926a72007-04-26 15:48:28 -0700595 * issue a challenge
596 */
597static int rxkad_issue_challenge(struct rxrpc_connection *conn)
598{
599 struct rxkad_challenge challenge;
David Howells0d12f8a2016-03-04 15:53:46 +0000600 struct rxrpc_wire_header whdr;
David Howells17926a72007-04-26 15:48:28 -0700601 struct msghdr msg;
602 struct kvec iov[2];
603 size_t len;
David Howells0d12f8a2016-03-04 15:53:46 +0000604 u32 serial;
David Howells17926a72007-04-26 15:48:28 -0700605 int ret;
606
David Howells19ffa012016-04-04 14:00:36 +0100607 _enter("{%d,%x}", conn->debug_id, key_serial(conn->params.key));
David Howells17926a72007-04-26 15:48:28 -0700608
David Howells19ffa012016-04-04 14:00:36 +0100609 ret = key_validate(conn->params.key);
David Howells17926a72007-04-26 15:48:28 -0700610 if (ret < 0)
611 return ret;
612
613 get_random_bytes(&conn->security_nonce, sizeof(conn->security_nonce));
614
615 challenge.version = htonl(2);
616 challenge.nonce = htonl(conn->security_nonce);
617 challenge.min_level = htonl(0);
618 challenge.__padding = 0;
619
David Howells7b674e32017-08-29 10:18:37 +0100620 msg.msg_name = &conn->params.peer->srx.transport;
621 msg.msg_namelen = conn->params.peer->srx.transport_len;
David Howells17926a72007-04-26 15:48:28 -0700622 msg.msg_control = NULL;
623 msg.msg_controllen = 0;
624 msg.msg_flags = 0;
625
David Howells19ffa012016-04-04 14:00:36 +0100626 whdr.epoch = htonl(conn->proto.epoch);
627 whdr.cid = htonl(conn->proto.cid);
David Howells0d12f8a2016-03-04 15:53:46 +0000628 whdr.callNumber = 0;
629 whdr.seq = 0;
630 whdr.type = RXRPC_PACKET_TYPE_CHALLENGE;
631 whdr.flags = conn->out_clientflag;
632 whdr.userStatus = 0;
633 whdr.securityIndex = conn->security_ix;
634 whdr._rsvd = 0;
David Howells68d6d1a2017-06-05 14:30:49 +0100635 whdr.serviceId = htons(conn->service_id);
David Howells17926a72007-04-26 15:48:28 -0700636
David Howells0d12f8a2016-03-04 15:53:46 +0000637 iov[0].iov_base = &whdr;
638 iov[0].iov_len = sizeof(whdr);
David Howells17926a72007-04-26 15:48:28 -0700639 iov[1].iov_base = &challenge;
640 iov[1].iov_len = sizeof(challenge);
641
642 len = iov[0].iov_len + iov[1].iov_len;
643
David Howells0d12f8a2016-03-04 15:53:46 +0000644 serial = atomic_inc_return(&conn->serial);
645 whdr.serial = htonl(serial);
646 _proto("Tx CHALLENGE %%%u", serial);
David Howells17926a72007-04-26 15:48:28 -0700647
David Howells85f32272016-04-04 14:00:36 +0100648 ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len);
David Howells17926a72007-04-26 15:48:28 -0700649 if (ret < 0) {
David Howells6b47fe12018-05-10 23:26:01 +0100650 trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
David Howells4764c0d2018-07-23 17:18:37 +0100651 rxrpc_tx_point_rxkad_challenge);
David Howells17926a72007-04-26 15:48:28 -0700652 return -EAGAIN;
653 }
654
David Howells330bdcf2018-08-08 11:30:02 +0100655 conn->params.peer->last_tx_at = ktime_get_seconds();
David Howells4764c0d2018-07-23 17:18:37 +0100656 trace_rxrpc_tx_packet(conn->debug_id, &whdr,
657 rxrpc_tx_point_rxkad_challenge);
David Howells17926a72007-04-26 15:48:28 -0700658 _leave(" = 0");
659 return 0;
660}
661
662/*
663 * send a Kerberos security response
664 */
665static int rxkad_send_response(struct rxrpc_connection *conn,
David Howells0d12f8a2016-03-04 15:53:46 +0000666 struct rxrpc_host_header *hdr,
David Howells17926a72007-04-26 15:48:28 -0700667 struct rxkad_response *resp,
668 const struct rxkad_key *s2)
669{
David Howells0d12f8a2016-03-04 15:53:46 +0000670 struct rxrpc_wire_header whdr;
David Howells17926a72007-04-26 15:48:28 -0700671 struct msghdr msg;
672 struct kvec iov[3];
673 size_t len;
David Howells0d12f8a2016-03-04 15:53:46 +0000674 u32 serial;
David Howells17926a72007-04-26 15:48:28 -0700675 int ret;
676
677 _enter("");
678
David Howells7b674e32017-08-29 10:18:37 +0100679 msg.msg_name = &conn->params.peer->srx.transport;
680 msg.msg_namelen = conn->params.peer->srx.transport_len;
David Howells17926a72007-04-26 15:48:28 -0700681 msg.msg_control = NULL;
682 msg.msg_controllen = 0;
683 msg.msg_flags = 0;
684
David Howells0d12f8a2016-03-04 15:53:46 +0000685 memset(&whdr, 0, sizeof(whdr));
686 whdr.epoch = htonl(hdr->epoch);
687 whdr.cid = htonl(hdr->cid);
688 whdr.type = RXRPC_PACKET_TYPE_RESPONSE;
689 whdr.flags = conn->out_clientflag;
690 whdr.securityIndex = hdr->securityIndex;
691 whdr.serviceId = htons(hdr->serviceId);
David Howells17926a72007-04-26 15:48:28 -0700692
David Howells0d12f8a2016-03-04 15:53:46 +0000693 iov[0].iov_base = &whdr;
694 iov[0].iov_len = sizeof(whdr);
David Howells17926a72007-04-26 15:48:28 -0700695 iov[1].iov_base = resp;
696 iov[1].iov_len = sizeof(*resp);
David Howells0d12f8a2016-03-04 15:53:46 +0000697 iov[2].iov_base = (void *)s2->ticket;
David Howells17926a72007-04-26 15:48:28 -0700698 iov[2].iov_len = s2->ticket_len;
699
700 len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
701
David Howells0d12f8a2016-03-04 15:53:46 +0000702 serial = atomic_inc_return(&conn->serial);
703 whdr.serial = htonl(serial);
704 _proto("Tx RESPONSE %%%u", serial);
David Howells17926a72007-04-26 15:48:28 -0700705
David Howells85f32272016-04-04 14:00:36 +0100706 ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 3, len);
David Howells17926a72007-04-26 15:48:28 -0700707 if (ret < 0) {
David Howells6b47fe12018-05-10 23:26:01 +0100708 trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
David Howells4764c0d2018-07-23 17:18:37 +0100709 rxrpc_tx_point_rxkad_response);
David Howells17926a72007-04-26 15:48:28 -0700710 return -EAGAIN;
711 }
712
David Howells330bdcf2018-08-08 11:30:02 +0100713 conn->params.peer->last_tx_at = ktime_get_seconds();
David Howells17926a72007-04-26 15:48:28 -0700714 _leave(" = 0");
715 return 0;
716}
717
718/*
719 * calculate the response checksum
720 */
721static void rxkad_calc_response_checksum(struct rxkad_response *response)
722{
723 u32 csum = 1000003;
724 int loop;
725 u8 *p = (u8 *) response;
726
727 for (loop = sizeof(*response); loop > 0; loop--)
728 csum = csum * 0x10204081 + *p++;
729
730 response->encrypted.checksum = htonl(csum);
731}
732
733/*
David Howells17926a72007-04-26 15:48:28 -0700734 * encrypt the response packet
735 */
736static void rxkad_encrypt_response(struct rxrpc_connection *conn,
737 struct rxkad_response *resp,
738 const struct rxkad_key *s2)
739{
Kees Cook69d826f2018-09-18 19:10:47 -0700740 SYNC_SKCIPHER_REQUEST_ON_STACK(req, conn->cipher);
David Howells17926a72007-04-26 15:48:28 -0700741 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700742 struct scatterlist sg[1];
David Howells17926a72007-04-26 15:48:28 -0700743
744 /* continue encrypting from where we left off */
745 memcpy(&iv, s2->session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700746
Herbert Xua2636292016-06-26 14:55:24 -0700747 sg_init_table(sg, 1);
748 sg_set_buf(sg, &resp->encrypted, sizeof(resp->encrypted));
Kees Cook69d826f2018-09-18 19:10:47 -0700749 skcipher_request_set_sync_tfm(req, conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800750 skcipher_request_set_callback(req, 0, NULL, NULL);
751 skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800752 crypto_skcipher_encrypt(req);
753 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700754}
755
756/*
757 * respond to a challenge packet
758 */
759static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
760 struct sk_buff *skb,
761 u32 *_abort_code)
762{
David Howells33941282009-09-14 01:17:35 +0000763 const struct rxrpc_key_token *token;
David Howells17926a72007-04-26 15:48:28 -0700764 struct rxkad_challenge challenge;
David Howells8c2f8262018-02-08 15:59:07 +0000765 struct rxkad_response *resp;
David Howells248f2192016-09-08 11:10:12 +0100766 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
David Howellsfb46f6e2017-04-06 10:12:00 +0100767 const char *eproto;
David Howells17926a72007-04-26 15:48:28 -0700768 u32 version, nonce, min_level, abort_code;
769 int ret;
770
David Howells19ffa012016-04-04 14:00:36 +0100771 _enter("{%d,%x}", conn->debug_id, key_serial(conn->params.key));
David Howells17926a72007-04-26 15:48:28 -0700772
David Howellsfb46f6e2017-04-06 10:12:00 +0100773 eproto = tracepoint_string("chall_no_key");
David Howellsef686222017-04-06 10:11:59 +0100774 abort_code = RX_PROTOCOL_ERROR;
775 if (!conn->params.key)
776 goto protocol_error;
David Howells17926a72007-04-26 15:48:28 -0700777
David Howellsef686222017-04-06 10:11:59 +0100778 abort_code = RXKADEXPIRED;
David Howells19ffa012016-04-04 14:00:36 +0100779 ret = key_validate(conn->params.key);
David Howellsef686222017-04-06 10:11:59 +0100780 if (ret < 0)
781 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700782
David Howellsfb46f6e2017-04-06 10:12:00 +0100783 eproto = tracepoint_string("chall_short");
David Howells17926a72007-04-26 15:48:28 -0700784 abort_code = RXKADPACKETSHORT;
David Howells775e5b72016-09-30 13:26:03 +0100785 if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
786 &challenge, sizeof(challenge)) < 0)
David Howells17926a72007-04-26 15:48:28 -0700787 goto protocol_error;
788
789 version = ntohl(challenge.version);
790 nonce = ntohl(challenge.nonce);
791 min_level = ntohl(challenge.min_level);
792
793 _proto("Rx CHALLENGE %%%u { v=%u n=%u ml=%u }",
David Howells0d12f8a2016-03-04 15:53:46 +0000794 sp->hdr.serial, version, nonce, min_level);
David Howells17926a72007-04-26 15:48:28 -0700795
David Howellsfb46f6e2017-04-06 10:12:00 +0100796 eproto = tracepoint_string("chall_ver");
David Howells17926a72007-04-26 15:48:28 -0700797 abort_code = RXKADINCONSISTENCY;
798 if (version != RXKAD_VERSION)
799 goto protocol_error;
800
801 abort_code = RXKADLEVELFAIL;
David Howellsef686222017-04-06 10:11:59 +0100802 ret = -EACCES;
David Howells19ffa012016-04-04 14:00:36 +0100803 if (conn->params.security_level < min_level)
David Howellsef686222017-04-06 10:11:59 +0100804 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700805
David Howells19ffa012016-04-04 14:00:36 +0100806 token = conn->params.key->payload.data[0];
David Howells17926a72007-04-26 15:48:28 -0700807
808 /* build the response packet */
David Howells8c2f8262018-02-08 15:59:07 +0000809 resp = kzalloc(sizeof(struct rxkad_response), GFP_NOFS);
810 if (!resp)
811 return -ENOMEM;
David Howells17926a72007-04-26 15:48:28 -0700812
David Howells8c2f8262018-02-08 15:59:07 +0000813 resp->version = htonl(RXKAD_VERSION);
814 resp->encrypted.epoch = htonl(conn->proto.epoch);
815 resp->encrypted.cid = htonl(conn->proto.cid);
816 resp->encrypted.securityIndex = htonl(conn->security_ix);
817 resp->encrypted.inc_nonce = htonl(nonce + 1);
818 resp->encrypted.level = htonl(conn->params.security_level);
819 resp->kvno = htonl(token->kad->kvno);
820 resp->ticket_len = htonl(token->kad->ticket_len);
821 resp->encrypted.call_id[0] = htonl(conn->channels[0].call_counter);
822 resp->encrypted.call_id[1] = htonl(conn->channels[1].call_counter);
823 resp->encrypted.call_id[2] = htonl(conn->channels[2].call_counter);
824 resp->encrypted.call_id[3] = htonl(conn->channels[3].call_counter);
David Howells17926a72007-04-26 15:48:28 -0700825
826 /* calculate the response checksum and then do the encryption */
David Howells8c2f8262018-02-08 15:59:07 +0000827 rxkad_calc_response_checksum(resp);
828 rxkad_encrypt_response(conn, resp, token->kad);
829 ret = rxkad_send_response(conn, &sp->hdr, resp, token->kad);
830 kfree(resp);
831 return ret;
David Howells17926a72007-04-26 15:48:28 -0700832
833protocol_error:
David Howellsfb46f6e2017-04-06 10:12:00 +0100834 trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
David Howellsef686222017-04-06 10:11:59 +0100835 ret = -EPROTO;
836other_error:
David Howells17926a72007-04-26 15:48:28 -0700837 *_abort_code = abort_code;
David Howellsef686222017-04-06 10:11:59 +0100838 return ret;
David Howells17926a72007-04-26 15:48:28 -0700839}
840
841/*
842 * decrypt the kerberos IV ticket in the response
843 */
844static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
David Howellsfb46f6e2017-04-06 10:12:00 +0100845 struct sk_buff *skb,
David Howells17926a72007-04-26 15:48:28 -0700846 void *ticket, size_t ticket_len,
847 struct rxrpc_crypt *_session_key,
Baolin Wang10674a02017-08-29 10:15:40 +0100848 time64_t *_expiry,
David Howells17926a72007-04-26 15:48:28 -0700849 u32 *_abort_code)
850{
Herbert Xu1afe5932016-01-24 21:19:01 +0800851 struct skcipher_request *req;
David Howellsfb46f6e2017-04-06 10:12:00 +0100852 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
David Howells17926a72007-04-26 15:48:28 -0700853 struct rxrpc_crypt iv, key;
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700854 struct scatterlist sg[1];
David Howells17926a72007-04-26 15:48:28 -0700855 struct in_addr addr;
Eric Dumazet95c96172012-04-15 05:58:06 +0000856 unsigned int life;
David Howellsfb46f6e2017-04-06 10:12:00 +0100857 const char *eproto;
Baolin Wang10674a02017-08-29 10:15:40 +0100858 time64_t issue, now;
David Howells17926a72007-04-26 15:48:28 -0700859 bool little_endian;
860 int ret;
David Howellsfb46f6e2017-04-06 10:12:00 +0100861 u32 abort_code;
David Howells17926a72007-04-26 15:48:28 -0700862 u8 *p, *q, *name, *end;
863
864 _enter("{%d},{%x}", conn->debug_id, key_serial(conn->server_key));
865
866 *_expiry = 0;
867
868 ret = key_validate(conn->server_key);
869 if (ret < 0) {
870 switch (ret) {
871 case -EKEYEXPIRED:
David Howellsfb46f6e2017-04-06 10:12:00 +0100872 abort_code = RXKADEXPIRED;
David Howellsef686222017-04-06 10:11:59 +0100873 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700874 default:
David Howellsfb46f6e2017-04-06 10:12:00 +0100875 abort_code = RXKADNOAUTH;
David Howellsef686222017-04-06 10:11:59 +0100876 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700877 }
878 }
879
David Howells146aa8b2015-10-21 14:04:48 +0100880 ASSERT(conn->server_key->payload.data[0] != NULL);
David Howells17926a72007-04-26 15:48:28 -0700881 ASSERTCMP((unsigned long) ticket & 7UL, ==, 0);
882
David Howells146aa8b2015-10-21 14:04:48 +0100883 memcpy(&iv, &conn->server_key->payload.data[2], sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700884
David Howellsef686222017-04-06 10:11:59 +0100885 ret = -ENOMEM;
Herbert Xu1afe5932016-01-24 21:19:01 +0800886 req = skcipher_request_alloc(conn->server_key->payload.data[0],
887 GFP_NOFS);
David Howellsef686222017-04-06 10:11:59 +0100888 if (!req)
889 goto temporary_error;
David Howells17926a72007-04-26 15:48:28 -0700890
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700891 sg_init_one(&sg[0], ticket, ticket_len);
Herbert Xu1afe5932016-01-24 21:19:01 +0800892 skcipher_request_set_callback(req, 0, NULL, NULL);
893 skcipher_request_set_crypt(req, sg, sg, ticket_len, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800894 crypto_skcipher_decrypt(req);
895 skcipher_request_free(req);
David Howells17926a72007-04-26 15:48:28 -0700896
897 p = ticket;
898 end = p + ticket_len;
899
David Howellsfb46f6e2017-04-06 10:12:00 +0100900#define Z(field) \
David Howells17926a72007-04-26 15:48:28 -0700901 ({ \
902 u8 *__str = p; \
David Howellsfb46f6e2017-04-06 10:12:00 +0100903 eproto = tracepoint_string("rxkad_bad_"#field); \
David Howells17926a72007-04-26 15:48:28 -0700904 q = memchr(p, 0, end - p); \
David Howellsfb46f6e2017-04-06 10:12:00 +0100905 if (!q || q - p > (field##_SZ)) \
David Howells17926a72007-04-26 15:48:28 -0700906 goto bad_ticket; \
907 for (; p < q; p++) \
908 if (!isprint(*p)) \
909 goto bad_ticket; \
910 p++; \
911 __str; \
912 })
913
914 /* extract the ticket flags */
915 _debug("KIV FLAGS: %x", *p);
916 little_endian = *p & 1;
917 p++;
918
919 /* extract the authentication name */
David Howellsfb46f6e2017-04-06 10:12:00 +0100920 name = Z(ANAME);
David Howells17926a72007-04-26 15:48:28 -0700921 _debug("KIV ANAME: %s", name);
922
923 /* extract the principal's instance */
David Howellsfb46f6e2017-04-06 10:12:00 +0100924 name = Z(INST);
David Howells17926a72007-04-26 15:48:28 -0700925 _debug("KIV INST : %s", name);
926
927 /* extract the principal's authentication domain */
David Howellsfb46f6e2017-04-06 10:12:00 +0100928 name = Z(REALM);
David Howells17926a72007-04-26 15:48:28 -0700929 _debug("KIV REALM: %s", name);
930
David Howellsfb46f6e2017-04-06 10:12:00 +0100931 eproto = tracepoint_string("rxkad_bad_len");
David Howells17926a72007-04-26 15:48:28 -0700932 if (end - p < 4 + 8 + 4 + 2)
933 goto bad_ticket;
934
935 /* get the IPv4 address of the entity that requested the ticket */
936 memcpy(&addr, p, sizeof(addr));
937 p += 4;
Harvey Harrison21454aa2008-10-31 00:54:56 -0700938 _debug("KIV ADDR : %pI4", &addr);
David Howells17926a72007-04-26 15:48:28 -0700939
940 /* get the session key from the ticket */
941 memcpy(&key, p, sizeof(key));
942 p += 8;
943 _debug("KIV KEY : %08x %08x", ntohl(key.n[0]), ntohl(key.n[1]));
944 memcpy(_session_key, &key, sizeof(key));
945
946 /* get the ticket's lifetime */
947 life = *p++ * 5 * 60;
948 _debug("KIV LIFE : %u", life);
949
950 /* get the issue time of the ticket */
951 if (little_endian) {
952 __le32 stamp;
953 memcpy(&stamp, p, 4);
Baolin Wang10674a02017-08-29 10:15:40 +0100954 issue = rxrpc_u32_to_time64(le32_to_cpu(stamp));
David Howells17926a72007-04-26 15:48:28 -0700955 } else {
956 __be32 stamp;
957 memcpy(&stamp, p, 4);
Baolin Wang10674a02017-08-29 10:15:40 +0100958 issue = rxrpc_u32_to_time64(be32_to_cpu(stamp));
David Howells17926a72007-04-26 15:48:28 -0700959 }
960 p += 4;
Baolin Wang10674a02017-08-29 10:15:40 +0100961 now = ktime_get_real_seconds();
962 _debug("KIV ISSUE: %llx [%llx]", issue, now);
David Howells17926a72007-04-26 15:48:28 -0700963
964 /* check the ticket is in date */
965 if (issue > now) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100966 abort_code = RXKADNOAUTH;
David Howells17926a72007-04-26 15:48:28 -0700967 ret = -EKEYREJECTED;
David Howellsef686222017-04-06 10:11:59 +0100968 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700969 }
970
971 if (issue < now - life) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100972 abort_code = RXKADEXPIRED;
David Howells17926a72007-04-26 15:48:28 -0700973 ret = -EKEYEXPIRED;
David Howellsef686222017-04-06 10:11:59 +0100974 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700975 }
976
977 *_expiry = issue + life;
978
979 /* get the service name */
David Howellsfb46f6e2017-04-06 10:12:00 +0100980 name = Z(SNAME);
David Howells17926a72007-04-26 15:48:28 -0700981 _debug("KIV SNAME: %s", name);
982
983 /* get the service instance name */
David Howellsfb46f6e2017-04-06 10:12:00 +0100984 name = Z(INST);
David Howells17926a72007-04-26 15:48:28 -0700985 _debug("KIV SINST: %s", name);
David Howellsef686222017-04-06 10:11:59 +0100986 return 0;
David Howells17926a72007-04-26 15:48:28 -0700987
988bad_ticket:
David Howellsfb46f6e2017-04-06 10:12:00 +0100989 trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
990 abort_code = RXKADBADTICKET;
David Howellsef686222017-04-06 10:11:59 +0100991 ret = -EPROTO;
992other_error:
David Howellsfb46f6e2017-04-06 10:12:00 +0100993 *_abort_code = abort_code;
David Howellsef686222017-04-06 10:11:59 +0100994 return ret;
995temporary_error:
996 return ret;
David Howells17926a72007-04-26 15:48:28 -0700997}
998
999/*
1000 * decrypt the response packet
1001 */
1002static void rxkad_decrypt_response(struct rxrpc_connection *conn,
1003 struct rxkad_response *resp,
1004 const struct rxrpc_crypt *session_key)
1005{
Kees Cook69d826f2018-09-18 19:10:47 -07001006 SYNC_SKCIPHER_REQUEST_ON_STACK(req, rxkad_ci);
Herbert Xua2636292016-06-26 14:55:24 -07001007 struct scatterlist sg[1];
David Howells17926a72007-04-26 15:48:28 -07001008 struct rxrpc_crypt iv;
1009
1010 _enter(",,%08x%08x",
1011 ntohl(session_key->n[0]), ntohl(session_key->n[1]));
1012
1013 ASSERT(rxkad_ci != NULL);
1014
1015 mutex_lock(&rxkad_ci_mutex);
Kees Cook69d826f2018-09-18 19:10:47 -07001016 if (crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
Herbert Xu1afe5932016-01-24 21:19:01 +08001017 sizeof(*session_key)) < 0)
David Howells17926a72007-04-26 15:48:28 -07001018 BUG();
1019
1020 memcpy(&iv, session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -07001021
Herbert Xua2636292016-06-26 14:55:24 -07001022 sg_init_table(sg, 1);
1023 sg_set_buf(sg, &resp->encrypted, sizeof(resp->encrypted));
Kees Cook69d826f2018-09-18 19:10:47 -07001024 skcipher_request_set_sync_tfm(req, rxkad_ci);
Herbert Xu1afe5932016-01-24 21:19:01 +08001025 skcipher_request_set_callback(req, 0, NULL, NULL);
1026 skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +08001027 crypto_skcipher_decrypt(req);
1028 skcipher_request_zero(req);
1029
David Howells17926a72007-04-26 15:48:28 -07001030 mutex_unlock(&rxkad_ci_mutex);
1031
1032 _leave("");
1033}
1034
1035/*
1036 * verify a response
1037 */
1038static int rxkad_verify_response(struct rxrpc_connection *conn,
1039 struct sk_buff *skb,
1040 u32 *_abort_code)
1041{
David Howells8c2f8262018-02-08 15:59:07 +00001042 struct rxkad_response *response;
David Howells248f2192016-09-08 11:10:12 +01001043 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
David Howells17926a72007-04-26 15:48:28 -07001044 struct rxrpc_crypt session_key;
David Howellsfb46f6e2017-04-06 10:12:00 +01001045 const char *eproto;
Baolin Wang10674a02017-08-29 10:15:40 +01001046 time64_t expiry;
David Howells17926a72007-04-26 15:48:28 -07001047 void *ticket;
Al Viro91e916c2008-03-29 03:08:38 +00001048 u32 abort_code, version, kvno, ticket_len, level;
1049 __be32 csum;
David Howellsa1399f82016-06-27 14:39:44 +01001050 int ret, i;
David Howells17926a72007-04-26 15:48:28 -07001051
1052 _enter("{%d,%x}", conn->debug_id, key_serial(conn->server_key));
1053
David Howells8c2f8262018-02-08 15:59:07 +00001054 ret = -ENOMEM;
1055 response = kzalloc(sizeof(struct rxkad_response), GFP_NOFS);
1056 if (!response)
1057 goto temporary_error;
1058
David Howellsfb46f6e2017-04-06 10:12:00 +01001059 eproto = tracepoint_string("rxkad_rsp_short");
David Howells17926a72007-04-26 15:48:28 -07001060 abort_code = RXKADPACKETSHORT;
David Howells775e5b72016-09-30 13:26:03 +01001061 if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
David Howells8c2f8262018-02-08 15:59:07 +00001062 response, sizeof(*response)) < 0)
David Howells17926a72007-04-26 15:48:28 -07001063 goto protocol_error;
David Howells8c2f8262018-02-08 15:59:07 +00001064 if (!pskb_pull(skb, sizeof(*response)))
David Howells17926a72007-04-26 15:48:28 -07001065 BUG();
1066
David Howells8c2f8262018-02-08 15:59:07 +00001067 version = ntohl(response->version);
1068 ticket_len = ntohl(response->ticket_len);
1069 kvno = ntohl(response->kvno);
David Howells17926a72007-04-26 15:48:28 -07001070 _proto("Rx RESPONSE %%%u { v=%u kv=%u tl=%u }",
David Howells0d12f8a2016-03-04 15:53:46 +00001071 sp->hdr.serial, version, kvno, ticket_len);
David Howells17926a72007-04-26 15:48:28 -07001072
David Howellsfb46f6e2017-04-06 10:12:00 +01001073 eproto = tracepoint_string("rxkad_rsp_ver");
David Howells17926a72007-04-26 15:48:28 -07001074 abort_code = RXKADINCONSISTENCY;
1075 if (version != RXKAD_VERSION)
David Howells4aa9cb32007-12-07 04:31:47 -08001076 goto protocol_error;
David Howells17926a72007-04-26 15:48:28 -07001077
David Howellsfb46f6e2017-04-06 10:12:00 +01001078 eproto = tracepoint_string("rxkad_rsp_tktlen");
David Howells17926a72007-04-26 15:48:28 -07001079 abort_code = RXKADTICKETLEN;
1080 if (ticket_len < 4 || ticket_len > MAXKRB5TICKETLEN)
1081 goto protocol_error;
1082
David Howellsfb46f6e2017-04-06 10:12:00 +01001083 eproto = tracepoint_string("rxkad_rsp_unkkey");
David Howells17926a72007-04-26 15:48:28 -07001084 abort_code = RXKADUNKNOWNKEY;
1085 if (kvno >= RXKAD_TKT_TYPE_KERBEROS_V5)
1086 goto protocol_error;
1087
1088 /* extract the kerberos ticket and decrypt and decode it */
David Howellsef686222017-04-06 10:11:59 +01001089 ret = -ENOMEM;
David Howells17926a72007-04-26 15:48:28 -07001090 ticket = kmalloc(ticket_len, GFP_NOFS);
1091 if (!ticket)
David Howellsef686222017-04-06 10:11:59 +01001092 goto temporary_error;
David Howells17926a72007-04-26 15:48:28 -07001093
David Howellsfb46f6e2017-04-06 10:12:00 +01001094 eproto = tracepoint_string("rxkad_tkt_short");
David Howells17926a72007-04-26 15:48:28 -07001095 abort_code = RXKADPACKETSHORT;
David Howells775e5b72016-09-30 13:26:03 +01001096 if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
1097 ticket, ticket_len) < 0)
David Howells17926a72007-04-26 15:48:28 -07001098 goto protocol_error_free;
1099
David Howellsfb46f6e2017-04-06 10:12:00 +01001100 ret = rxkad_decrypt_ticket(conn, skb, ticket, ticket_len, &session_key,
David Howellsef686222017-04-06 10:11:59 +01001101 &expiry, _abort_code);
1102 if (ret < 0)
David Howells8c2f8262018-02-08 15:59:07 +00001103 goto temporary_error_free_resp;
David Howells17926a72007-04-26 15:48:28 -07001104
1105 /* use the session key from inside the ticket to decrypt the
1106 * response */
David Howells8c2f8262018-02-08 15:59:07 +00001107 rxkad_decrypt_response(conn, response, &session_key);
David Howells17926a72007-04-26 15:48:28 -07001108
David Howellsfb46f6e2017-04-06 10:12:00 +01001109 eproto = tracepoint_string("rxkad_rsp_param");
David Howells17926a72007-04-26 15:48:28 -07001110 abort_code = RXKADSEALEDINCON;
David Howells8c2f8262018-02-08 15:59:07 +00001111 if (ntohl(response->encrypted.epoch) != conn->proto.epoch)
David Howells17926a72007-04-26 15:48:28 -07001112 goto protocol_error_free;
David Howells8c2f8262018-02-08 15:59:07 +00001113 if (ntohl(response->encrypted.cid) != conn->proto.cid)
David Howells17926a72007-04-26 15:48:28 -07001114 goto protocol_error_free;
David Howells8c2f8262018-02-08 15:59:07 +00001115 if (ntohl(response->encrypted.securityIndex) != conn->security_ix)
David Howells17926a72007-04-26 15:48:28 -07001116 goto protocol_error_free;
David Howells8c2f8262018-02-08 15:59:07 +00001117 csum = response->encrypted.checksum;
1118 response->encrypted.checksum = 0;
1119 rxkad_calc_response_checksum(response);
David Howellsfb46f6e2017-04-06 10:12:00 +01001120 eproto = tracepoint_string("rxkad_rsp_csum");
David Howells8c2f8262018-02-08 15:59:07 +00001121 if (response->encrypted.checksum != csum)
David Howells17926a72007-04-26 15:48:28 -07001122 goto protocol_error_free;
1123
David Howellsa1399f82016-06-27 14:39:44 +01001124 spin_lock(&conn->channel_lock);
1125 for (i = 0; i < RXRPC_MAXCALLS; i++) {
1126 struct rxrpc_call *call;
David Howells8c2f8262018-02-08 15:59:07 +00001127 u32 call_id = ntohl(response->encrypted.call_id[i]);
David Howellsa1399f82016-06-27 14:39:44 +01001128
David Howellsfb46f6e2017-04-06 10:12:00 +01001129 eproto = tracepoint_string("rxkad_rsp_callid");
David Howellsa1399f82016-06-27 14:39:44 +01001130 if (call_id > INT_MAX)
1131 goto protocol_error_unlock;
1132
David Howellsfb46f6e2017-04-06 10:12:00 +01001133 eproto = tracepoint_string("rxkad_rsp_callctr");
David Howellsa1399f82016-06-27 14:39:44 +01001134 if (call_id < conn->channels[i].call_counter)
1135 goto protocol_error_unlock;
David Howellsfb46f6e2017-04-06 10:12:00 +01001136
1137 eproto = tracepoint_string("rxkad_rsp_callst");
David Howellsa1399f82016-06-27 14:39:44 +01001138 if (call_id > conn->channels[i].call_counter) {
1139 call = rcu_dereference_protected(
1140 conn->channels[i].call,
1141 lockdep_is_held(&conn->channel_lock));
1142 if (call && call->state < RXRPC_CALL_COMPLETE)
1143 goto protocol_error_unlock;
1144 conn->channels[i].call_counter = call_id;
1145 }
1146 }
1147 spin_unlock(&conn->channel_lock);
David Howells17926a72007-04-26 15:48:28 -07001148
David Howellsfb46f6e2017-04-06 10:12:00 +01001149 eproto = tracepoint_string("rxkad_rsp_seq");
David Howells17926a72007-04-26 15:48:28 -07001150 abort_code = RXKADOUTOFSEQUENCE;
David Howells8c2f8262018-02-08 15:59:07 +00001151 if (ntohl(response->encrypted.inc_nonce) != conn->security_nonce + 1)
David Howells17926a72007-04-26 15:48:28 -07001152 goto protocol_error_free;
1153
David Howellsfb46f6e2017-04-06 10:12:00 +01001154 eproto = tracepoint_string("rxkad_rsp_level");
David Howells17926a72007-04-26 15:48:28 -07001155 abort_code = RXKADLEVELFAIL;
David Howells8c2f8262018-02-08 15:59:07 +00001156 level = ntohl(response->encrypted.level);
David Howells17926a72007-04-26 15:48:28 -07001157 if (level > RXRPC_SECURITY_ENCRYPT)
1158 goto protocol_error_free;
David Howells19ffa012016-04-04 14:00:36 +01001159 conn->params.security_level = level;
David Howells17926a72007-04-26 15:48:28 -07001160
1161 /* create a key to hold the security data and expiration time - after
1162 * this the connection security can be handled in exactly the same way
1163 * as for a client connection */
1164 ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno);
David Howellsef686222017-04-06 10:11:59 +01001165 if (ret < 0)
David Howells8c2f8262018-02-08 15:59:07 +00001166 goto temporary_error_free_ticket;
David Howells17926a72007-04-26 15:48:28 -07001167
1168 kfree(ticket);
David Howells8c2f8262018-02-08 15:59:07 +00001169 kfree(response);
David Howells17926a72007-04-26 15:48:28 -07001170 _leave(" = 0");
1171 return 0;
1172
David Howellsa1399f82016-06-27 14:39:44 +01001173protocol_error_unlock:
1174 spin_unlock(&conn->channel_lock);
David Howells17926a72007-04-26 15:48:28 -07001175protocol_error_free:
1176 kfree(ticket);
1177protocol_error:
David Howells8c2f8262018-02-08 15:59:07 +00001178 kfree(response);
David Howellsfb46f6e2017-04-06 10:12:00 +01001179 trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
David Howells17926a72007-04-26 15:48:28 -07001180 *_abort_code = abort_code;
David Howells17926a72007-04-26 15:48:28 -07001181 return -EPROTO;
David Howellsef686222017-04-06 10:11:59 +01001182
David Howells8c2f8262018-02-08 15:59:07 +00001183temporary_error_free_ticket:
David Howellsef686222017-04-06 10:11:59 +01001184 kfree(ticket);
David Howells8c2f8262018-02-08 15:59:07 +00001185temporary_error_free_resp:
1186 kfree(response);
David Howellsef686222017-04-06 10:11:59 +01001187temporary_error:
1188 /* Ignore the response packet if we got a temporary error such as
1189 * ENOMEM. We just want to send the challenge again. Note that we
1190 * also come out this way if the ticket decryption fails.
1191 */
1192 return ret;
David Howells17926a72007-04-26 15:48:28 -07001193}
1194
1195/*
1196 * clear the connection security
1197 */
1198static void rxkad_clear(struct rxrpc_connection *conn)
1199{
1200 _enter("");
1201
1202 if (conn->cipher)
Kees Cook69d826f2018-09-18 19:10:47 -07001203 crypto_free_sync_skcipher(conn->cipher);
David Howells17926a72007-04-26 15:48:28 -07001204}
1205
1206/*
David Howells648af7f2016-04-07 17:23:51 +01001207 * Initialise the rxkad security service.
1208 */
1209static int rxkad_init(void)
1210{
1211 /* pin the cipher we need so that the crypto layer doesn't invoke
1212 * keventd to go get it */
Kees Cook69d826f2018-09-18 19:10:47 -07001213 rxkad_ci = crypto_alloc_sync_skcipher("pcbc(fcrypt)", 0, 0);
Wu Fengguangfa54cc72016-06-05 07:17:19 +08001214 return PTR_ERR_OR_ZERO(rxkad_ci);
David Howells648af7f2016-04-07 17:23:51 +01001215}
1216
1217/*
1218 * Clean up the rxkad security service.
1219 */
1220static void rxkad_exit(void)
1221{
1222 if (rxkad_ci)
Kees Cook69d826f2018-09-18 19:10:47 -07001223 crypto_free_sync_skcipher(rxkad_ci);
David Howells648af7f2016-04-07 17:23:51 +01001224}
1225
1226/*
David Howells17926a72007-04-26 15:48:28 -07001227 * RxRPC Kerberos-based security
1228 */
David Howells648af7f2016-04-07 17:23:51 +01001229const struct rxrpc_security rxkad = {
David Howells17926a72007-04-26 15:48:28 -07001230 .name = "rxkad",
David Howells8b815472009-09-14 01:17:30 +00001231 .security_index = RXRPC_SECURITY_RXKAD,
David Howells648af7f2016-04-07 17:23:51 +01001232 .init = rxkad_init,
1233 .exit = rxkad_exit,
David Howells17926a72007-04-26 15:48:28 -07001234 .init_connection_security = rxkad_init_connection_security,
1235 .prime_packet_security = rxkad_prime_packet_security,
1236 .secure_packet = rxkad_secure_packet,
1237 .verify_packet = rxkad_verify_packet,
David Howells248f2192016-09-08 11:10:12 +01001238 .locate_data = rxkad_locate_data,
David Howells17926a72007-04-26 15:48:28 -07001239 .issue_challenge = rxkad_issue_challenge,
1240 .respond_to_challenge = rxkad_respond_to_challenge,
1241 .verify_response = rxkad_verify_response,
1242 .clear = rxkad_clear,
1243};