xref: /linux/net/rxrpc/rxgk_kdf.c (revision ab93e0dd72c37d378dd936f031ffb83ff2bd87ce)
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /* RxGK transport key derivation.
3  *
4  * Copyright (C) 2025 Red Hat, Inc. All Rights Reserved.
5  * Written by David Howells (dhowells@redhat.com)
6  */
7 
8 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
9 
10 #include <linux/key-type.h>
11 #include <linux/slab.h>
12 #include <keys/rxrpc-type.h>
13 #include "ar-internal.h"
14 #include "rxgk_common.h"
15 
16 #define round16(x) (((x) + 15) & ~15)
17 
18 /*
19  * Constants used to derive the keys and hmacs actually used for doing stuff.
20  */
21 #define RXGK_CLIENT_ENC_PACKET		1026U // 0x402
22 #define RXGK_CLIENT_MIC_PACKET          1027U // 0x403
23 #define RXGK_SERVER_ENC_PACKET          1028U // 0x404
24 #define RXGK_SERVER_MIC_PACKET          1029U // 0x405
25 #define RXGK_CLIENT_ENC_RESPONSE        1030U // 0x406
26 #define RXGK_SERVER_ENC_TOKEN           1036U // 0x40c
27 
rxgk_free(struct rxgk_context * gk)28 static void rxgk_free(struct rxgk_context *gk)
29 {
30 	if (gk->tx_Kc)
31 		crypto_free_shash(gk->tx_Kc);
32 	if (gk->rx_Kc)
33 		crypto_free_shash(gk->rx_Kc);
34 	if (gk->tx_enc)
35 		crypto_free_aead(gk->tx_enc);
36 	if (gk->rx_enc)
37 		crypto_free_aead(gk->rx_enc);
38 	if (gk->resp_enc)
39 		crypto_free_aead(gk->resp_enc);
40 	kfree(gk);
41 }
42 
rxgk_put(struct rxgk_context * gk)43 void rxgk_put(struct rxgk_context *gk)
44 {
45 	if (gk && refcount_dec_and_test(&gk->usage))
46 		rxgk_free(gk);
47 }
48 
49 /*
50  * Transport key derivation function.
51  *
52  *      TK = random-to-key(PRF+(K0, L,
53  *                         epoch || cid || start_time || key_number))
54  *      [tools.ietf.org/html/draft-wilkinson-afs3-rxgk-11 sec 8.3]
55  */
rxgk_derive_transport_key(struct rxrpc_connection * conn,struct rxgk_context * gk,const struct rxgk_key * rxgk,struct krb5_buffer * TK,gfp_t gfp)56 static int rxgk_derive_transport_key(struct rxrpc_connection *conn,
57 				     struct rxgk_context *gk,
58 				     const struct rxgk_key *rxgk,
59 				     struct krb5_buffer *TK,
60 				     gfp_t gfp)
61 {
62 	const struct krb5_enctype *krb5 = gk->krb5;
63 	struct krb5_buffer conn_info;
64 	unsigned int L = krb5->key_bytes;
65 	__be32 *info;
66 	u8 *buffer;
67 	int ret;
68 
69 	_enter("");
70 
71 	conn_info.len = sizeof(__be32) * 5;
72 
73 	buffer = kzalloc(round16(conn_info.len), gfp);
74 	if (!buffer)
75 		return -ENOMEM;
76 
77 	conn_info.data = buffer;
78 
79 	info = (__be32 *)conn_info.data;
80 	info[0] = htonl(conn->proto.epoch);
81 	info[1] = htonl(conn->proto.cid);
82 	info[2] = htonl(conn->rxgk.start_time >> 32);
83 	info[3] = htonl(conn->rxgk.start_time >>  0);
84 	info[4] = htonl(gk->key_number);
85 
86 	ret = crypto_krb5_calc_PRFplus(krb5, &rxgk->key, L, &conn_info, TK, gfp);
87 	kfree_sensitive(buffer);
88 	_leave(" = %d", ret);
89 	return ret;
90 }
91 
92 /*
93  * Set up the ciphers for the usage keys.
94  */
rxgk_set_up_ciphers(struct rxrpc_connection * conn,struct rxgk_context * gk,const struct rxgk_key * rxgk,gfp_t gfp)95 static int rxgk_set_up_ciphers(struct rxrpc_connection *conn,
96 			       struct rxgk_context *gk,
97 			       const struct rxgk_key *rxgk,
98 			       gfp_t gfp)
99 {
100 	const struct krb5_enctype *krb5 = gk->krb5;
101 	struct crypto_shash *shash;
102 	struct crypto_aead *aead;
103 	struct krb5_buffer TK;
104 	bool service = rxrpc_conn_is_service(conn);
105 	int ret;
106 	u8 *buffer;
107 
108 	buffer = kzalloc(krb5->key_bytes, gfp);
109 	if (!buffer)
110 		return -ENOMEM;
111 
112 	TK.len = krb5->key_bytes;
113 	TK.data = buffer;
114 
115 	ret = rxgk_derive_transport_key(conn, gk, rxgk, &TK, gfp);
116 	if (ret < 0)
117 		goto out;
118 
119 	aead = crypto_krb5_prepare_encryption(krb5, &TK, RXGK_CLIENT_ENC_RESPONSE, gfp);
120 	if (IS_ERR(aead))
121 		goto aead_error;
122 	gk->resp_enc = aead;
123 
124 	if (crypto_aead_blocksize(gk->resp_enc) != krb5->block_len ||
125 	    crypto_aead_authsize(gk->resp_enc) != krb5->cksum_len) {
126 		pr_notice("algo inconsistent with krb5 table %u!=%u or %u!=%u\n",
127 			  crypto_aead_blocksize(gk->resp_enc), krb5->block_len,
128 			  crypto_aead_authsize(gk->resp_enc), krb5->cksum_len);
129 		ret = -EINVAL;
130 		goto out;
131 	}
132 
133 	if (service) {
134 		switch (conn->security_level) {
135 		case RXRPC_SECURITY_AUTH:
136 			shash = crypto_krb5_prepare_checksum(
137 				krb5, &TK, RXGK_SERVER_MIC_PACKET, gfp);
138 			if (IS_ERR(shash))
139 				goto hash_error;
140 			gk->tx_Kc = shash;
141 			shash = crypto_krb5_prepare_checksum(
142 				krb5, &TK, RXGK_CLIENT_MIC_PACKET, gfp);
143 			if (IS_ERR(shash))
144 				goto hash_error;
145 			gk->rx_Kc = shash;
146 			break;
147 		case RXRPC_SECURITY_ENCRYPT:
148 			aead = crypto_krb5_prepare_encryption(
149 				krb5, &TK, RXGK_SERVER_ENC_PACKET, gfp);
150 			if (IS_ERR(aead))
151 				goto aead_error;
152 			gk->tx_enc = aead;
153 			aead = crypto_krb5_prepare_encryption(
154 				krb5, &TK, RXGK_CLIENT_ENC_PACKET, gfp);
155 			if (IS_ERR(aead))
156 				goto aead_error;
157 			gk->rx_enc = aead;
158 			break;
159 		}
160 	} else {
161 		switch (conn->security_level) {
162 		case RXRPC_SECURITY_AUTH:
163 			shash = crypto_krb5_prepare_checksum(
164 				krb5, &TK, RXGK_CLIENT_MIC_PACKET, gfp);
165 			if (IS_ERR(shash))
166 				goto hash_error;
167 			gk->tx_Kc = shash;
168 			shash = crypto_krb5_prepare_checksum(
169 				krb5, &TK, RXGK_SERVER_MIC_PACKET, gfp);
170 			if (IS_ERR(shash))
171 				goto hash_error;
172 			gk->rx_Kc = shash;
173 			break;
174 		case RXRPC_SECURITY_ENCRYPT:
175 			aead = crypto_krb5_prepare_encryption(
176 				krb5, &TK, RXGK_CLIENT_ENC_PACKET, gfp);
177 			if (IS_ERR(aead))
178 				goto aead_error;
179 			gk->tx_enc = aead;
180 			aead = crypto_krb5_prepare_encryption(
181 				krb5, &TK, RXGK_SERVER_ENC_PACKET, gfp);
182 			if (IS_ERR(aead))
183 				goto aead_error;
184 			gk->rx_enc = aead;
185 			break;
186 		}
187 	}
188 
189 	ret = 0;
190 out:
191 	kfree_sensitive(buffer);
192 	return ret;
193 aead_error:
194 	ret = PTR_ERR(aead);
195 	goto out;
196 hash_error:
197 	ret = PTR_ERR(shash);
198 	goto out;
199 }
200 
201 /*
202  * Derive a transport key for a connection and then derive a bunch of usage
203  * keys from it and set up ciphers using them.
204  */
rxgk_generate_transport_key(struct rxrpc_connection * conn,const struct rxgk_key * key,unsigned int key_number,gfp_t gfp)205 struct rxgk_context *rxgk_generate_transport_key(struct rxrpc_connection *conn,
206 						 const struct rxgk_key *key,
207 						 unsigned int key_number,
208 						 gfp_t gfp)
209 {
210 	struct rxgk_context *gk;
211 	unsigned long lifetime;
212 	int ret = -ENOPKG;
213 
214 	_enter("");
215 
216 	gk = kzalloc(sizeof(*gk), GFP_KERNEL);
217 	if (!gk)
218 		return ERR_PTR(-ENOMEM);
219 	refcount_set(&gk->usage, 1);
220 	gk->key		= key;
221 	gk->key_number	= key_number;
222 
223 	gk->krb5 = crypto_krb5_find_enctype(key->enctype);
224 	if (!gk->krb5)
225 		goto err_tk;
226 
227 	ret = rxgk_set_up_ciphers(conn, gk, key, gfp);
228 	if (ret)
229 		goto err_tk;
230 
231 	/* Set the remaining number of bytes encrypted with this key that may
232 	 * be transmitted before rekeying.  Note that the spec has been
233 	 * interpreted differently on this point...
234 	 */
235 	switch (key->bytelife) {
236 	case 0:
237 	case 63:
238 		gk->bytes_remaining = LLONG_MAX;
239 		break;
240 	case 1 ... 62:
241 		gk->bytes_remaining = 1LL << key->bytelife;
242 		break;
243 	default:
244 		gk->bytes_remaining = key->bytelife;
245 		break;
246 	}
247 
248 	/* Set the time after which rekeying must occur */
249 	if (key->lifetime) {
250 		lifetime = min_t(u64, key->lifetime, INT_MAX / HZ);
251 		lifetime *= HZ;
252 	} else {
253 		lifetime = MAX_JIFFY_OFFSET;
254 	}
255 	gk->expiry = jiffies + lifetime;
256 	return gk;
257 
258 err_tk:
259 	rxgk_put(gk);
260 	_leave(" = %d", ret);
261 	return ERR_PTR(ret);
262 }
263 
264 /*
265  * Use the server secret key to set up the ciphers that will be used to extract
266  * the token from a response packet.
267  */
rxgk_set_up_token_cipher(const struct krb5_buffer * server_key,struct crypto_aead ** token_aead,unsigned int enctype,const struct krb5_enctype ** _krb5,gfp_t gfp)268 int rxgk_set_up_token_cipher(const struct krb5_buffer *server_key,
269 			     struct crypto_aead **token_aead,
270 			     unsigned int enctype,
271 			     const struct krb5_enctype **_krb5,
272 			     gfp_t gfp)
273 {
274 	const struct krb5_enctype *krb5;
275 	struct crypto_aead *aead;
276 
277 	krb5 = crypto_krb5_find_enctype(enctype);
278 	if (!krb5)
279 		return -ENOPKG;
280 
281 	aead = crypto_krb5_prepare_encryption(krb5, server_key, RXGK_SERVER_ENC_TOKEN, gfp);
282 	if (IS_ERR(aead))
283 		return PTR_ERR(aead);
284 
285 	*_krb5 = krb5;
286 	*token_aead = aead;
287 	return 0;
288 }
289