blob: 301894857473344a431075a15a56818fe74200af [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 Howells12da59f2020-09-16 08:37:29 +010018#include <linux/key-type.h>
David Howells17926a72007-04-26 15:48:28 -070019#include <net/sock.h>
20#include <net/af_rxrpc.h>
David Howells33941282009-09-14 01:17:35 +000021#include <keys/rxrpc-type.h>
David Howells17926a72007-04-26 15:48:28 -070022#include "ar-internal.h"
23
24#define RXKAD_VERSION 2
25#define MAXKRB5TICKETLEN 1024
26#define RXKAD_TKT_TYPE_KERBEROS_V5 256
27#define ANAME_SZ 40 /* size of authentication name */
28#define INST_SZ 40 /* size of principal's instance */
29#define REALM_SZ 40 /* size of principal's auth domain */
30#define SNAME_SZ 40 /* size of service name */
31
David Howells17926a72007-04-26 15:48:28 -070032struct rxkad_level1_hdr {
33 __be32 data_size; /* true data size (excluding padding) */
34};
35
36struct rxkad_level2_hdr {
37 __be32 data_size; /* true data size (excluding padding) */
38 __be32 checksum; /* decrypted data checksum */
39};
40
David Howells8d47a432020-09-16 01:38:15 +010041static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
42 struct crypto_sync_skcipher *ci);
43
David Howells17926a72007-04-26 15:48:28 -070044/*
45 * this holds a pinned cipher so that keventd doesn't get called by the cipher
46 * alloc routine, but since we have it to hand, we use it to decrypt RESPONSE
47 * packets
48 */
Kees Cook69d826f2018-09-18 19:10:47 -070049static struct crypto_sync_skcipher *rxkad_ci;
David Howells1db88c52019-07-30 15:56:57 +010050static struct skcipher_request *rxkad_ci_req;
David Howells17926a72007-04-26 15:48:28 -070051static DEFINE_MUTEX(rxkad_ci_mutex);
52
53/*
David Howells12da59f2020-09-16 08:37:29 +010054 * Parse the information from a server key
55 *
56 * The data should be the 8-byte secret key.
57 */
58static int rxkad_preparse_server_key(struct key_preparsed_payload *prep)
59{
60 struct crypto_skcipher *ci;
61
62 if (prep->datalen != 8)
63 return -EINVAL;
64
65 memcpy(&prep->payload.data[2], prep->data, 8);
66
67 ci = crypto_alloc_skcipher("pcbc(des)", 0, CRYPTO_ALG_ASYNC);
68 if (IS_ERR(ci)) {
69 _leave(" = %ld", PTR_ERR(ci));
70 return PTR_ERR(ci);
71 }
72
73 if (crypto_skcipher_setkey(ci, prep->data, 8) < 0)
74 BUG();
75
76 prep->payload.data[0] = ci;
77 _leave(" = 0");
78 return 0;
79}
80
81static void rxkad_free_preparse_server_key(struct key_preparsed_payload *prep)
82{
83
84 if (prep->payload.data[0])
85 crypto_free_skcipher(prep->payload.data[0]);
86}
87
88static void rxkad_destroy_server_key(struct key *key)
89{
90 if (key->payload.data[0]) {
91 crypto_free_skcipher(key->payload.data[0]);
92 key->payload.data[0] = NULL;
93 }
94}
95
96/*
David Howells17926a72007-04-26 15:48:28 -070097 * initialise connection security
98 */
David Howells41057eb2020-09-16 08:19:12 +010099static int rxkad_init_connection_security(struct rxrpc_connection *conn,
100 struct rxrpc_key_token *token)
David Howells17926a72007-04-26 15:48:28 -0700101{
Kees Cook69d826f2018-09-18 19:10:47 -0700102 struct crypto_sync_skcipher *ci;
David Howells17926a72007-04-26 15:48:28 -0700103 int ret;
104
David Howells19ffa012016-04-04 14:00:36 +0100105 _enter("{%d},{%x}", conn->debug_id, key_serial(conn->params.key));
David Howells17926a72007-04-26 15:48:28 -0700106
David Howells33941282009-09-14 01:17:35 +0000107 conn->security_ix = token->security_index;
David Howells17926a72007-04-26 15:48:28 -0700108
Kees Cook69d826f2018-09-18 19:10:47 -0700109 ci = crypto_alloc_sync_skcipher("pcbc(fcrypt)", 0, 0);
David Howells17926a72007-04-26 15:48:28 -0700110 if (IS_ERR(ci)) {
111 _debug("no cipher");
112 ret = PTR_ERR(ci);
113 goto error;
114 }
115
Kees Cook69d826f2018-09-18 19:10:47 -0700116 if (crypto_sync_skcipher_setkey(ci, token->kad->session_key,
Herbert Xu1afe5932016-01-24 21:19:01 +0800117 sizeof(token->kad->session_key)) < 0)
David Howells17926a72007-04-26 15:48:28 -0700118 BUG();
119
David Howells19ffa012016-04-04 14:00:36 +0100120 switch (conn->params.security_level) {
David Howells17926a72007-04-26 15:48:28 -0700121 case RXRPC_SECURITY_PLAIN:
122 break;
123 case RXRPC_SECURITY_AUTH:
124 conn->size_align = 8;
125 conn->security_size = sizeof(struct rxkad_level1_hdr);
David Howells17926a72007-04-26 15:48:28 -0700126 break;
127 case RXRPC_SECURITY_ENCRYPT:
128 conn->size_align = 8;
129 conn->security_size = sizeof(struct rxkad_level2_hdr);
David Howells17926a72007-04-26 15:48:28 -0700130 break;
131 default:
132 ret = -EKEYREJECTED;
133 goto error;
134 }
135
David Howells8d47a432020-09-16 01:38:15 +0100136 ret = rxkad_prime_packet_security(conn, ci);
137 if (ret < 0)
138 goto error_ci;
139
David Howells17926a72007-04-26 15:48:28 -0700140 conn->cipher = ci;
David Howells8d47a432020-09-16 01:38:15 +0100141 return 0;
142
143error_ci:
144 crypto_free_sync_skcipher(ci);
David Howells17926a72007-04-26 15:48:28 -0700145error:
146 _leave(" = %d", ret);
147 return ret;
148}
149
150/*
151 * prime the encryption state with the invariant parts of a connection's
152 * description
153 */
David Howells8d47a432020-09-16 01:38:15 +0100154static int rxkad_prime_packet_security(struct rxrpc_connection *conn,
155 struct crypto_sync_skcipher *ci)
David Howells17926a72007-04-26 15:48:28 -0700156{
David Howells1db88c52019-07-30 15:56:57 +0100157 struct skcipher_request *req;
David Howells33941282009-09-14 01:17:35 +0000158 struct rxrpc_key_token *token;
Herbert Xua2636292016-06-26 14:55:24 -0700159 struct scatterlist sg;
David Howells17926a72007-04-26 15:48:28 -0700160 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700161 __be32 *tmpbuf;
162 size_t tmpsize = 4 * sizeof(__be32);
David Howells17926a72007-04-26 15:48:28 -0700163
164 _enter("");
165
David Howells19ffa012016-04-04 14:00:36 +0100166 if (!conn->params.key)
Herbert Xua2636292016-06-26 14:55:24 -0700167 return 0;
168
169 tmpbuf = kmalloc(tmpsize, GFP_KERNEL);
170 if (!tmpbuf)
171 return -ENOMEM;
David Howells17926a72007-04-26 15:48:28 -0700172
David Howells8d47a432020-09-16 01:38:15 +0100173 req = skcipher_request_alloc(&ci->base, GFP_NOFS);
David Howells1db88c52019-07-30 15:56:57 +0100174 if (!req) {
175 kfree(tmpbuf);
176 return -ENOMEM;
177 }
178
David Howells19ffa012016-04-04 14:00:36 +0100179 token = conn->params.key->payload.data[0];
David Howells33941282009-09-14 01:17:35 +0000180 memcpy(&iv, token->kad->session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700181
Herbert Xua2636292016-06-26 14:55:24 -0700182 tmpbuf[0] = htonl(conn->proto.epoch);
183 tmpbuf[1] = htonl(conn->proto.cid);
184 tmpbuf[2] = 0;
185 tmpbuf[3] = htonl(conn->security_ix);
David Howells17926a72007-04-26 15:48:28 -0700186
Herbert Xua2636292016-06-26 14:55:24 -0700187 sg_init_one(&sg, tmpbuf, tmpsize);
David Howells8d47a432020-09-16 01:38:15 +0100188 skcipher_request_set_sync_tfm(req, ci);
Herbert Xu1afe5932016-01-24 21:19:01 +0800189 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700190 skcipher_request_set_crypt(req, &sg, &sg, tmpsize, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800191 crypto_skcipher_encrypt(req);
David Howells1db88c52019-07-30 15:56:57 +0100192 skcipher_request_free(req);
David Howells17926a72007-04-26 15:48:28 -0700193
Herbert Xua2636292016-06-26 14:55:24 -0700194 memcpy(&conn->csum_iv, tmpbuf + 2, sizeof(conn->csum_iv));
195 kfree(tmpbuf);
196 _leave(" = 0");
197 return 0;
David Howells17926a72007-04-26 15:48:28 -0700198}
199
200/*
David Howells1db88c52019-07-30 15:56:57 +0100201 * Allocate and prepare the crypto request on a call. For any particular call,
202 * this is called serially for the packets, so no lock should be necessary.
203 */
204static struct skcipher_request *rxkad_get_call_crypto(struct rxrpc_call *call)
205{
206 struct crypto_skcipher *tfm = &call->conn->cipher->base;
207 struct skcipher_request *cipher_req = call->cipher_req;
208
209 if (!cipher_req) {
210 cipher_req = skcipher_request_alloc(tfm, GFP_NOFS);
211 if (!cipher_req)
212 return NULL;
213 call->cipher_req = cipher_req;
214 }
215
216 return cipher_req;
217}
218
219/*
220 * Clean up the crypto on a call.
221 */
222static void rxkad_free_call_crypto(struct rxrpc_call *call)
223{
224 if (call->cipher_req)
225 skcipher_request_free(call->cipher_req);
226 call->cipher_req = NULL;
227}
228
229/*
David Howells17926a72007-04-26 15:48:28 -0700230 * partially encrypt a packet (level 1 security)
231 */
232static int rxkad_secure_packet_auth(const struct rxrpc_call *call,
233 struct sk_buff *skb,
234 u32 data_size,
Kees Cook54424d32018-08-03 10:15:25 +0100235 void *sechdr,
236 struct skcipher_request *req)
David Howells17926a72007-04-26 15:48:28 -0700237{
David Howellsfb46f6e2017-04-06 10:12:00 +0100238 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
Herbert Xua2636292016-06-26 14:55:24 -0700239 struct rxkad_level1_hdr hdr;
David Howells17926a72007-04-26 15:48:28 -0700240 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700241 struct scatterlist sg;
David Howells17926a72007-04-26 15:48:28 -0700242 u16 check;
243
David Howells17926a72007-04-26 15:48:28 -0700244 _enter("");
245
David Howells5a924b82016-09-22 00:29:31 +0100246 check = sp->hdr.seq ^ call->call_id;
David Howells0d12f8a2016-03-04 15:53:46 +0000247 data_size |= (u32)check << 16;
David Howells17926a72007-04-26 15:48:28 -0700248
Herbert Xua2636292016-06-26 14:55:24 -0700249 hdr.data_size = htonl(data_size);
250 memcpy(sechdr, &hdr, sizeof(hdr));
David Howells17926a72007-04-26 15:48:28 -0700251
252 /* start the encryption afresh */
253 memset(&iv, 0, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700254
Herbert Xua2636292016-06-26 14:55:24 -0700255 sg_init_one(&sg, sechdr, 8);
Kees Cook69d826f2018-09-18 19:10:47 -0700256 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800257 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700258 skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800259 crypto_skcipher_encrypt(req);
260 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700261
David Howells17926a72007-04-26 15:48:28 -0700262 _leave(" = 0");
263 return 0;
264}
265
266/*
267 * wholly encrypt a packet (level 2 security)
268 */
269static int rxkad_secure_packet_encrypt(const struct rxrpc_call *call,
David Howellsb4f13422016-03-04 15:56:19 +0000270 struct sk_buff *skb,
271 u32 data_size,
Kees Cook54424d32018-08-03 10:15:25 +0100272 void *sechdr,
273 struct skcipher_request *req)
David Howells17926a72007-04-26 15:48:28 -0700274{
David Howells33941282009-09-14 01:17:35 +0000275 const struct rxrpc_key_token *token;
Herbert Xua2636292016-06-26 14:55:24 -0700276 struct rxkad_level2_hdr rxkhdr;
David Howells17926a72007-04-26 15:48:28 -0700277 struct rxrpc_skb_priv *sp;
David Howells17926a72007-04-26 15:48:28 -0700278 struct rxrpc_crypt iv;
279 struct scatterlist sg[16];
Eric Dumazet95c96172012-04-15 05:58:06 +0000280 unsigned int len;
David Howells17926a72007-04-26 15:48:28 -0700281 u16 check;
Herbert Xu1afe5932016-01-24 21:19:01 +0800282 int err;
David Howells17926a72007-04-26 15:48:28 -0700283
284 sp = rxrpc_skb(skb);
285
286 _enter("");
287
David Howells5a924b82016-09-22 00:29:31 +0100288 check = sp->hdr.seq ^ call->call_id;
David Howells17926a72007-04-26 15:48:28 -0700289
David Howells0d12f8a2016-03-04 15:53:46 +0000290 rxkhdr.data_size = htonl(data_size | (u32)check << 16);
David Howells17926a72007-04-26 15:48:28 -0700291 rxkhdr.checksum = 0;
Herbert Xua2636292016-06-26 14:55:24 -0700292 memcpy(sechdr, &rxkhdr, sizeof(rxkhdr));
David Howells17926a72007-04-26 15:48:28 -0700293
294 /* encrypt from the session key */
David Howells19ffa012016-04-04 14:00:36 +0100295 token = call->conn->params.key->payload.data[0];
David Howells33941282009-09-14 01:17:35 +0000296 memcpy(&iv, token->kad->session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700297
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700298 sg_init_one(&sg[0], sechdr, sizeof(rxkhdr));
Kees Cook69d826f2018-09-18 19:10:47 -0700299 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800300 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700301 skcipher_request_set_crypt(req, &sg[0], &sg[0], sizeof(rxkhdr), iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800302 crypto_skcipher_encrypt(req);
David Howells17926a72007-04-26 15:48:28 -0700303
304 /* we want to encrypt the skbuff in-place */
David Howellsd0d5c0c2019-08-27 10:13:46 +0100305 err = -EMSGSIZE;
306 if (skb_shinfo(skb)->nr_frags > 16)
Herbert Xu1afe5932016-01-24 21:19:01 +0800307 goto out;
David Howells17926a72007-04-26 15:48:28 -0700308
309 len = data_size + call->conn->size_align - 1;
310 len &= ~(call->conn->size_align - 1);
311
David Howellsd0d5c0c2019-08-27 10:13:46 +0100312 sg_init_table(sg, ARRAY_SIZE(sg));
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200313 err = skb_to_sgvec(skb, sg, 0, len);
314 if (unlikely(err < 0))
315 goto out;
Herbert Xu1afe5932016-01-24 21:19:01 +0800316 skcipher_request_set_crypt(req, sg, sg, len, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800317 crypto_skcipher_encrypt(req);
David Howells17926a72007-04-26 15:48:28 -0700318
319 _leave(" = 0");
Herbert Xu1afe5932016-01-24 21:19:01 +0800320 err = 0;
321
322out:
323 skcipher_request_zero(req);
324 return err;
David Howells17926a72007-04-26 15:48:28 -0700325}
326
327/*
328 * checksum an RxRPC packet header
329 */
Herbert Xua2636292016-06-26 14:55:24 -0700330static int rxkad_secure_packet(struct rxrpc_call *call,
David Howellsb4f13422016-03-04 15:56:19 +0000331 struct sk_buff *skb,
332 size_t data_size,
333 void *sechdr)
David Howells17926a72007-04-26 15:48:28 -0700334{
335 struct rxrpc_skb_priv *sp;
David Howells1db88c52019-07-30 15:56:57 +0100336 struct skcipher_request *req;
David Howells17926a72007-04-26 15:48:28 -0700337 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700338 struct scatterlist sg;
David Howells0d12f8a2016-03-04 15:53:46 +0000339 u32 x, y;
David Howells17926a72007-04-26 15:48:28 -0700340 int ret;
341
342 sp = rxrpc_skb(skb);
343
344 _enter("{%d{%x}},{#%u},%zu,",
David Howells19ffa012016-04-04 14:00:36 +0100345 call->debug_id, key_serial(call->conn->params.key),
346 sp->hdr.seq, data_size);
David Howells17926a72007-04-26 15:48:28 -0700347
348 if (!call->conn->cipher)
349 return 0;
350
David Howells19ffa012016-04-04 14:00:36 +0100351 ret = key_validate(call->conn->params.key);
David Howells17926a72007-04-26 15:48:28 -0700352 if (ret < 0)
353 return ret;
354
David Howells1db88c52019-07-30 15:56:57 +0100355 req = rxkad_get_call_crypto(call);
356 if (!req)
357 return -ENOMEM;
358
David Howells17926a72007-04-26 15:48:28 -0700359 /* continue encrypting from where we left off */
360 memcpy(&iv, call->conn->csum_iv.x, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700361
362 /* calculate the security checksum */
David Howells01a90a42016-08-23 15:27:24 +0100363 x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
David Howells0d12f8a2016-03-04 15:53:46 +0000364 x |= sp->hdr.seq & 0x3fffffff;
David Howells5a924b82016-09-22 00:29:31 +0100365 call->crypto_buf[0] = htonl(call->call_id);
Herbert Xua2636292016-06-26 14:55:24 -0700366 call->crypto_buf[1] = htonl(x);
David Howells17926a72007-04-26 15:48:28 -0700367
Herbert Xua2636292016-06-26 14:55:24 -0700368 sg_init_one(&sg, call->crypto_buf, 8);
Kees Cook69d826f2018-09-18 19:10:47 -0700369 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800370 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700371 skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800372 crypto_skcipher_encrypt(req);
373 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700374
Herbert Xua2636292016-06-26 14:55:24 -0700375 y = ntohl(call->crypto_buf[1]);
Al Viro91e916c2008-03-29 03:08:38 +0000376 y = (y >> 16) & 0xffff;
377 if (y == 0)
378 y = 1; /* zero checksums are not permitted */
David Howells0d12f8a2016-03-04 15:53:46 +0000379 sp->hdr.cksum = y;
David Howells17926a72007-04-26 15:48:28 -0700380
David Howells19ffa012016-04-04 14:00:36 +0100381 switch (call->conn->params.security_level) {
David Howells17926a72007-04-26 15:48:28 -0700382 case RXRPC_SECURITY_PLAIN:
383 ret = 0;
384 break;
385 case RXRPC_SECURITY_AUTH:
Kees Cook54424d32018-08-03 10:15:25 +0100386 ret = rxkad_secure_packet_auth(call, skb, data_size, sechdr,
387 req);
David Howells17926a72007-04-26 15:48:28 -0700388 break;
389 case RXRPC_SECURITY_ENCRYPT:
390 ret = rxkad_secure_packet_encrypt(call, skb, data_size,
Kees Cook54424d32018-08-03 10:15:25 +0100391 sechdr, req);
David Howells17926a72007-04-26 15:48:28 -0700392 break;
393 default:
394 ret = -EPERM;
395 break;
396 }
397
Al Viro91e916c2008-03-29 03:08:38 +0000398 _leave(" = %d [set %hx]", ret, y);
David Howells17926a72007-04-26 15:48:28 -0700399 return ret;
400}
401
402/*
403 * decrypt partial encryption on a packet (level 1 security)
404 */
David Howells5a429762016-09-06 22:19:51 +0100405static int rxkad_verify_packet_1(struct rxrpc_call *call, struct sk_buff *skb,
David Howells248f2192016-09-08 11:10:12 +0100406 unsigned int offset, unsigned int len,
Kees Cook54424d32018-08-03 10:15:25 +0100407 rxrpc_seq_t seq,
408 struct skcipher_request *req)
David Howells17926a72007-04-26 15:48:28 -0700409{
410 struct rxkad_level1_hdr sechdr;
David Howells17926a72007-04-26 15:48:28 -0700411 struct rxrpc_crypt iv;
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700412 struct scatterlist sg[16];
David Howellsfb46f6e2017-04-06 10:12:00 +0100413 bool aborted;
David Howells17926a72007-04-26 15:48:28 -0700414 u32 data_size, buf;
415 u16 check;
David Howellsd0d5c0c2019-08-27 10:13:46 +0100416 int ret;
David Howells17926a72007-04-26 15:48:28 -0700417
418 _enter("");
419
David Howells248f2192016-09-08 11:10:12 +0100420 if (len < 8) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100421 aborted = rxrpc_abort_eproto(call, skb, "rxkad_1_hdr", "V1H",
422 RXKADSEALEDINCON);
David Howells5a429762016-09-06 22:19:51 +0100423 goto protocol_error;
424 }
David Howells17926a72007-04-26 15:48:28 -0700425
David Howells248f2192016-09-08 11:10:12 +0100426 /* Decrypt the skbuff in-place. TODO: We really want to decrypt
427 * directly into the target buffer.
428 */
David Howellsd0d5c0c2019-08-27 10:13:46 +0100429 sg_init_table(sg, ARRAY_SIZE(sg));
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200430 ret = skb_to_sgvec(skb, sg, offset, 8);
431 if (unlikely(ret < 0))
432 return ret;
David Howells17926a72007-04-26 15:48:28 -0700433
434 /* start the decryption afresh */
435 memset(&iv, 0, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700436
Kees Cook69d826f2018-09-18 19:10:47 -0700437 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800438 skcipher_request_set_callback(req, 0, NULL, NULL);
439 skcipher_request_set_crypt(req, sg, sg, 8, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800440 crypto_skcipher_decrypt(req);
441 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700442
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_1_len", "XV1",
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_1_check", "V1C",
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_1_datalen", "V1L",
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;
David Howells17926a72007-04-26 15:48:28 -0700477}
478
479/*
480 * wholly decrypt a packet (level 2 security)
481 */
David Howells5a429762016-09-06 22:19:51 +0100482static int rxkad_verify_packet_2(struct rxrpc_call *call, struct sk_buff *skb,
David Howells248f2192016-09-08 11:10:12 +0100483 unsigned int offset, unsigned int len,
Kees Cook54424d32018-08-03 10:15:25 +0100484 rxrpc_seq_t seq,
485 struct skcipher_request *req)
David Howells17926a72007-04-26 15:48:28 -0700486{
David Howells33941282009-09-14 01:17:35 +0000487 const struct rxrpc_key_token *token;
David Howells17926a72007-04-26 15:48:28 -0700488 struct rxkad_level2_hdr sechdr;
David Howells17926a72007-04-26 15:48:28 -0700489 struct rxrpc_crypt iv;
490 struct scatterlist _sg[4], *sg;
David Howellsfb46f6e2017-04-06 10:12:00 +0100491 bool aborted;
David Howells17926a72007-04-26 15:48:28 -0700492 u32 data_size, buf;
493 u16 check;
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200494 int nsg, ret;
David Howells17926a72007-04-26 15:48:28 -0700495
496 _enter(",{%d}", skb->len);
497
David Howells248f2192016-09-08 11:10:12 +0100498 if (len < 8) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100499 aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_hdr", "V2H",
500 RXKADSEALEDINCON);
David Howells5a429762016-09-06 22:19:51 +0100501 goto protocol_error;
502 }
David Howells17926a72007-04-26 15:48:28 -0700503
David Howells248f2192016-09-08 11:10:12 +0100504 /* Decrypt the skbuff in-place. TODO: We really want to decrypt
505 * directly into the target buffer.
506 */
David Howells17926a72007-04-26 15:48:28 -0700507 sg = _sg;
David Howellsd0d5c0c2019-08-27 10:13:46 +0100508 nsg = skb_shinfo(skb)->nr_frags;
509 if (nsg <= 4) {
510 nsg = 4;
511 } else {
Kees Cook6da2ec52018-06-12 13:55:00 -0700512 sg = kmalloc_array(nsg, sizeof(*sg), GFP_NOIO);
David Howells17926a72007-04-26 15:48:28 -0700513 if (!sg)
514 goto nomem;
515 }
516
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700517 sg_init_table(sg, nsg);
Jason A. Donenfeld89a5ea92017-06-04 04:16:24 +0200518 ret = skb_to_sgvec(skb, sg, offset, len);
519 if (unlikely(ret < 0)) {
520 if (sg != _sg)
521 kfree(sg);
522 return ret;
523 }
David Howells17926a72007-04-26 15:48:28 -0700524
525 /* decrypt from the session key */
David Howells19ffa012016-04-04 14:00:36 +0100526 token = call->conn->params.key->payload.data[0];
David Howells33941282009-09-14 01:17:35 +0000527 memcpy(&iv, token->kad->session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700528
Kees Cook69d826f2018-09-18 19:10:47 -0700529 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800530 skcipher_request_set_callback(req, 0, NULL, NULL);
David Howells248f2192016-09-08 11:10:12 +0100531 skcipher_request_set_crypt(req, sg, sg, len, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800532 crypto_skcipher_decrypt(req);
533 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700534 if (sg != _sg)
535 kfree(sg);
536
David Howells5a429762016-09-06 22:19:51 +0100537 /* Extract the decrypted packet length */
David Howells248f2192016-09-08 11:10:12 +0100538 if (skb_copy_bits(skb, offset, &sechdr, sizeof(sechdr)) < 0) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100539 aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_len", "XV2",
540 RXKADDATALEN);
David Howells5a429762016-09-06 22:19:51 +0100541 goto protocol_error;
542 }
David Howells248f2192016-09-08 11:10:12 +0100543 offset += sizeof(sechdr);
544 len -= sizeof(sechdr);
David Howells17926a72007-04-26 15:48:28 -0700545
546 buf = ntohl(sechdr.data_size);
547 data_size = buf & 0xffff;
548
549 check = buf >> 16;
David Howells5a429762016-09-06 22:19:51 +0100550 check ^= seq ^ call->call_id;
David Howells17926a72007-04-26 15:48:28 -0700551 check &= 0xffff;
552 if (check != 0) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100553 aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_check", "V2C",
554 RXKADSEALEDINCON);
David Howells17926a72007-04-26 15:48:28 -0700555 goto protocol_error;
556 }
557
David Howells248f2192016-09-08 11:10:12 +0100558 if (data_size > len) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100559 aborted = rxrpc_abort_eproto(call, skb, "rxkad_2_datalen", "V2L",
560 RXKADDATALEN);
David Howells5a429762016-09-06 22:19:51 +0100561 goto protocol_error;
562 }
David Howells17926a72007-04-26 15:48:28 -0700563
564 _leave(" = 0 [dlen=%x]", data_size);
565 return 0;
566
David Howells17926a72007-04-26 15:48:28 -0700567protocol_error:
David Howellsfb46f6e2017-04-06 10:12:00 +0100568 if (aborted)
569 rxrpc_send_abort_packet(call);
David Howells17926a72007-04-26 15:48:28 -0700570 return -EPROTO;
571
572nomem:
573 _leave(" = -ENOMEM");
574 return -ENOMEM;
575}
576
577/*
David Howells5a429762016-09-06 22:19:51 +0100578 * Verify the security on a received packet or subpacket (if part of a
579 * jumbo packet).
David Howells17926a72007-04-26 15:48:28 -0700580 */
David Howells5a429762016-09-06 22:19:51 +0100581static int rxkad_verify_packet(struct rxrpc_call *call, struct sk_buff *skb,
David Howells248f2192016-09-08 11:10:12 +0100582 unsigned int offset, unsigned int len,
David Howells5a429762016-09-06 22:19:51 +0100583 rxrpc_seq_t seq, u16 expected_cksum)
David Howells17926a72007-04-26 15:48:28 -0700584{
David Howells1db88c52019-07-30 15:56:57 +0100585 struct skcipher_request *req;
David Howells17926a72007-04-26 15:48:28 -0700586 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700587 struct scatterlist sg;
David Howellsfb46f6e2017-04-06 10:12:00 +0100588 bool aborted;
David Howells0d12f8a2016-03-04 15:53:46 +0000589 u16 cksum;
590 u32 x, y;
David Howells17926a72007-04-26 15:48:28 -0700591
592 _enter("{%d{%x}},{#%u}",
David Howells5a429762016-09-06 22:19:51 +0100593 call->debug_id, key_serial(call->conn->params.key), seq);
David Howells17926a72007-04-26 15:48:28 -0700594
595 if (!call->conn->cipher)
596 return 0;
597
David Howells1db88c52019-07-30 15:56:57 +0100598 req = rxkad_get_call_crypto(call);
599 if (!req)
600 return -ENOMEM;
601
David Howells17926a72007-04-26 15:48:28 -0700602 /* continue encrypting from where we left off */
603 memcpy(&iv, call->conn->csum_iv.x, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700604
605 /* validate the security checksum */
David Howells01a90a42016-08-23 15:27:24 +0100606 x = (call->cid & RXRPC_CHANNELMASK) << (32 - RXRPC_CIDSHIFT);
David Howells5a429762016-09-06 22:19:51 +0100607 x |= seq & 0x3fffffff;
Herbert Xua2636292016-06-26 14:55:24 -0700608 call->crypto_buf[0] = htonl(call->call_id);
609 call->crypto_buf[1] = htonl(x);
David Howells17926a72007-04-26 15:48:28 -0700610
Herbert Xua2636292016-06-26 14:55:24 -0700611 sg_init_one(&sg, call->crypto_buf, 8);
Kees Cook69d826f2018-09-18 19:10:47 -0700612 skcipher_request_set_sync_tfm(req, call->conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800613 skcipher_request_set_callback(req, 0, NULL, NULL);
Herbert Xua2636292016-06-26 14:55:24 -0700614 skcipher_request_set_crypt(req, &sg, &sg, 8, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800615 crypto_skcipher_encrypt(req);
616 skcipher_request_zero(req);
David Howells17926a72007-04-26 15:48:28 -0700617
Herbert Xua2636292016-06-26 14:55:24 -0700618 y = ntohl(call->crypto_buf[1]);
David Howells0d12f8a2016-03-04 15:53:46 +0000619 cksum = (y >> 16) & 0xffff;
620 if (cksum == 0)
621 cksum = 1; /* zero checksums are not permitted */
David Howells17926a72007-04-26 15:48:28 -0700622
David Howells5a429762016-09-06 22:19:51 +0100623 if (cksum != expected_cksum) {
David Howellsfb46f6e2017-04-06 10:12:00 +0100624 aborted = rxrpc_abort_eproto(call, skb, "rxkad_csum", "VCK",
625 RXKADSEALEDINCON);
626 goto protocol_error;
David Howells17926a72007-04-26 15:48:28 -0700627 }
628
David Howells19ffa012016-04-04 14:00:36 +0100629 switch (call->conn->params.security_level) {
David Howells17926a72007-04-26 15:48:28 -0700630 case RXRPC_SECURITY_PLAIN:
David Howells5a429762016-09-06 22:19:51 +0100631 return 0;
David Howells17926a72007-04-26 15:48:28 -0700632 case RXRPC_SECURITY_AUTH:
Kees Cook54424d32018-08-03 10:15:25 +0100633 return rxkad_verify_packet_1(call, skb, offset, len, seq, req);
David Howells17926a72007-04-26 15:48:28 -0700634 case RXRPC_SECURITY_ENCRYPT:
Kees Cook54424d32018-08-03 10:15:25 +0100635 return rxkad_verify_packet_2(call, skb, offset, len, seq, req);
David Howells17926a72007-04-26 15:48:28 -0700636 default:
David Howells5a429762016-09-06 22:19:51 +0100637 return -ENOANO;
David Howells17926a72007-04-26 15:48:28 -0700638 }
David Howellsfb46f6e2017-04-06 10:12:00 +0100639
640protocol_error:
641 if (aborted)
642 rxrpc_send_abort_packet(call);
643 return -EPROTO;
David Howells17926a72007-04-26 15:48:28 -0700644}
645
646/*
David Howells248f2192016-09-08 11:10:12 +0100647 * Locate the data contained in a packet that was partially encrypted.
648 */
649static void rxkad_locate_data_1(struct rxrpc_call *call, struct sk_buff *skb,
650 unsigned int *_offset, unsigned int *_len)
651{
652 struct rxkad_level1_hdr sechdr;
653
654 if (skb_copy_bits(skb, *_offset, &sechdr, sizeof(sechdr)) < 0)
655 BUG();
656 *_offset += sizeof(sechdr);
657 *_len = ntohl(sechdr.data_size) & 0xffff;
658}
659
660/*
661 * Locate the data contained in a packet that was completely encrypted.
662 */
663static void rxkad_locate_data_2(struct rxrpc_call *call, struct sk_buff *skb,
664 unsigned int *_offset, unsigned int *_len)
665{
666 struct rxkad_level2_hdr sechdr;
667
668 if (skb_copy_bits(skb, *_offset, &sechdr, sizeof(sechdr)) < 0)
669 BUG();
670 *_offset += sizeof(sechdr);
671 *_len = ntohl(sechdr.data_size) & 0xffff;
672}
673
674/*
675 * Locate the data contained in an already decrypted packet.
676 */
677static void rxkad_locate_data(struct rxrpc_call *call, struct sk_buff *skb,
678 unsigned int *_offset, unsigned int *_len)
679{
680 switch (call->conn->params.security_level) {
681 case RXRPC_SECURITY_AUTH:
682 rxkad_locate_data_1(call, skb, _offset, _len);
683 return;
684 case RXRPC_SECURITY_ENCRYPT:
685 rxkad_locate_data_2(call, skb, _offset, _len);
686 return;
687 default:
688 return;
689 }
690}
691
692/*
David Howells17926a72007-04-26 15:48:28 -0700693 * issue a challenge
694 */
695static int rxkad_issue_challenge(struct rxrpc_connection *conn)
696{
697 struct rxkad_challenge challenge;
David Howells0d12f8a2016-03-04 15:53:46 +0000698 struct rxrpc_wire_header whdr;
David Howells17926a72007-04-26 15:48:28 -0700699 struct msghdr msg;
700 struct kvec iov[2];
701 size_t len;
David Howells0d12f8a2016-03-04 15:53:46 +0000702 u32 serial;
David Howells17926a72007-04-26 15:48:28 -0700703 int ret;
704
David Howellsec832bd2020-09-16 08:00:44 +0100705 _enter("{%d}", conn->debug_id);
David Howells17926a72007-04-26 15:48:28 -0700706
707 get_random_bytes(&conn->security_nonce, sizeof(conn->security_nonce));
708
709 challenge.version = htonl(2);
710 challenge.nonce = htonl(conn->security_nonce);
711 challenge.min_level = htonl(0);
712 challenge.__padding = 0;
713
David Howells7b674e32017-08-29 10:18:37 +0100714 msg.msg_name = &conn->params.peer->srx.transport;
715 msg.msg_namelen = conn->params.peer->srx.transport_len;
David Howells17926a72007-04-26 15:48:28 -0700716 msg.msg_control = NULL;
717 msg.msg_controllen = 0;
718 msg.msg_flags = 0;
719
David Howells19ffa012016-04-04 14:00:36 +0100720 whdr.epoch = htonl(conn->proto.epoch);
721 whdr.cid = htonl(conn->proto.cid);
David Howells0d12f8a2016-03-04 15:53:46 +0000722 whdr.callNumber = 0;
723 whdr.seq = 0;
724 whdr.type = RXRPC_PACKET_TYPE_CHALLENGE;
725 whdr.flags = conn->out_clientflag;
726 whdr.userStatus = 0;
727 whdr.securityIndex = conn->security_ix;
728 whdr._rsvd = 0;
David Howells68d6d1a2017-06-05 14:30:49 +0100729 whdr.serviceId = htons(conn->service_id);
David Howells17926a72007-04-26 15:48:28 -0700730
David Howells0d12f8a2016-03-04 15:53:46 +0000731 iov[0].iov_base = &whdr;
732 iov[0].iov_len = sizeof(whdr);
David Howells17926a72007-04-26 15:48:28 -0700733 iov[1].iov_base = &challenge;
734 iov[1].iov_len = sizeof(challenge);
735
736 len = iov[0].iov_len + iov[1].iov_len;
737
David Howells0d12f8a2016-03-04 15:53:46 +0000738 serial = atomic_inc_return(&conn->serial);
739 whdr.serial = htonl(serial);
740 _proto("Tx CHALLENGE %%%u", serial);
David Howells17926a72007-04-26 15:48:28 -0700741
David Howells85f32272016-04-04 14:00:36 +0100742 ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 2, len);
David Howells17926a72007-04-26 15:48:28 -0700743 if (ret < 0) {
David Howells6b47fe12018-05-10 23:26:01 +0100744 trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
David Howells4764c0d2018-07-23 17:18:37 +0100745 rxrpc_tx_point_rxkad_challenge);
David Howells17926a72007-04-26 15:48:28 -0700746 return -EAGAIN;
747 }
748
David Howells330bdcf2018-08-08 11:30:02 +0100749 conn->params.peer->last_tx_at = ktime_get_seconds();
David Howells4764c0d2018-07-23 17:18:37 +0100750 trace_rxrpc_tx_packet(conn->debug_id, &whdr,
751 rxrpc_tx_point_rxkad_challenge);
David Howells17926a72007-04-26 15:48:28 -0700752 _leave(" = 0");
753 return 0;
754}
755
756/*
757 * send a Kerberos security response
758 */
759static int rxkad_send_response(struct rxrpc_connection *conn,
David Howells0d12f8a2016-03-04 15:53:46 +0000760 struct rxrpc_host_header *hdr,
David Howells17926a72007-04-26 15:48:28 -0700761 struct rxkad_response *resp,
762 const struct rxkad_key *s2)
763{
David Howells0d12f8a2016-03-04 15:53:46 +0000764 struct rxrpc_wire_header whdr;
David Howells17926a72007-04-26 15:48:28 -0700765 struct msghdr msg;
766 struct kvec iov[3];
767 size_t len;
David Howells0d12f8a2016-03-04 15:53:46 +0000768 u32 serial;
David Howells17926a72007-04-26 15:48:28 -0700769 int ret;
770
771 _enter("");
772
David Howells7b674e32017-08-29 10:18:37 +0100773 msg.msg_name = &conn->params.peer->srx.transport;
774 msg.msg_namelen = conn->params.peer->srx.transport_len;
David Howells17926a72007-04-26 15:48:28 -0700775 msg.msg_control = NULL;
776 msg.msg_controllen = 0;
777 msg.msg_flags = 0;
778
David Howells0d12f8a2016-03-04 15:53:46 +0000779 memset(&whdr, 0, sizeof(whdr));
780 whdr.epoch = htonl(hdr->epoch);
781 whdr.cid = htonl(hdr->cid);
782 whdr.type = RXRPC_PACKET_TYPE_RESPONSE;
783 whdr.flags = conn->out_clientflag;
784 whdr.securityIndex = hdr->securityIndex;
785 whdr.serviceId = htons(hdr->serviceId);
David Howells17926a72007-04-26 15:48:28 -0700786
David Howells0d12f8a2016-03-04 15:53:46 +0000787 iov[0].iov_base = &whdr;
788 iov[0].iov_len = sizeof(whdr);
David Howells17926a72007-04-26 15:48:28 -0700789 iov[1].iov_base = resp;
790 iov[1].iov_len = sizeof(*resp);
David Howells0d12f8a2016-03-04 15:53:46 +0000791 iov[2].iov_base = (void *)s2->ticket;
David Howells17926a72007-04-26 15:48:28 -0700792 iov[2].iov_len = s2->ticket_len;
793
794 len = iov[0].iov_len + iov[1].iov_len + iov[2].iov_len;
795
David Howells0d12f8a2016-03-04 15:53:46 +0000796 serial = atomic_inc_return(&conn->serial);
797 whdr.serial = htonl(serial);
798 _proto("Tx RESPONSE %%%u", serial);
David Howells17926a72007-04-26 15:48:28 -0700799
David Howells85f32272016-04-04 14:00:36 +0100800 ret = kernel_sendmsg(conn->params.local->socket, &msg, iov, 3, len);
David Howells17926a72007-04-26 15:48:28 -0700801 if (ret < 0) {
David Howells6b47fe12018-05-10 23:26:01 +0100802 trace_rxrpc_tx_fail(conn->debug_id, serial, ret,
David Howells4764c0d2018-07-23 17:18:37 +0100803 rxrpc_tx_point_rxkad_response);
David Howells17926a72007-04-26 15:48:28 -0700804 return -EAGAIN;
805 }
806
David Howells330bdcf2018-08-08 11:30:02 +0100807 conn->params.peer->last_tx_at = ktime_get_seconds();
David Howells17926a72007-04-26 15:48:28 -0700808 _leave(" = 0");
809 return 0;
810}
811
812/*
813 * calculate the response checksum
814 */
815static void rxkad_calc_response_checksum(struct rxkad_response *response)
816{
817 u32 csum = 1000003;
818 int loop;
819 u8 *p = (u8 *) response;
820
821 for (loop = sizeof(*response); loop > 0; loop--)
822 csum = csum * 0x10204081 + *p++;
823
824 response->encrypted.checksum = htonl(csum);
825}
826
827/*
David Howells17926a72007-04-26 15:48:28 -0700828 * encrypt the response packet
829 */
David Howells1db88c52019-07-30 15:56:57 +0100830static int rxkad_encrypt_response(struct rxrpc_connection *conn,
831 struct rxkad_response *resp,
832 const struct rxkad_key *s2)
David Howells17926a72007-04-26 15:48:28 -0700833{
David Howells1db88c52019-07-30 15:56:57 +0100834 struct skcipher_request *req;
David Howells17926a72007-04-26 15:48:28 -0700835 struct rxrpc_crypt iv;
Herbert Xua2636292016-06-26 14:55:24 -0700836 struct scatterlist sg[1];
David Howells17926a72007-04-26 15:48:28 -0700837
David Howells1db88c52019-07-30 15:56:57 +0100838 req = skcipher_request_alloc(&conn->cipher->base, GFP_NOFS);
839 if (!req)
840 return -ENOMEM;
841
David Howells17926a72007-04-26 15:48:28 -0700842 /* continue encrypting from where we left off */
843 memcpy(&iv, s2->session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700844
Herbert Xua2636292016-06-26 14:55:24 -0700845 sg_init_table(sg, 1);
846 sg_set_buf(sg, &resp->encrypted, sizeof(resp->encrypted));
Kees Cook69d826f2018-09-18 19:10:47 -0700847 skcipher_request_set_sync_tfm(req, conn->cipher);
Herbert Xu1afe5932016-01-24 21:19:01 +0800848 skcipher_request_set_callback(req, 0, NULL, NULL);
849 skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800850 crypto_skcipher_encrypt(req);
David Howells1db88c52019-07-30 15:56:57 +0100851 skcipher_request_free(req);
852 return 0;
David Howells17926a72007-04-26 15:48:28 -0700853}
854
855/*
856 * respond to a challenge packet
857 */
858static int rxkad_respond_to_challenge(struct rxrpc_connection *conn,
859 struct sk_buff *skb,
860 u32 *_abort_code)
861{
David Howells33941282009-09-14 01:17:35 +0000862 const struct rxrpc_key_token *token;
David Howells17926a72007-04-26 15:48:28 -0700863 struct rxkad_challenge challenge;
David Howells8c2f8262018-02-08 15:59:07 +0000864 struct rxkad_response *resp;
David Howells248f2192016-09-08 11:10:12 +0100865 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
David Howellsfb46f6e2017-04-06 10:12:00 +0100866 const char *eproto;
David Howells17926a72007-04-26 15:48:28 -0700867 u32 version, nonce, min_level, abort_code;
868 int ret;
869
David Howells19ffa012016-04-04 14:00:36 +0100870 _enter("{%d,%x}", conn->debug_id, key_serial(conn->params.key));
David Howells17926a72007-04-26 15:48:28 -0700871
David Howellsfb46f6e2017-04-06 10:12:00 +0100872 eproto = tracepoint_string("chall_no_key");
David Howellsef686222017-04-06 10:11:59 +0100873 abort_code = RX_PROTOCOL_ERROR;
874 if (!conn->params.key)
875 goto protocol_error;
David Howells17926a72007-04-26 15:48:28 -0700876
David Howellsef686222017-04-06 10:11:59 +0100877 abort_code = RXKADEXPIRED;
David Howells19ffa012016-04-04 14:00:36 +0100878 ret = key_validate(conn->params.key);
David Howellsef686222017-04-06 10:11:59 +0100879 if (ret < 0)
880 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700881
David Howellsfb46f6e2017-04-06 10:12:00 +0100882 eproto = tracepoint_string("chall_short");
David Howells17926a72007-04-26 15:48:28 -0700883 abort_code = RXKADPACKETSHORT;
David Howells775e5b72016-09-30 13:26:03 +0100884 if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
885 &challenge, sizeof(challenge)) < 0)
David Howells17926a72007-04-26 15:48:28 -0700886 goto protocol_error;
887
888 version = ntohl(challenge.version);
889 nonce = ntohl(challenge.nonce);
890 min_level = ntohl(challenge.min_level);
891
892 _proto("Rx CHALLENGE %%%u { v=%u n=%u ml=%u }",
David Howells0d12f8a2016-03-04 15:53:46 +0000893 sp->hdr.serial, version, nonce, min_level);
David Howells17926a72007-04-26 15:48:28 -0700894
David Howellsfb46f6e2017-04-06 10:12:00 +0100895 eproto = tracepoint_string("chall_ver");
David Howells17926a72007-04-26 15:48:28 -0700896 abort_code = RXKADINCONSISTENCY;
897 if (version != RXKAD_VERSION)
898 goto protocol_error;
899
900 abort_code = RXKADLEVELFAIL;
David Howellsef686222017-04-06 10:11:59 +0100901 ret = -EACCES;
David Howells19ffa012016-04-04 14:00:36 +0100902 if (conn->params.security_level < min_level)
David Howellsef686222017-04-06 10:11:59 +0100903 goto other_error;
David Howells17926a72007-04-26 15:48:28 -0700904
David Howells19ffa012016-04-04 14:00:36 +0100905 token = conn->params.key->payload.data[0];
David Howells17926a72007-04-26 15:48:28 -0700906
907 /* build the response packet */
David Howells8c2f8262018-02-08 15:59:07 +0000908 resp = kzalloc(sizeof(struct rxkad_response), GFP_NOFS);
909 if (!resp)
910 return -ENOMEM;
David Howells17926a72007-04-26 15:48:28 -0700911
David Howells8c2f8262018-02-08 15:59:07 +0000912 resp->version = htonl(RXKAD_VERSION);
913 resp->encrypted.epoch = htonl(conn->proto.epoch);
914 resp->encrypted.cid = htonl(conn->proto.cid);
915 resp->encrypted.securityIndex = htonl(conn->security_ix);
916 resp->encrypted.inc_nonce = htonl(nonce + 1);
917 resp->encrypted.level = htonl(conn->params.security_level);
918 resp->kvno = htonl(token->kad->kvno);
919 resp->ticket_len = htonl(token->kad->ticket_len);
920 resp->encrypted.call_id[0] = htonl(conn->channels[0].call_counter);
921 resp->encrypted.call_id[1] = htonl(conn->channels[1].call_counter);
922 resp->encrypted.call_id[2] = htonl(conn->channels[2].call_counter);
923 resp->encrypted.call_id[3] = htonl(conn->channels[3].call_counter);
David Howells17926a72007-04-26 15:48:28 -0700924
925 /* calculate the response checksum and then do the encryption */
David Howells8c2f8262018-02-08 15:59:07 +0000926 rxkad_calc_response_checksum(resp);
David Howells1db88c52019-07-30 15:56:57 +0100927 ret = rxkad_encrypt_response(conn, resp, token->kad);
928 if (ret == 0)
929 ret = rxkad_send_response(conn, &sp->hdr, resp, token->kad);
David Howells8c2f8262018-02-08 15:59:07 +0000930 kfree(resp);
931 return ret;
David Howells17926a72007-04-26 15:48:28 -0700932
933protocol_error:
David Howellsfb46f6e2017-04-06 10:12:00 +0100934 trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
David Howellsef686222017-04-06 10:11:59 +0100935 ret = -EPROTO;
936other_error:
David Howells17926a72007-04-26 15:48:28 -0700937 *_abort_code = abort_code;
David Howellsef686222017-04-06 10:11:59 +0100938 return ret;
David Howells17926a72007-04-26 15:48:28 -0700939}
940
941/*
942 * decrypt the kerberos IV ticket in the response
943 */
944static int rxkad_decrypt_ticket(struct rxrpc_connection *conn,
David Howellsec832bd2020-09-16 08:00:44 +0100945 struct key *server_key,
David Howellsfb46f6e2017-04-06 10:12:00 +0100946 struct sk_buff *skb,
David Howells17926a72007-04-26 15:48:28 -0700947 void *ticket, size_t ticket_len,
948 struct rxrpc_crypt *_session_key,
Baolin Wang10674a02017-08-29 10:15:40 +0100949 time64_t *_expiry,
David Howells17926a72007-04-26 15:48:28 -0700950 u32 *_abort_code)
951{
Herbert Xu1afe5932016-01-24 21:19:01 +0800952 struct skcipher_request *req;
David Howellsfb46f6e2017-04-06 10:12:00 +0100953 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
David Howells17926a72007-04-26 15:48:28 -0700954 struct rxrpc_crypt iv, key;
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700955 struct scatterlist sg[1];
David Howells17926a72007-04-26 15:48:28 -0700956 struct in_addr addr;
Eric Dumazet95c96172012-04-15 05:58:06 +0000957 unsigned int life;
David Howellsfb46f6e2017-04-06 10:12:00 +0100958 const char *eproto;
Baolin Wang10674a02017-08-29 10:15:40 +0100959 time64_t issue, now;
David Howells17926a72007-04-26 15:48:28 -0700960 bool little_endian;
961 int ret;
David Howellsfb46f6e2017-04-06 10:12:00 +0100962 u32 abort_code;
David Howells17926a72007-04-26 15:48:28 -0700963 u8 *p, *q, *name, *end;
964
David Howellsec832bd2020-09-16 08:00:44 +0100965 _enter("{%d},{%x}", conn->debug_id, key_serial(server_key));
David Howells17926a72007-04-26 15:48:28 -0700966
967 *_expiry = 0;
968
David Howellsec832bd2020-09-16 08:00:44 +0100969 ASSERT(server_key->payload.data[0] != NULL);
David Howells17926a72007-04-26 15:48:28 -0700970 ASSERTCMP((unsigned long) ticket & 7UL, ==, 0);
971
David Howellsec832bd2020-09-16 08:00:44 +0100972 memcpy(&iv, &server_key->payload.data[2], sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -0700973
David Howellsef686222017-04-06 10:11:59 +0100974 ret = -ENOMEM;
David Howellsec832bd2020-09-16 08:00:44 +0100975 req = skcipher_request_alloc(server_key->payload.data[0], GFP_NOFS);
David Howellsef686222017-04-06 10:11:59 +0100976 if (!req)
977 goto temporary_error;
David Howells17926a72007-04-26 15:48:28 -0700978
Herbert Xu68e3f5d2007-10-27 00:52:07 -0700979 sg_init_one(&sg[0], ticket, ticket_len);
Herbert Xu1afe5932016-01-24 21:19:01 +0800980 skcipher_request_set_callback(req, 0, NULL, NULL);
981 skcipher_request_set_crypt(req, sg, sg, ticket_len, iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +0800982 crypto_skcipher_decrypt(req);
983 skcipher_request_free(req);
David Howells17926a72007-04-26 15:48:28 -0700984
985 p = ticket;
986 end = p + ticket_len;
987
David Howellsfb46f6e2017-04-06 10:12:00 +0100988#define Z(field) \
David Howells17926a72007-04-26 15:48:28 -0700989 ({ \
990 u8 *__str = p; \
David Howellsfb46f6e2017-04-06 10:12:00 +0100991 eproto = tracepoint_string("rxkad_bad_"#field); \
David Howells17926a72007-04-26 15:48:28 -0700992 q = memchr(p, 0, end - p); \
David Howellsfb46f6e2017-04-06 10:12:00 +0100993 if (!q || q - p > (field##_SZ)) \
David Howells17926a72007-04-26 15:48:28 -0700994 goto bad_ticket; \
995 for (; p < q; p++) \
996 if (!isprint(*p)) \
997 goto bad_ticket; \
998 p++; \
999 __str; \
1000 })
1001
1002 /* extract the ticket flags */
1003 _debug("KIV FLAGS: %x", *p);
1004 little_endian = *p & 1;
1005 p++;
1006
1007 /* extract the authentication name */
David Howellsfb46f6e2017-04-06 10:12:00 +01001008 name = Z(ANAME);
David Howells17926a72007-04-26 15:48:28 -07001009 _debug("KIV ANAME: %s", name);
1010
1011 /* extract the principal's instance */
David Howellsfb46f6e2017-04-06 10:12:00 +01001012 name = Z(INST);
David Howells17926a72007-04-26 15:48:28 -07001013 _debug("KIV INST : %s", name);
1014
1015 /* extract the principal's authentication domain */
David Howellsfb46f6e2017-04-06 10:12:00 +01001016 name = Z(REALM);
David Howells17926a72007-04-26 15:48:28 -07001017 _debug("KIV REALM: %s", name);
1018
David Howellsfb46f6e2017-04-06 10:12:00 +01001019 eproto = tracepoint_string("rxkad_bad_len");
David Howells17926a72007-04-26 15:48:28 -07001020 if (end - p < 4 + 8 + 4 + 2)
1021 goto bad_ticket;
1022
1023 /* get the IPv4 address of the entity that requested the ticket */
1024 memcpy(&addr, p, sizeof(addr));
1025 p += 4;
Harvey Harrison21454aa2008-10-31 00:54:56 -07001026 _debug("KIV ADDR : %pI4", &addr);
David Howells17926a72007-04-26 15:48:28 -07001027
1028 /* get the session key from the ticket */
1029 memcpy(&key, p, sizeof(key));
1030 p += 8;
1031 _debug("KIV KEY : %08x %08x", ntohl(key.n[0]), ntohl(key.n[1]));
1032 memcpy(_session_key, &key, sizeof(key));
1033
1034 /* get the ticket's lifetime */
1035 life = *p++ * 5 * 60;
1036 _debug("KIV LIFE : %u", life);
1037
1038 /* get the issue time of the ticket */
1039 if (little_endian) {
1040 __le32 stamp;
1041 memcpy(&stamp, p, 4);
Baolin Wang10674a02017-08-29 10:15:40 +01001042 issue = rxrpc_u32_to_time64(le32_to_cpu(stamp));
David Howells17926a72007-04-26 15:48:28 -07001043 } else {
1044 __be32 stamp;
1045 memcpy(&stamp, p, 4);
Baolin Wang10674a02017-08-29 10:15:40 +01001046 issue = rxrpc_u32_to_time64(be32_to_cpu(stamp));
David Howells17926a72007-04-26 15:48:28 -07001047 }
1048 p += 4;
Baolin Wang10674a02017-08-29 10:15:40 +01001049 now = ktime_get_real_seconds();
1050 _debug("KIV ISSUE: %llx [%llx]", issue, now);
David Howells17926a72007-04-26 15:48:28 -07001051
1052 /* check the ticket is in date */
1053 if (issue > now) {
David Howellsfb46f6e2017-04-06 10:12:00 +01001054 abort_code = RXKADNOAUTH;
David Howells17926a72007-04-26 15:48:28 -07001055 ret = -EKEYREJECTED;
David Howellsef686222017-04-06 10:11:59 +01001056 goto other_error;
David Howells17926a72007-04-26 15:48:28 -07001057 }
1058
1059 if (issue < now - life) {
David Howellsfb46f6e2017-04-06 10:12:00 +01001060 abort_code = RXKADEXPIRED;
David Howells17926a72007-04-26 15:48:28 -07001061 ret = -EKEYEXPIRED;
David Howellsef686222017-04-06 10:11:59 +01001062 goto other_error;
David Howells17926a72007-04-26 15:48:28 -07001063 }
1064
1065 *_expiry = issue + life;
1066
1067 /* get the service name */
David Howellsfb46f6e2017-04-06 10:12:00 +01001068 name = Z(SNAME);
David Howells17926a72007-04-26 15:48:28 -07001069 _debug("KIV SNAME: %s", name);
1070
1071 /* get the service instance name */
David Howellsfb46f6e2017-04-06 10:12:00 +01001072 name = Z(INST);
David Howells17926a72007-04-26 15:48:28 -07001073 _debug("KIV SINST: %s", name);
David Howellsef686222017-04-06 10:11:59 +01001074 return 0;
David Howells17926a72007-04-26 15:48:28 -07001075
1076bad_ticket:
David Howellsfb46f6e2017-04-06 10:12:00 +01001077 trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
1078 abort_code = RXKADBADTICKET;
David Howellsef686222017-04-06 10:11:59 +01001079 ret = -EPROTO;
1080other_error:
David Howellsfb46f6e2017-04-06 10:12:00 +01001081 *_abort_code = abort_code;
David Howellsef686222017-04-06 10:11:59 +01001082 return ret;
1083temporary_error:
1084 return ret;
David Howells17926a72007-04-26 15:48:28 -07001085}
1086
1087/*
1088 * decrypt the response packet
1089 */
1090static void rxkad_decrypt_response(struct rxrpc_connection *conn,
1091 struct rxkad_response *resp,
1092 const struct rxrpc_crypt *session_key)
1093{
David Howells1db88c52019-07-30 15:56:57 +01001094 struct skcipher_request *req = rxkad_ci_req;
Herbert Xua2636292016-06-26 14:55:24 -07001095 struct scatterlist sg[1];
David Howells17926a72007-04-26 15:48:28 -07001096 struct rxrpc_crypt iv;
1097
1098 _enter(",,%08x%08x",
1099 ntohl(session_key->n[0]), ntohl(session_key->n[1]));
1100
David Howells17926a72007-04-26 15:48:28 -07001101 mutex_lock(&rxkad_ci_mutex);
Kees Cook69d826f2018-09-18 19:10:47 -07001102 if (crypto_sync_skcipher_setkey(rxkad_ci, session_key->x,
David Howells1db88c52019-07-30 15:56:57 +01001103 sizeof(*session_key)) < 0)
David Howells17926a72007-04-26 15:48:28 -07001104 BUG();
1105
1106 memcpy(&iv, session_key, sizeof(iv));
David Howells17926a72007-04-26 15:48:28 -07001107
Herbert Xua2636292016-06-26 14:55:24 -07001108 sg_init_table(sg, 1);
1109 sg_set_buf(sg, &resp->encrypted, sizeof(resp->encrypted));
Kees Cook69d826f2018-09-18 19:10:47 -07001110 skcipher_request_set_sync_tfm(req, rxkad_ci);
Herbert Xu1afe5932016-01-24 21:19:01 +08001111 skcipher_request_set_callback(req, 0, NULL, NULL);
1112 skcipher_request_set_crypt(req, sg, sg, sizeof(resp->encrypted), iv.x);
Herbert Xu1afe5932016-01-24 21:19:01 +08001113 crypto_skcipher_decrypt(req);
1114 skcipher_request_zero(req);
1115
David Howells17926a72007-04-26 15:48:28 -07001116 mutex_unlock(&rxkad_ci_mutex);
1117
1118 _leave("");
1119}
1120
1121/*
1122 * verify a response
1123 */
1124static int rxkad_verify_response(struct rxrpc_connection *conn,
1125 struct sk_buff *skb,
1126 u32 *_abort_code)
1127{
David Howells8c2f8262018-02-08 15:59:07 +00001128 struct rxkad_response *response;
David Howells248f2192016-09-08 11:10:12 +01001129 struct rxrpc_skb_priv *sp = rxrpc_skb(skb);
David Howells17926a72007-04-26 15:48:28 -07001130 struct rxrpc_crypt session_key;
David Howellsec832bd2020-09-16 08:00:44 +01001131 struct key *server_key;
David Howellsfb46f6e2017-04-06 10:12:00 +01001132 const char *eproto;
Baolin Wang10674a02017-08-29 10:15:40 +01001133 time64_t expiry;
David Howells17926a72007-04-26 15:48:28 -07001134 void *ticket;
Al Viro91e916c2008-03-29 03:08:38 +00001135 u32 abort_code, version, kvno, ticket_len, level;
1136 __be32 csum;
David Howellsa1399f82016-06-27 14:39:44 +01001137 int ret, i;
David Howells17926a72007-04-26 15:48:28 -07001138
David Howellsec832bd2020-09-16 08:00:44 +01001139 _enter("{%d}", conn->debug_id);
1140
1141 server_key = rxrpc_look_up_server_security(conn, skb, 0, 0);
1142 if (IS_ERR(server_key)) {
1143 switch (PTR_ERR(server_key)) {
1144 case -ENOKEY:
1145 abort_code = RXKADUNKNOWNKEY;
1146 break;
1147 case -EKEYEXPIRED:
1148 abort_code = RXKADEXPIRED;
1149 break;
1150 default:
1151 abort_code = RXKADNOAUTH;
1152 break;
1153 }
1154 trace_rxrpc_abort(0, "SVK",
1155 sp->hdr.cid, sp->hdr.callNumber, sp->hdr.seq,
1156 abort_code, PTR_ERR(server_key));
1157 *_abort_code = abort_code;
1158 return -EPROTO;
1159 }
David Howells17926a72007-04-26 15:48:28 -07001160
David Howells8c2f8262018-02-08 15:59:07 +00001161 ret = -ENOMEM;
1162 response = kzalloc(sizeof(struct rxkad_response), GFP_NOFS);
1163 if (!response)
1164 goto temporary_error;
1165
David Howellsfb46f6e2017-04-06 10:12:00 +01001166 eproto = tracepoint_string("rxkad_rsp_short");
David Howells17926a72007-04-26 15:48:28 -07001167 abort_code = RXKADPACKETSHORT;
David Howells775e5b72016-09-30 13:26:03 +01001168 if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
David Howells8c2f8262018-02-08 15:59:07 +00001169 response, sizeof(*response)) < 0)
David Howells17926a72007-04-26 15:48:28 -07001170 goto protocol_error;
David Howells8c2f8262018-02-08 15:59:07 +00001171 if (!pskb_pull(skb, sizeof(*response)))
David Howells17926a72007-04-26 15:48:28 -07001172 BUG();
1173
David Howells8c2f8262018-02-08 15:59:07 +00001174 version = ntohl(response->version);
1175 ticket_len = ntohl(response->ticket_len);
1176 kvno = ntohl(response->kvno);
David Howells17926a72007-04-26 15:48:28 -07001177 _proto("Rx RESPONSE %%%u { v=%u kv=%u tl=%u }",
David Howells0d12f8a2016-03-04 15:53:46 +00001178 sp->hdr.serial, version, kvno, ticket_len);
David Howells17926a72007-04-26 15:48:28 -07001179
David Howellsfb46f6e2017-04-06 10:12:00 +01001180 eproto = tracepoint_string("rxkad_rsp_ver");
David Howells17926a72007-04-26 15:48:28 -07001181 abort_code = RXKADINCONSISTENCY;
1182 if (version != RXKAD_VERSION)
David Howells4aa9cb32007-12-07 04:31:47 -08001183 goto protocol_error;
David Howells17926a72007-04-26 15:48:28 -07001184
David Howellsfb46f6e2017-04-06 10:12:00 +01001185 eproto = tracepoint_string("rxkad_rsp_tktlen");
David Howells17926a72007-04-26 15:48:28 -07001186 abort_code = RXKADTICKETLEN;
1187 if (ticket_len < 4 || ticket_len > MAXKRB5TICKETLEN)
1188 goto protocol_error;
1189
David Howellsfb46f6e2017-04-06 10:12:00 +01001190 eproto = tracepoint_string("rxkad_rsp_unkkey");
David Howells17926a72007-04-26 15:48:28 -07001191 abort_code = RXKADUNKNOWNKEY;
1192 if (kvno >= RXKAD_TKT_TYPE_KERBEROS_V5)
1193 goto protocol_error;
1194
1195 /* extract the kerberos ticket and decrypt and decode it */
David Howellsef686222017-04-06 10:11:59 +01001196 ret = -ENOMEM;
David Howells17926a72007-04-26 15:48:28 -07001197 ticket = kmalloc(ticket_len, GFP_NOFS);
1198 if (!ticket)
Dinghao Liub43c75a2020-08-27 16:55:46 +01001199 goto temporary_error_free_resp;
David Howells17926a72007-04-26 15:48:28 -07001200
David Howellsfb46f6e2017-04-06 10:12:00 +01001201 eproto = tracepoint_string("rxkad_tkt_short");
David Howells17926a72007-04-26 15:48:28 -07001202 abort_code = RXKADPACKETSHORT;
David Howells775e5b72016-09-30 13:26:03 +01001203 if (skb_copy_bits(skb, sizeof(struct rxrpc_wire_header),
1204 ticket, ticket_len) < 0)
David Howells17926a72007-04-26 15:48:28 -07001205 goto protocol_error_free;
1206
David Howellsec832bd2020-09-16 08:00:44 +01001207 ret = rxkad_decrypt_ticket(conn, server_key, skb, ticket, ticket_len,
1208 &session_key, &expiry, _abort_code);
David Howellsef686222017-04-06 10:11:59 +01001209 if (ret < 0)
Qiushi Wuf45d01f2020-05-22 13:45:18 -05001210 goto temporary_error_free_ticket;
David Howells17926a72007-04-26 15:48:28 -07001211
1212 /* use the session key from inside the ticket to decrypt the
1213 * response */
David Howells8c2f8262018-02-08 15:59:07 +00001214 rxkad_decrypt_response(conn, response, &session_key);
David Howells17926a72007-04-26 15:48:28 -07001215
David Howellsfb46f6e2017-04-06 10:12:00 +01001216 eproto = tracepoint_string("rxkad_rsp_param");
David Howells17926a72007-04-26 15:48:28 -07001217 abort_code = RXKADSEALEDINCON;
David Howells8c2f8262018-02-08 15:59:07 +00001218 if (ntohl(response->encrypted.epoch) != conn->proto.epoch)
David Howells17926a72007-04-26 15:48:28 -07001219 goto protocol_error_free;
David Howells8c2f8262018-02-08 15:59:07 +00001220 if (ntohl(response->encrypted.cid) != conn->proto.cid)
David Howells17926a72007-04-26 15:48:28 -07001221 goto protocol_error_free;
David Howells8c2f8262018-02-08 15:59:07 +00001222 if (ntohl(response->encrypted.securityIndex) != conn->security_ix)
David Howells17926a72007-04-26 15:48:28 -07001223 goto protocol_error_free;
David Howells8c2f8262018-02-08 15:59:07 +00001224 csum = response->encrypted.checksum;
1225 response->encrypted.checksum = 0;
1226 rxkad_calc_response_checksum(response);
David Howellsfb46f6e2017-04-06 10:12:00 +01001227 eproto = tracepoint_string("rxkad_rsp_csum");
David Howells8c2f8262018-02-08 15:59:07 +00001228 if (response->encrypted.checksum != csum)
David Howells17926a72007-04-26 15:48:28 -07001229 goto protocol_error_free;
1230
David Howells245500d2020-07-01 11:15:32 +01001231 spin_lock(&conn->bundle->channel_lock);
David Howellsa1399f82016-06-27 14:39:44 +01001232 for (i = 0; i < RXRPC_MAXCALLS; i++) {
1233 struct rxrpc_call *call;
David Howells8c2f8262018-02-08 15:59:07 +00001234 u32 call_id = ntohl(response->encrypted.call_id[i]);
David Howellsa1399f82016-06-27 14:39:44 +01001235
David Howellsfb46f6e2017-04-06 10:12:00 +01001236 eproto = tracepoint_string("rxkad_rsp_callid");
David Howellsa1399f82016-06-27 14:39:44 +01001237 if (call_id > INT_MAX)
1238 goto protocol_error_unlock;
1239
David Howellsfb46f6e2017-04-06 10:12:00 +01001240 eproto = tracepoint_string("rxkad_rsp_callctr");
David Howellsa1399f82016-06-27 14:39:44 +01001241 if (call_id < conn->channels[i].call_counter)
1242 goto protocol_error_unlock;
David Howellsfb46f6e2017-04-06 10:12:00 +01001243
1244 eproto = tracepoint_string("rxkad_rsp_callst");
David Howellsa1399f82016-06-27 14:39:44 +01001245 if (call_id > conn->channels[i].call_counter) {
1246 call = rcu_dereference_protected(
1247 conn->channels[i].call,
David Howells245500d2020-07-01 11:15:32 +01001248 lockdep_is_held(&conn->bundle->channel_lock));
David Howellsa1399f82016-06-27 14:39:44 +01001249 if (call && call->state < RXRPC_CALL_COMPLETE)
1250 goto protocol_error_unlock;
1251 conn->channels[i].call_counter = call_id;
1252 }
1253 }
David Howells245500d2020-07-01 11:15:32 +01001254 spin_unlock(&conn->bundle->channel_lock);
David Howells17926a72007-04-26 15:48:28 -07001255
David Howellsfb46f6e2017-04-06 10:12:00 +01001256 eproto = tracepoint_string("rxkad_rsp_seq");
David Howells17926a72007-04-26 15:48:28 -07001257 abort_code = RXKADOUTOFSEQUENCE;
David Howells8c2f8262018-02-08 15:59:07 +00001258 if (ntohl(response->encrypted.inc_nonce) != conn->security_nonce + 1)
David Howells17926a72007-04-26 15:48:28 -07001259 goto protocol_error_free;
1260
David Howellsfb46f6e2017-04-06 10:12:00 +01001261 eproto = tracepoint_string("rxkad_rsp_level");
David Howells17926a72007-04-26 15:48:28 -07001262 abort_code = RXKADLEVELFAIL;
David Howells8c2f8262018-02-08 15:59:07 +00001263 level = ntohl(response->encrypted.level);
David Howells17926a72007-04-26 15:48:28 -07001264 if (level > RXRPC_SECURITY_ENCRYPT)
1265 goto protocol_error_free;
David Howells19ffa012016-04-04 14:00:36 +01001266 conn->params.security_level = level;
David Howells17926a72007-04-26 15:48:28 -07001267
1268 /* create a key to hold the security data and expiration time - after
1269 * this the connection security can be handled in exactly the same way
1270 * as for a client connection */
1271 ret = rxrpc_get_server_data_key(conn, &session_key, expiry, kvno);
David Howellsef686222017-04-06 10:11:59 +01001272 if (ret < 0)
David Howells8c2f8262018-02-08 15:59:07 +00001273 goto temporary_error_free_ticket;
David Howells17926a72007-04-26 15:48:28 -07001274
1275 kfree(ticket);
David Howells8c2f8262018-02-08 15:59:07 +00001276 kfree(response);
David Howells17926a72007-04-26 15:48:28 -07001277 _leave(" = 0");
1278 return 0;
1279
David Howellsa1399f82016-06-27 14:39:44 +01001280protocol_error_unlock:
David Howells245500d2020-07-01 11:15:32 +01001281 spin_unlock(&conn->bundle->channel_lock);
David Howells17926a72007-04-26 15:48:28 -07001282protocol_error_free:
1283 kfree(ticket);
1284protocol_error:
David Howells8c2f8262018-02-08 15:59:07 +00001285 kfree(response);
David Howellsfb46f6e2017-04-06 10:12:00 +01001286 trace_rxrpc_rx_eproto(NULL, sp->hdr.serial, eproto);
David Howellsec832bd2020-09-16 08:00:44 +01001287 key_put(server_key);
David Howells17926a72007-04-26 15:48:28 -07001288 *_abort_code = abort_code;
David Howells17926a72007-04-26 15:48:28 -07001289 return -EPROTO;
David Howellsef686222017-04-06 10:11:59 +01001290
David Howells8c2f8262018-02-08 15:59:07 +00001291temporary_error_free_ticket:
David Howellsef686222017-04-06 10:11:59 +01001292 kfree(ticket);
Dinghao Liub43c75a2020-08-27 16:55:46 +01001293temporary_error_free_resp:
David Howells8c2f8262018-02-08 15:59:07 +00001294 kfree(response);
David Howellsef686222017-04-06 10:11:59 +01001295temporary_error:
1296 /* Ignore the response packet if we got a temporary error such as
1297 * ENOMEM. We just want to send the challenge again. Note that we
1298 * also come out this way if the ticket decryption fails.
1299 */
David Howellsec832bd2020-09-16 08:00:44 +01001300 key_put(server_key);
David Howellsef686222017-04-06 10:11:59 +01001301 return ret;
David Howells17926a72007-04-26 15:48:28 -07001302}
1303
1304/*
1305 * clear the connection security
1306 */
1307static void rxkad_clear(struct rxrpc_connection *conn)
1308{
1309 _enter("");
1310
1311 if (conn->cipher)
Kees Cook69d826f2018-09-18 19:10:47 -07001312 crypto_free_sync_skcipher(conn->cipher);
David Howells17926a72007-04-26 15:48:28 -07001313}
1314
1315/*
David Howells648af7f2016-04-07 17:23:51 +01001316 * Initialise the rxkad security service.
1317 */
1318static int rxkad_init(void)
1319{
David Howells1db88c52019-07-30 15:56:57 +01001320 struct crypto_sync_skcipher *tfm;
1321 struct skcipher_request *req;
1322
David Howells648af7f2016-04-07 17:23:51 +01001323 /* pin the cipher we need so that the crypto layer doesn't invoke
1324 * keventd to go get it */
David Howells1db88c52019-07-30 15:56:57 +01001325 tfm = crypto_alloc_sync_skcipher("pcbc(fcrypt)", 0, 0);
1326 if (IS_ERR(tfm))
1327 return PTR_ERR(tfm);
1328
1329 req = skcipher_request_alloc(&tfm->base, GFP_KERNEL);
1330 if (!req)
1331 goto nomem_tfm;
1332
1333 rxkad_ci_req = req;
1334 rxkad_ci = tfm;
1335 return 0;
1336
1337nomem_tfm:
1338 crypto_free_sync_skcipher(tfm);
1339 return -ENOMEM;
David Howells648af7f2016-04-07 17:23:51 +01001340}
1341
1342/*
1343 * Clean up the rxkad security service.
1344 */
1345static void rxkad_exit(void)
1346{
David Howells1db88c52019-07-30 15:56:57 +01001347 crypto_free_sync_skcipher(rxkad_ci);
1348 skcipher_request_free(rxkad_ci_req);
David Howells648af7f2016-04-07 17:23:51 +01001349}
1350
1351/*
David Howells17926a72007-04-26 15:48:28 -07001352 * RxRPC Kerberos-based security
1353 */
David Howells648af7f2016-04-07 17:23:51 +01001354const struct rxrpc_security rxkad = {
David Howells17926a72007-04-26 15:48:28 -07001355 .name = "rxkad",
David Howells8b815472009-09-14 01:17:30 +00001356 .security_index = RXRPC_SECURITY_RXKAD,
David Howells063c60d2019-12-20 16:17:16 +00001357 .no_key_abort = RXKADUNKNOWNKEY,
David Howells648af7f2016-04-07 17:23:51 +01001358 .init = rxkad_init,
1359 .exit = rxkad_exit,
David Howells12da59f2020-09-16 08:37:29 +01001360 .preparse_server_key = rxkad_preparse_server_key,
1361 .free_preparse_server_key = rxkad_free_preparse_server_key,
1362 .destroy_server_key = rxkad_destroy_server_key,
David Howells17926a72007-04-26 15:48:28 -07001363 .init_connection_security = rxkad_init_connection_security,
David Howells17926a72007-04-26 15:48:28 -07001364 .secure_packet = rxkad_secure_packet,
1365 .verify_packet = rxkad_verify_packet,
David Howells1db88c52019-07-30 15:56:57 +01001366 .free_call_crypto = rxkad_free_call_crypto,
David Howells248f2192016-09-08 11:10:12 +01001367 .locate_data = rxkad_locate_data,
David Howells17926a72007-04-26 15:48:28 -07001368 .issue_challenge = rxkad_issue_challenge,
1369 .respond_to_challenge = rxkad_respond_to_challenge,
1370 .verify_response = rxkad_verify_response,
1371 .clear = rxkad_clear,
1372};