1 | /* |
2 | * COPYRIGHT (c) 2008 |
3 | * The Regents of the University of Michigan |
4 | * ALL RIGHTS RESERVED |
5 | * |
6 | * Permission is granted to use, copy, create derivative works |
7 | * and redistribute this software and such derivative works |
8 | * for any purpose, so long as the name of The University of |
9 | * Michigan is not used in any advertising or publicity |
10 | * pertaining to the use of distribution of this software |
11 | * without specific, written prior authorization. If the |
12 | * above copyright notice or any other identification of the |
13 | * University of Michigan is included in any copy of any |
14 | * portion of this software, then the disclaimer below must |
15 | * also be included. |
16 | * |
17 | * THIS SOFTWARE IS PROVIDED AS IS, WITHOUT REPRESENTATION |
18 | * FROM THE UNIVERSITY OF MICHIGAN AS TO ITS FITNESS FOR ANY |
19 | * PURPOSE, AND WITHOUT WARRANTY BY THE UNIVERSITY OF |
20 | * MICHIGAN OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING |
21 | * WITHOUT LIMITATION THE IMPLIED WARRANTIES OF |
22 | * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE |
23 | * REGENTS OF THE UNIVERSITY OF MICHIGAN SHALL NOT BE LIABLE |
24 | * FOR ANY DAMAGES, INCLUDING SPECIAL, INDIRECT, INCIDENTAL, OR |
25 | * CONSEQUENTIAL DAMAGES, WITH RESPECT TO ANY CLAIM ARISING |
26 | * OUT OF OR IN CONNECTION WITH THE USE OF THE SOFTWARE, EVEN |
27 | * IF IT HAS BEEN OR IS HEREAFTER ADVISED OF THE POSSIBILITY OF |
28 | * SUCH DAMAGES. |
29 | */ |
30 | |
31 | /* |
32 | * Copyright (C) 1998 by the FundsXpress, INC. |
33 | * |
34 | * All rights reserved. |
35 | * |
36 | * Export of this software from the United States of America may require |
37 | * a specific license from the United States Government. It is the |
38 | * responsibility of any person or organization contemplating export to |
39 | * obtain such a license before exporting. |
40 | * |
41 | * WITHIN THAT CONSTRAINT, permission to use, copy, modify, and |
42 | * distribute this software and its documentation for any purpose and |
43 | * without fee is hereby granted, provided that the above copyright |
44 | * notice appear in all copies and that both that copyright notice and |
45 | * this permission notice appear in supporting documentation, and that |
46 | * the name of FundsXpress. not be used in advertising or publicity pertaining |
47 | * to distribution of the software without specific, written prior |
48 | * permission. FundsXpress makes no representations about the suitability of |
49 | * this software for any purpose. It is provided "as is" without express |
50 | * or implied warranty. |
51 | * |
52 | * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR |
53 | * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED |
54 | * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. |
55 | */ |
56 | |
57 | #include <crypto/skcipher.h> |
58 | #include <linux/err.h> |
59 | #include <linux/types.h> |
60 | #include <linux/sunrpc/gss_krb5.h> |
61 | #include <linux/sunrpc/xdr.h> |
62 | #include <linux/lcm.h> |
63 | #include <crypto/hash.h> |
64 | #include <kunit/visibility.h> |
65 | |
66 | #include "gss_krb5_internal.h" |
67 | |
68 | #if IS_ENABLED(CONFIG_SUNRPC_DEBUG) |
69 | # define RPCDBG_FACILITY RPCDBG_AUTH |
70 | #endif |
71 | |
72 | /** |
73 | * krb5_nfold - n-fold function |
74 | * @inbits: number of bits in @in |
75 | * @in: buffer containing input to fold |
76 | * @outbits: number of bits in the output buffer |
77 | * @out: buffer to hold the result |
78 | * |
79 | * This is the n-fold function as described in rfc3961, sec 5.1 |
80 | * Taken from MIT Kerberos and modified. |
81 | */ |
82 | VISIBLE_IF_KUNIT |
83 | void krb5_nfold(u32 inbits, const u8 *in, u32 outbits, u8 *out) |
84 | { |
85 | unsigned long ulcm; |
86 | int byte, i, msbit; |
87 | |
88 | /* the code below is more readable if I make these bytes |
89 | instead of bits */ |
90 | |
91 | inbits >>= 3; |
92 | outbits >>= 3; |
93 | |
94 | /* first compute lcm(n,k) */ |
95 | ulcm = lcm(a: inbits, b: outbits); |
96 | |
97 | /* now do the real work */ |
98 | |
99 | memset(out, 0, outbits); |
100 | byte = 0; |
101 | |
102 | /* this will end up cycling through k lcm(k,n)/k times, which |
103 | is correct */ |
104 | for (i = ulcm-1; i >= 0; i--) { |
105 | /* compute the msbit in k which gets added into this byte */ |
106 | msbit = ( |
107 | /* first, start with the msbit in the first, |
108 | * unrotated byte */ |
109 | ((inbits << 3) - 1) |
110 | /* then, for each byte, shift to the right |
111 | * for each repetition */ |
112 | + (((inbits << 3) + 13) * (i/inbits)) |
113 | /* last, pick out the correct byte within |
114 | * that shifted repetition */ |
115 | + ((inbits - (i % inbits)) << 3) |
116 | ) % (inbits << 3); |
117 | |
118 | /* pull out the byte value itself */ |
119 | byte += (((in[((inbits - 1) - (msbit >> 3)) % inbits] << 8)| |
120 | (in[((inbits) - (msbit >> 3)) % inbits])) |
121 | >> ((msbit & 7) + 1)) & 0xff; |
122 | |
123 | /* do the addition */ |
124 | byte += out[i % outbits]; |
125 | out[i % outbits] = byte & 0xff; |
126 | |
127 | /* keep around the carry bit, if any */ |
128 | byte >>= 8; |
129 | |
130 | } |
131 | |
132 | /* if there's a carry bit left over, add it back in */ |
133 | if (byte) { |
134 | for (i = outbits - 1; i >= 0; i--) { |
135 | /* do the addition */ |
136 | byte += out[i]; |
137 | out[i] = byte & 0xff; |
138 | |
139 | /* keep around the carry bit, if any */ |
140 | byte >>= 8; |
141 | } |
142 | } |
143 | } |
144 | EXPORT_SYMBOL_IF_KUNIT(krb5_nfold); |
145 | |
146 | /* |
147 | * This is the DK (derive_key) function as described in rfc3961, sec 5.1 |
148 | * Taken from MIT Kerberos and modified. |
149 | */ |
150 | static int krb5_DK(const struct gss_krb5_enctype *gk5e, |
151 | const struct xdr_netobj *inkey, u8 *rawkey, |
152 | const struct xdr_netobj *in_constant, gfp_t gfp_mask) |
153 | { |
154 | size_t blocksize, keybytes, keylength, n; |
155 | unsigned char *inblockdata, *outblockdata; |
156 | struct xdr_netobj inblock, outblock; |
157 | struct crypto_sync_skcipher *cipher; |
158 | int ret = -EINVAL; |
159 | |
160 | keybytes = gk5e->keybytes; |
161 | keylength = gk5e->keylength; |
162 | |
163 | if (inkey->len != keylength) |
164 | goto err_return; |
165 | |
166 | cipher = crypto_alloc_sync_skcipher(alg_name: gk5e->encrypt_name, type: 0, mask: 0); |
167 | if (IS_ERR(ptr: cipher)) |
168 | goto err_return; |
169 | blocksize = crypto_sync_skcipher_blocksize(tfm: cipher); |
170 | if (crypto_sync_skcipher_setkey(tfm: cipher, key: inkey->data, keylen: inkey->len)) |
171 | goto err_return; |
172 | |
173 | ret = -ENOMEM; |
174 | inblockdata = kmalloc(size: blocksize, flags: gfp_mask); |
175 | if (inblockdata == NULL) |
176 | goto err_free_cipher; |
177 | |
178 | outblockdata = kmalloc(size: blocksize, flags: gfp_mask); |
179 | if (outblockdata == NULL) |
180 | goto err_free_in; |
181 | |
182 | inblock.data = (char *) inblockdata; |
183 | inblock.len = blocksize; |
184 | |
185 | outblock.data = (char *) outblockdata; |
186 | outblock.len = blocksize; |
187 | |
188 | /* initialize the input block */ |
189 | |
190 | if (in_constant->len == inblock.len) { |
191 | memcpy(inblock.data, in_constant->data, inblock.len); |
192 | } else { |
193 | krb5_nfold(in_constant->len * 8, in_constant->data, |
194 | inblock.len * 8, inblock.data); |
195 | } |
196 | |
197 | /* loop encrypting the blocks until enough key bytes are generated */ |
198 | |
199 | n = 0; |
200 | while (n < keybytes) { |
201 | krb5_encrypt(key: cipher, NULL, in: inblock.data, out: outblock.data, |
202 | length: inblock.len); |
203 | |
204 | if ((keybytes - n) <= outblock.len) { |
205 | memcpy(rawkey + n, outblock.data, (keybytes - n)); |
206 | break; |
207 | } |
208 | |
209 | memcpy(rawkey + n, outblock.data, outblock.len); |
210 | memcpy(inblock.data, outblock.data, outblock.len); |
211 | n += outblock.len; |
212 | } |
213 | |
214 | ret = 0; |
215 | |
216 | kfree_sensitive(objp: outblockdata); |
217 | err_free_in: |
218 | kfree_sensitive(objp: inblockdata); |
219 | err_free_cipher: |
220 | crypto_free_sync_skcipher(tfm: cipher); |
221 | err_return: |
222 | return ret; |
223 | } |
224 | |
225 | /* |
226 | * This is the identity function, with some sanity checking. |
227 | */ |
228 | static int krb5_random_to_key_v2(const struct gss_krb5_enctype *gk5e, |
229 | struct xdr_netobj *randombits, |
230 | struct xdr_netobj *key) |
231 | { |
232 | int ret = -EINVAL; |
233 | |
234 | if (key->len != 16 && key->len != 32) { |
235 | dprintk("%s: key->len is %d\n" , __func__, key->len); |
236 | goto err_out; |
237 | } |
238 | if (randombits->len != 16 && randombits->len != 32) { |
239 | dprintk("%s: randombits->len is %d\n" , |
240 | __func__, randombits->len); |
241 | goto err_out; |
242 | } |
243 | if (randombits->len != key->len) { |
244 | dprintk("%s: randombits->len is %d, key->len is %d\n" , |
245 | __func__, randombits->len, key->len); |
246 | goto err_out; |
247 | } |
248 | memcpy(key->data, randombits->data, key->len); |
249 | ret = 0; |
250 | err_out: |
251 | return ret; |
252 | } |
253 | |
254 | /** |
255 | * krb5_derive_key_v2 - Derive a subkey for an RFC 3962 enctype |
256 | * @gk5e: Kerberos 5 enctype profile |
257 | * @inkey: base protocol key |
258 | * @outkey: OUT: derived key |
259 | * @label: subkey usage label |
260 | * @gfp_mask: memory allocation control flags |
261 | * |
262 | * Caller sets @outkey->len to the desired length of the derived key. |
263 | * |
264 | * On success, returns 0 and fills in @outkey. A negative errno value |
265 | * is returned on failure. |
266 | */ |
267 | int krb5_derive_key_v2(const struct gss_krb5_enctype *gk5e, |
268 | const struct xdr_netobj *inkey, |
269 | struct xdr_netobj *outkey, |
270 | const struct xdr_netobj *label, |
271 | gfp_t gfp_mask) |
272 | { |
273 | struct xdr_netobj inblock; |
274 | int ret; |
275 | |
276 | inblock.len = gk5e->keybytes; |
277 | inblock.data = kmalloc(size: inblock.len, flags: gfp_mask); |
278 | if (!inblock.data) |
279 | return -ENOMEM; |
280 | |
281 | ret = krb5_DK(gk5e, inkey, rawkey: inblock.data, in_constant: label, gfp_mask); |
282 | if (!ret) |
283 | ret = krb5_random_to_key_v2(gk5e, randombits: &inblock, key: outkey); |
284 | |
285 | kfree_sensitive(objp: inblock.data); |
286 | return ret; |
287 | } |
288 | |
289 | /* |
290 | * K(i) = CMAC(key, K(i-1) | i | constant | 0x00 | k) |
291 | * |
292 | * i: A block counter is used with a length of 4 bytes, represented |
293 | * in big-endian order. |
294 | * |
295 | * constant: The label input to the KDF is the usage constant supplied |
296 | * to the key derivation function |
297 | * |
298 | * k: The length of the output key in bits, represented as a 4-byte |
299 | * string in big-endian order. |
300 | * |
301 | * Caller fills in K(i-1) in @step, and receives the result K(i) |
302 | * in the same buffer. |
303 | */ |
304 | static int |
305 | krb5_cmac_Ki(struct crypto_shash *tfm, const struct xdr_netobj *constant, |
306 | u32 outlen, u32 count, struct xdr_netobj *step) |
307 | { |
308 | __be32 k = cpu_to_be32(outlen * 8); |
309 | SHASH_DESC_ON_STACK(desc, tfm); |
310 | __be32 i = cpu_to_be32(count); |
311 | u8 zero = 0; |
312 | int ret; |
313 | |
314 | desc->tfm = tfm; |
315 | ret = crypto_shash_init(desc); |
316 | if (ret) |
317 | goto out_err; |
318 | |
319 | ret = crypto_shash_update(desc, data: step->data, len: step->len); |
320 | if (ret) |
321 | goto out_err; |
322 | ret = crypto_shash_update(desc, data: (u8 *)&i, len: sizeof(i)); |
323 | if (ret) |
324 | goto out_err; |
325 | ret = crypto_shash_update(desc, data: constant->data, len: constant->len); |
326 | if (ret) |
327 | goto out_err; |
328 | ret = crypto_shash_update(desc, data: &zero, len: sizeof(zero)); |
329 | if (ret) |
330 | goto out_err; |
331 | ret = crypto_shash_update(desc, data: (u8 *)&k, len: sizeof(k)); |
332 | if (ret) |
333 | goto out_err; |
334 | ret = crypto_shash_final(desc, out: step->data); |
335 | if (ret) |
336 | goto out_err; |
337 | |
338 | out_err: |
339 | shash_desc_zero(desc); |
340 | return ret; |
341 | } |
342 | |
343 | /** |
344 | * krb5_kdf_feedback_cmac - Derive a subkey for a Camellia/CMAC-based enctype |
345 | * @gk5e: Kerberos 5 enctype parameters |
346 | * @inkey: base protocol key |
347 | * @outkey: OUT: derived key |
348 | * @constant: subkey usage label |
349 | * @gfp_mask: memory allocation control flags |
350 | * |
351 | * RFC 6803 Section 3: |
352 | * |
353 | * "We use a key derivation function from the family specified in |
354 | * [SP800-108], Section 5.2, 'KDF in Feedback Mode'." |
355 | * |
356 | * n = ceiling(k / 128) |
357 | * K(0) = zeros |
358 | * K(i) = CMAC(key, K(i-1) | i | constant | 0x00 | k) |
359 | * DR(key, constant) = k-truncate(K(1) | K(2) | ... | K(n)) |
360 | * KDF-FEEDBACK-CMAC(key, constant) = random-to-key(DR(key, constant)) |
361 | * |
362 | * Caller sets @outkey->len to the desired length of the derived key (k). |
363 | * |
364 | * On success, returns 0 and fills in @outkey. A negative errno value |
365 | * is returned on failure. |
366 | */ |
367 | int |
368 | krb5_kdf_feedback_cmac(const struct gss_krb5_enctype *gk5e, |
369 | const struct xdr_netobj *inkey, |
370 | struct xdr_netobj *outkey, |
371 | const struct xdr_netobj *constant, |
372 | gfp_t gfp_mask) |
373 | { |
374 | struct xdr_netobj step = { .data = NULL }; |
375 | struct xdr_netobj DR = { .data = NULL }; |
376 | unsigned int blocksize, offset; |
377 | struct crypto_shash *tfm; |
378 | int n, count, ret; |
379 | |
380 | /* |
381 | * This implementation assumes the CMAC used for an enctype's |
382 | * key derivation is the same as the CMAC used for its |
383 | * checksumming. This happens to be true for enctypes that |
384 | * are currently supported by this implementation. |
385 | */ |
386 | tfm = crypto_alloc_shash(alg_name: gk5e->cksum_name, type: 0, mask: 0); |
387 | if (IS_ERR(ptr: tfm)) { |
388 | ret = PTR_ERR(ptr: tfm); |
389 | goto out; |
390 | } |
391 | ret = crypto_shash_setkey(tfm, key: inkey->data, keylen: inkey->len); |
392 | if (ret) |
393 | goto out_free_tfm; |
394 | |
395 | blocksize = crypto_shash_digestsize(tfm); |
396 | n = (outkey->len + blocksize - 1) / blocksize; |
397 | |
398 | /* K(0) is all zeroes */ |
399 | ret = -ENOMEM; |
400 | step.len = blocksize; |
401 | step.data = kzalloc(size: step.len, flags: gfp_mask); |
402 | if (!step.data) |
403 | goto out_free_tfm; |
404 | |
405 | DR.len = blocksize * n; |
406 | DR.data = kmalloc(size: DR.len, flags: gfp_mask); |
407 | if (!DR.data) |
408 | goto out_free_tfm; |
409 | |
410 | /* XXX: Does not handle partial-block key sizes */ |
411 | for (offset = 0, count = 1; count <= n; count++) { |
412 | ret = krb5_cmac_Ki(tfm, constant, outlen: outkey->len, count, step: &step); |
413 | if (ret) |
414 | goto out_free_tfm; |
415 | |
416 | memcpy(DR.data + offset, step.data, blocksize); |
417 | offset += blocksize; |
418 | } |
419 | |
420 | /* k-truncate and random-to-key */ |
421 | memcpy(outkey->data, DR.data, outkey->len); |
422 | ret = 0; |
423 | |
424 | out_free_tfm: |
425 | crypto_free_shash(tfm); |
426 | out: |
427 | kfree_sensitive(objp: step.data); |
428 | kfree_sensitive(objp: DR.data); |
429 | return ret; |
430 | } |
431 | |
432 | /* |
433 | * K1 = HMAC-SHA(key, 0x00000001 | label | 0x00 | k) |
434 | * |
435 | * key: The source of entropy from which subsequent keys are derived. |
436 | * |
437 | * label: An octet string describing the intended usage of the |
438 | * derived key. |
439 | * |
440 | * k: Length in bits of the key to be outputted, expressed in |
441 | * big-endian binary representation in 4 bytes. |
442 | */ |
443 | static int |
444 | krb5_hmac_K1(struct crypto_shash *tfm, const struct xdr_netobj *label, |
445 | u32 outlen, struct xdr_netobj *K1) |
446 | { |
447 | __be32 k = cpu_to_be32(outlen * 8); |
448 | SHASH_DESC_ON_STACK(desc, tfm); |
449 | __be32 one = cpu_to_be32(1); |
450 | u8 zero = 0; |
451 | int ret; |
452 | |
453 | desc->tfm = tfm; |
454 | ret = crypto_shash_init(desc); |
455 | if (ret) |
456 | goto out_err; |
457 | ret = crypto_shash_update(desc, data: (u8 *)&one, len: sizeof(one)); |
458 | if (ret) |
459 | goto out_err; |
460 | ret = crypto_shash_update(desc, data: label->data, len: label->len); |
461 | if (ret) |
462 | goto out_err; |
463 | ret = crypto_shash_update(desc, data: &zero, len: sizeof(zero)); |
464 | if (ret) |
465 | goto out_err; |
466 | ret = crypto_shash_update(desc, data: (u8 *)&k, len: sizeof(k)); |
467 | if (ret) |
468 | goto out_err; |
469 | ret = crypto_shash_final(desc, out: K1->data); |
470 | if (ret) |
471 | goto out_err; |
472 | |
473 | out_err: |
474 | shash_desc_zero(desc); |
475 | return ret; |
476 | } |
477 | |
478 | /** |
479 | * krb5_kdf_hmac_sha2 - Derive a subkey for an AES/SHA2-based enctype |
480 | * @gk5e: Kerberos 5 enctype policy parameters |
481 | * @inkey: base protocol key |
482 | * @outkey: OUT: derived key |
483 | * @label: subkey usage label |
484 | * @gfp_mask: memory allocation control flags |
485 | * |
486 | * RFC 8009 Section 3: |
487 | * |
488 | * "We use a key derivation function from Section 5.1 of [SP800-108], |
489 | * which uses the HMAC algorithm as the PRF." |
490 | * |
491 | * function KDF-HMAC-SHA2(key, label, [context,] k): |
492 | * k-truncate(K1) |
493 | * |
494 | * Caller sets @outkey->len to the desired length of the derived key. |
495 | * |
496 | * On success, returns 0 and fills in @outkey. A negative errno value |
497 | * is returned on failure. |
498 | */ |
499 | int |
500 | krb5_kdf_hmac_sha2(const struct gss_krb5_enctype *gk5e, |
501 | const struct xdr_netobj *inkey, |
502 | struct xdr_netobj *outkey, |
503 | const struct xdr_netobj *label, |
504 | gfp_t gfp_mask) |
505 | { |
506 | struct crypto_shash *tfm; |
507 | struct xdr_netobj K1 = { |
508 | .data = NULL, |
509 | }; |
510 | int ret; |
511 | |
512 | /* |
513 | * This implementation assumes the HMAC used for an enctype's |
514 | * key derivation is the same as the HMAC used for its |
515 | * checksumming. This happens to be true for enctypes that |
516 | * are currently supported by this implementation. |
517 | */ |
518 | tfm = crypto_alloc_shash(alg_name: gk5e->cksum_name, type: 0, mask: 0); |
519 | if (IS_ERR(ptr: tfm)) { |
520 | ret = PTR_ERR(ptr: tfm); |
521 | goto out; |
522 | } |
523 | ret = crypto_shash_setkey(tfm, key: inkey->data, keylen: inkey->len); |
524 | if (ret) |
525 | goto out_free_tfm; |
526 | |
527 | K1.len = crypto_shash_digestsize(tfm); |
528 | K1.data = kmalloc(size: K1.len, flags: gfp_mask); |
529 | if (!K1.data) { |
530 | ret = -ENOMEM; |
531 | goto out_free_tfm; |
532 | } |
533 | |
534 | ret = krb5_hmac_K1(tfm, label, outlen: outkey->len, K1: &K1); |
535 | if (ret) |
536 | goto out_free_tfm; |
537 | |
538 | /* k-truncate and random-to-key */ |
539 | memcpy(outkey->data, K1.data, outkey->len); |
540 | |
541 | out_free_tfm: |
542 | kfree_sensitive(objp: K1.data); |
543 | crypto_free_shash(tfm); |
544 | out: |
545 | return ret; |
546 | } |
547 | |