1 /*
2 * Copyright (c) 2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 /*
30 * Copyright (c) 1999 Kungliga Tekniska Högskolan
31 * (Royal Institute of Technology, Stockholm, Sweden).
32 * All rights reserved.
33 *
34 * Redistribution and use in source and binary forms, with or without
35 * modification, are permitted provided that the following conditions
36 * are met:
37 *
38 * 1. Redistributions of source code must retain the above copyright
39 * notice, this list of conditions and the following disclaimer.
40 *
41 * 2. Redistributions in binary form must reproduce the above copyright
42 * notice, this list of conditions and the following disclaimer in the
43 * documentation and/or other materials provided with the distribution.
44 *
45 * 3. Neither the name of KTH nor the names of its contributors may be
46 * used to endorse or promote products derived from this software without
47 * specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY KTH AND ITS CONTRIBUTORS ``AS IS'' AND ANY
50 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
51 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
52 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL KTH OR ITS CONTRIBUTORS BE
53 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
54 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
55 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
56 * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
57 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
58 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
59 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 */
61
62 #include <stdint.h>
63 #include <sys/param.h>
64 #include <sys/systm.h>
65 #include <sys/kernel.h>
66 #include <sys/malloc.h>
67 #include <sys/kpi_mbuf.h>
68 #include <sys/random.h>
69 #include <mach_assert.h>
70 #include <kern/assert.h>
71 #include <libkern/OSAtomic.h>
72 #include <IOKit/IOLib.h>
73 #include "gss_krb5_mech.h"
74
75 LCK_GRP_DECLARE(gss_krb5_mech_grp, "gss_krb5_mech");
76
77 typedef struct crypt_walker_ctx {
78 size_t length;
79 const struct ccmode_cbc *ccmode;
80 cccbc_ctx *crypt_ctx;
81 cccbc_iv *iv;
82 } *crypt_walker_ctx_t;
83
84 typedef struct hmac_walker_ctx {
85 const struct ccdigest_info *di;
86 struct cchmac_ctx *hmac_ctx;
87 } *hmac_walker_ctx_t;
88
89 typedef size_t (*ccpad_func)(const struct ccmode_cbc *, cccbc_ctx *, cccbc_iv *,
90 size_t nbytes, const void *, void *);
91
92 static int krb5_n_fold(const void *instr, size_t len, void *foldstr, size_t size);
93
94 size_t gss_mbuf_len(mbuf_t, size_t);
95 errno_t gss_prepend_mbuf(mbuf_t *, uint8_t *, size_t);
96 errno_t gss_append_mbuf(mbuf_t, uint8_t *, size_t);
97 errno_t gss_strip_mbuf(mbuf_t, int);
98 int mbuf_walk(mbuf_t, size_t, size_t, size_t, int (*)(void *, uint8_t *, size_t), void *);
99
100 void do_crypt_init(crypt_walker_ctx_t, int, crypto_ctx_t, cccbc_ctx *);
101 int do_crypt(void *, uint8_t *, size_t);
102 void do_hmac_init(hmac_walker_ctx_t, crypto_ctx_t, void *);
103 int do_hmac(void *, uint8_t *, size_t);
104 void do_hmac_destroy(hmac_walker_ctx_t, crypto_ctx_t);
105
106 void krb5_make_usage(uint32_t, uint8_t, uint8_t[KRB5_USAGE_LEN]);
107 void krb5_key_derivation(crypto_ctx_t, const void *, size_t, krb5_key_t *, size_t);
108 void cc_key_schedule_create(crypto_ctx_t);
109 void gss_crypto_ctx_free(crypto_ctx_t);
110 int gss_crypto_ctx_init(struct crypto_ctx *, lucid_context_t);
111
112 errno_t krb5_crypt_mbuf(crypto_ctx_t, mbuf_t *, size_t, int, cccbc_ctx *);
113 int krb5_mic(crypto_ctx_t, gss_buffer_t, gss_buffer_t, gss_buffer_t, uint8_t *, int *, int, int);
114 int krb5_mic_mbuf(crypto_ctx_t, gss_buffer_t, mbuf_t, size_t, size_t, gss_buffer_t, uint8_t *, int *, int, int);
115
116 uint32_t gss_krb5_cfx_get_mic(uint32_t *, gss_ctx_id_t, gss_qop_t, gss_buffer_t, gss_buffer_t);
117 uint32_t gss_krb5_cfx_get_mic_mbuf(uint32_t *, gss_ctx_id_t, gss_qop_t, mbuf_t, size_t, size_t, gss_buffer_t);
118 uint32_t gss_krb5_cfx_verify_mic_mbuf(uint32_t *, gss_ctx_id_t, mbuf_t, size_t, size_t, gss_buffer_t, gss_qop_t *);
119 errno_t krb5_cfx_crypt_mbuf(crypto_ctx_t, mbuf_t *, size_t *, int, int);
120 uint32_t gss_krb5_cfx_wrap_mbuf(uint32_t *, gss_ctx_id_t, int, gss_qop_t, mbuf_t *, size_t, int *);
121 uint32_t gss_krb5_cfx_unwrap_mbuf(uint32_t *, gss_ctx_id_t, mbuf_t *, size_t, int *, gss_qop_t *);
122
123 int gss_krb5_mech_is_initialized(void);
124 void gss_krb5_mech_init(void);
125
126 /* Debugging routines */
127 void
printmbuf(const char * str,mbuf_t mb,uint32_t offset,uint32_t len)128 printmbuf(const char *str, mbuf_t mb, uint32_t offset, uint32_t len)
129 {
130 size_t i;
131 int cout = 1;
132
133 len = len ? len : ~0;
134 printf("%s mbuf = %p offset = %d len = %d:\n", str ? str : "mbuf", mb, offset, len);
135 for (; mb && len; mb = mbuf_next(mb)) {
136 if (offset >= mbuf_len(mb)) {
137 offset -= mbuf_len(mb);
138 continue;
139 }
140 for (i = offset; len && i < mbuf_len(mb); i++) {
141 const char *s = (cout % 8) ? " " : (cout % 16) ? " " : "\n";
142 printf("%02x%s", ((uint8_t *)mbuf_data(mb))[i], s);
143 len--;
144 cout++;
145 }
146 offset = 0;
147 }
148 if ((cout - 1) % 16) {
149 printf("\n");
150 }
151 printf("Count chars %d\n", cout - 1);
152 }
153
154 void
printgbuf(const char * str,gss_buffer_t buf)155 printgbuf(const char *str, gss_buffer_t buf)
156 {
157 size_t i;
158 size_t len = buf->length > 128 ? 128 : buf->length;
159
160 printf("%s: len = %d value = %p\n", str ? str : "buffer", (int)buf->length, buf->value);
161 for (i = 0; i < len; i++) {
162 const char *s = ((i + 1) % 8) ? " " : ((i + 1) % 16) ? " " : "\n";
163 printf("%02x%s", ((uint8_t *)buf->value)[i], s);
164 }
165 if (i % 16) {
166 printf("\n");
167 }
168 }
169
170 /*
171 * Initialize the data structures for the gss kerberos mech.
172 */
173 #define GSS_KRB5_NOT_INITIALIZED 0
174 #define GSS_KRB5_INITIALIZING 1
175 #define GSS_KRB5_INITIALIZED 2
176 static volatile uint32_t gss_krb5_mech_initted = GSS_KRB5_NOT_INITIALIZED;
177
178 int
gss_krb5_mech_is_initialized(void)179 gss_krb5_mech_is_initialized(void)
180 {
181 return gss_krb5_mech_initted == GSS_KRB5_NOT_INITIALIZED;
182 }
183
184 static void
gss_krb5_key_set(krb5_key_t * krb_key,void * key,size_t len)185 gss_krb5_key_set(krb5_key_t *krb_key, void *key, size_t len)
186 {
187 krb_key->key_val = key;
188 krb_key->key_len = len;
189 }
190
191 static void
gss_krb5_key_free(krb5_key_t * krb_key,int free)192 gss_krb5_key_free(krb5_key_t *krb_key, int free)
193 {
194 if (free) {
195 cc_clear(krb_key->key_len, krb_key->key_val);
196 kfree_data(krb_key->key_val, krb_key->key_len);
197 }
198 memset(krb_key, 0, sizeof(krb5_key_t));
199 }
200
201 static void
gss_krb5_key_ctx_free(krb5_key_t * krb_key,void * ctx_key)202 gss_krb5_key_ctx_free(krb5_key_t *krb_key, void *ctx_key)
203 {
204 gss_krb5_key_free(krb_key, krb_key->key_val && ctx_key != krb_key->key_val);
205 }
206
207 void
gss_krb5_mech_init(void)208 gss_krb5_mech_init(void)
209 {
210 /* Once initted always initted */
211 if (gss_krb5_mech_initted == GSS_KRB5_INITIALIZED) {
212 return;
213 }
214
215 /* make sure we init only once */
216 if (!OSCompareAndSwap(GSS_KRB5_NOT_INITIALIZED, GSS_KRB5_INITIALIZING, &gss_krb5_mech_initted)) {
217 /* wait until initialization is complete */
218 while (!gss_krb5_mech_is_initialized()) {
219 IOSleep(10);
220 }
221 return;
222 }
223 gss_krb5_mech_initted = GSS_KRB5_INITIALIZED;
224 }
225
226 uint32_t
gss_release_buffer(uint32_t * minor,gss_buffer_t buf)227 gss_release_buffer(uint32_t *minor, gss_buffer_t buf)
228 {
229 if (minor) {
230 *minor = 0;
231 }
232 if (buf->value) {
233 kfree_data(buf->value, buf->length);
234 }
235 buf->value = NULL;
236 buf->length = 0;
237 return GSS_S_COMPLETE;
238 }
239
240 /*
241 * GSS mbuf routines
242 */
243
244 size_t
gss_mbuf_len(mbuf_t mb,size_t offset)245 gss_mbuf_len(mbuf_t mb, size_t offset)
246 {
247 size_t len;
248
249 for (len = 0; mb; mb = mbuf_next(mb)) {
250 len += mbuf_len(mb);
251 }
252 return (offset > len) ? 0 : len - offset;
253 }
254
255 /*
256 * Split an mbuf in a chain into two mbufs such that the original mbuf
257 * points to the original mbuf and the new mbuf points to the rest of the
258 * chain. The first mbuf length is the first len bytes and the second
259 * mbuf contains the remaining bytes. if len is zero or equals
260 * mbuf_len(mb) the don't create a new mbuf. We are already at an mbuf
261 * boundary. Return the mbuf that starts at the offset.
262 */
263 static errno_t
split_one_mbuf(mbuf_t mb,size_t offset,mbuf_t * nmb,int join)264 split_one_mbuf(mbuf_t mb, size_t offset, mbuf_t *nmb, int join)
265 {
266 errno_t error;
267
268 *nmb = mb;
269 /* We don't have an mbuf or we're alread on an mbuf boundary */
270 if (mb == NULL || offset == 0) {
271 return 0;
272 }
273
274 /* If the mbuf length is offset then the next mbuf is the one we want */
275 if (mbuf_len(mb) == offset) {
276 *nmb = mbuf_next(mb);
277 if (!join) {
278 mbuf_setnext(mb, NULL);
279 }
280 return 0;
281 }
282
283 if (offset > mbuf_len(mb)) {
284 return EINVAL;
285 }
286
287 error = mbuf_split(mb, offset, MBUF_WAITOK, nmb);
288 if (error) {
289 return error;
290 }
291
292 if (mbuf_flags(*nmb) & MBUF_PKTHDR) {
293 /* We don't want to copy the pkthdr. mbuf_split does that. */
294 error = mbuf_setflags_mask(*nmb, ~MBUF_PKTHDR, MBUF_PKTHDR);
295 }
296
297 if (join) {
298 /* Join the chain again */
299 mbuf_setnext(mb, *nmb);
300 }
301
302 return 0;
303 }
304
305 /*
306 * Given an mbuf with an offset and length return the chain such that
307 * offset and offset + *subchain_length are on mbuf boundaries. If
308 * *mbuf_length is less that the length of the chain after offset
309 * return that length in *mbuf_length. The mbuf sub chain starting at
310 * offset is returned in *subchain. If an error occurs return the
311 * corresponding errno. Note if there are less than offset bytes then
312 * subchain will be set to NULL and *subchain_length will be set to
313 * zero. If *subchain_length is 0; then set it to the length of the
314 * chain starting at offset. Join parameter is used to indicate whether
315 * the mbuf chain will be joined again as on chain, just rearranged so
316 * that offset and subchain_length are on mbuf boundaries.
317 */
318
319 errno_t
gss_normalize_mbuf(mbuf_t chain,size_t offset,size_t * subchain_length,mbuf_t * subchain,mbuf_t * tail,int join)320 gss_normalize_mbuf(mbuf_t chain, size_t offset, size_t *subchain_length, mbuf_t *subchain, mbuf_t *tail, int join)
321 {
322 size_t length = *subchain_length ? *subchain_length : ~0;
323 size_t len;
324 mbuf_t mb, nmb;
325 errno_t error;
326
327 if (tail == NULL) {
328 tail = &nmb;
329 }
330 *tail = NULL;
331 *subchain = NULL;
332
333 for (len = offset, mb = chain; mb && len > mbuf_len(mb); mb = mbuf_next(mb)) {
334 len -= mbuf_len(mb);
335 }
336
337 /* if we don't have offset bytes just return */
338 if (mb == NULL) {
339 return 0;
340 }
341
342 error = split_one_mbuf(mb, len, subchain, join);
343 if (error) {
344 return error;
345 }
346
347 assert(subchain != NULL && *subchain != NULL);
348 assert(offset == 0 ? mb == *subchain : 1);
349
350 len = gss_mbuf_len(*subchain, 0);
351 length = (length > len) ? len : length;
352 *subchain_length = length;
353
354 for (len = length, mb = *subchain; mb && len > mbuf_len(mb); mb = mbuf_next(mb)) {
355 len -= mbuf_len(mb);
356 }
357
358 error = split_one_mbuf(mb, len, tail, join);
359
360 return error;
361 }
362
363 mbuf_t
gss_join_mbuf(mbuf_t head,mbuf_t body,mbuf_t tail)364 gss_join_mbuf(mbuf_t head, mbuf_t body, mbuf_t tail)
365 {
366 mbuf_t mb;
367
368 for (mb = head; mb && mbuf_next(mb); mb = mbuf_next(mb)) {
369 ;
370 }
371 if (mb) {
372 mbuf_setnext(mb, body);
373 }
374 for (mb = body; mb && mbuf_next(mb); mb = mbuf_next(mb)) {
375 ;
376 }
377 if (mb) {
378 mbuf_setnext(mb, tail);
379 }
380 mb = head ? head : (body ? body : tail);
381 return mb;
382 }
383
384 /*
385 * Prepend size bytes to the mbuf chain.
386 */
387 errno_t
gss_prepend_mbuf(mbuf_t * chain,uint8_t * bytes,size_t size)388 gss_prepend_mbuf(mbuf_t *chain, uint8_t *bytes, size_t size)
389 {
390 uint8_t *data = mbuf_data(*chain);
391 size_t leading = mbuf_leadingspace(*chain);
392 size_t trailing = mbuf_trailingspace(*chain);
393 size_t mlen = mbuf_len(*chain);
394 errno_t error;
395
396 if (size > leading && size <= leading + trailing) {
397 data = memmove(data + size - leading, data, mlen);
398 mbuf_setdata(*chain, data, mlen);
399 }
400
401 error = mbuf_prepend(chain, size, MBUF_WAITOK);
402 if (error) {
403 return error;
404 }
405 data = mbuf_data(*chain);
406 memcpy(data, bytes, size);
407
408 return 0;
409 }
410
411 errno_t
gss_append_mbuf(mbuf_t chain,uint8_t * bytes,size_t size)412 gss_append_mbuf(mbuf_t chain, uint8_t *bytes, size_t size)
413 {
414 size_t len = 0;
415 mbuf_t mb;
416
417 if (chain == NULL) {
418 return EINVAL;
419 }
420
421 for (mb = chain; mb; mb = mbuf_next(mb)) {
422 len += mbuf_len(mb);
423 }
424
425 return mbuf_copyback(chain, len, size, bytes, MBUF_WAITOK);
426 }
427
428 errno_t
gss_strip_mbuf(mbuf_t chain,int size)429 gss_strip_mbuf(mbuf_t chain, int size)
430 {
431 if (chain == NULL) {
432 return EINVAL;
433 }
434
435 mbuf_adj(chain, size);
436
437 return 0;
438 }
439
440
441 /*
442 * Kerberos mech generic crypto support for mbufs
443 */
444
445 /*
446 * Walk the mbuf after the given offset calling the passed in crypto function
447 * for len bytes. Note the length, len should be a multiple of the blocksize and
448 * there should be at least len bytes available after the offset in the mbuf chain.
449 * padding should be done before calling this routine.
450 */
451 int
mbuf_walk(mbuf_t mbp,size_t offset,size_t len,size_t blocksize,int (* crypto_fn)(void *,uint8_t * data,size_t length),void * ctx)452 mbuf_walk(mbuf_t mbp, size_t offset, size_t len, size_t blocksize, int (*crypto_fn)(void *, uint8_t *data, size_t length), void *ctx)
453 {
454 mbuf_t mb;
455 size_t mlen, residue;
456 uint8_t *ptr;
457 int error = 0;
458
459 /* Move to the start of the chain */
460 for (mb = mbp; mb && len > 0; mb = mbuf_next(mb)) {
461 ptr = mbuf_data(mb);
462 mlen = mbuf_len(mb);
463 if (offset >= mlen) {
464 /* Offset not yet reached */
465 offset -= mlen;
466 continue;
467 }
468 /* Found starting point in chain */
469 ptr += offset;
470 mlen -= offset;
471 offset = 0;
472
473 /*
474 * Handle the data in this mbuf. If the length to
475 * walk is less than the data in the mbuf, set
476 * the mbuf length left to be the length left
477 */
478 mlen = mlen < len ? mlen : len;
479 /* Figure out how much is a multple of blocksize */
480 residue = mlen % blocksize;
481 /* And addjust the mleft length to be the largest multiple of blocksized */
482 mlen -= residue;
483 /* run our hash/encrypt/decrpyt function */
484 if (mlen > 0) {
485 error = crypto_fn(ctx, ptr, mlen);
486 if (error) {
487 break;
488 }
489 ptr += mlen;
490 len -= mlen;
491 }
492 /*
493 * If we have a residue then to get a full block for our crypto
494 * function, we need to copy the residue into our block size
495 * block and use the next mbuf to get the rest of the data for
496 * the block. N.B. We generally assume that from the offset
497 * passed in, that the total length, len, is a multple of
498 * blocksize and that there are at least len bytes in the chain
499 * from the offset. We also assume there is at least (blocksize
500 * - residue) size data in any next mbuf for residue > 0. If not
501 * we attemp to pullup bytes from down the chain.
502 */
503 if (residue) {
504 mbuf_t nmb = mbuf_next(mb);
505 uint8_t *nptr = NULL, *block = NULL;
506
507 block = kalloc_data(blocksize, Z_WAITOK | Z_ZERO);
508 if (block == NULL) {
509 return ENOMEM;
510 }
511 assert(nmb);
512 len -= residue;
513 offset = blocksize - residue;
514 if (len < offset) {
515 offset = len;
516 /*
517 * We don't have enough bytes so zero the block
518 * so that any trailing bytes will be zero.
519 */
520 cc_clear(blocksize, block);
521 }
522 memcpy(block, ptr, residue);
523 if (len && nmb) {
524 mlen = mbuf_len(nmb);
525 if (mlen < offset) {
526 error = mbuf_pullup(&nmb, offset - mlen);
527 if (error) {
528 mbuf_setnext(mb, NULL);
529 kfree_data(block, blocksize);
530 return error;
531 }
532 }
533 nptr = mbuf_data(nmb);
534 memcpy(block + residue, nptr, offset);
535 }
536 len -= offset;
537 error = crypto_fn(ctx, block, blocksize);
538 if (error) {
539 kfree_data(block, blocksize);
540 break;
541 }
542 memcpy(ptr, block, residue);
543 if (nptr) {
544 memcpy(nptr, block + residue, offset);
545 }
546 kfree_data(block, blocksize);
547 }
548 }
549
550 return error;
551 }
552
553 void
do_crypt_init(crypt_walker_ctx_t wctx,int encrypt,crypto_ctx_t cctx,cccbc_ctx * ks)554 do_crypt_init(crypt_walker_ctx_t wctx, int encrypt, crypto_ctx_t cctx, cccbc_ctx *ks)
555 {
556 memset(wctx, 0, sizeof(*wctx));
557 wctx->length = 0;
558 wctx->ccmode = encrypt ? cctx->enc_mode : cctx->dec_mode;
559 wctx->crypt_ctx = ks;
560 wctx->iv = kalloc_data(wctx->ccmode->block_size, Z_WAITOK | Z_ZERO);
561 cccbc_set_iv(wctx->ccmode, wctx->iv, NULL);
562 }
563
564 int
do_crypt(void * walker,uint8_t * data,size_t len)565 do_crypt(void *walker, uint8_t *data, size_t len)
566 {
567 struct crypt_walker_ctx *wctx = (crypt_walker_ctx_t)walker;
568 size_t nblocks;
569
570 nblocks = len / wctx->ccmode->block_size;
571 assert(len % wctx->ccmode->block_size == 0);
572 cccbc_update(wctx->ccmode, wctx->crypt_ctx, wctx->iv, nblocks, data, data);
573 wctx->length += len;
574
575 return 0;
576 }
577
578 void
do_hmac_init(hmac_walker_ctx_t wctx,crypto_ctx_t cctx,void * key)579 do_hmac_init(hmac_walker_ctx_t wctx, crypto_ctx_t cctx, void *key)
580 {
581 size_t alloc_size = cchmac_di_size(cctx->di);
582
583 wctx->di = cctx->di;
584 wctx->hmac_ctx = kalloc_data(alloc_size, Z_WAITOK | Z_ZERO);
585 cchmac_init(cctx->di, wctx->hmac_ctx, cctx->keylen, key);
586 }
587
588 int
do_hmac(void * walker,uint8_t * data,size_t len)589 do_hmac(void *walker, uint8_t *data, size_t len)
590 {
591 hmac_walker_ctx_t wctx = (hmac_walker_ctx_t)walker;
592
593 cchmac_update(wctx->di, wctx->hmac_ctx, len, data);
594
595 return 0;
596 }
597
598 void
do_hmac_destroy(hmac_walker_ctx_t wctx,crypto_ctx_t cctx)599 do_hmac_destroy(hmac_walker_ctx_t wctx, crypto_ctx_t cctx)
600 {
601 size_t alloc_size = cchmac_di_size(cctx->di);
602 kfree_data(wctx->hmac_ctx, alloc_size);
603 }
604
605 int
krb5_mic(crypto_ctx_t ctx,gss_buffer_t header,gss_buffer_t bp,gss_buffer_t trailer,uint8_t * mic,int * verify,int ikey,int reverse)606 krb5_mic(crypto_ctx_t ctx, gss_buffer_t header, gss_buffer_t bp, gss_buffer_t trailer, uint8_t *mic, int *verify, int ikey, int reverse)
607 {
608 uint8_t *digest = NULL;
609 cchmac_di_decl(ctx->di, hmac_ctx);
610 int kdx = (verify == NULL) ? (reverse ? GSS_RCV : GSS_SND) : (reverse ? GSS_SND : GSS_RCV);
611 void *key2use;
612
613 digest = kalloc_data(ctx->di->output_size, Z_WAITOK | Z_ZERO);
614 if (digest == NULL) {
615 return ENOMEM;
616 }
617 if (ikey) {
618 if (!(ctx->flags & CRYPTO_KS_ALLOCED)) {
619 lck_mtx_lock(&ctx->lock);
620 if (!(ctx->flags & CRYPTO_KS_ALLOCED)) {
621 cc_key_schedule_create(ctx);
622 }
623 ctx->flags |= CRYPTO_KS_ALLOCED;
624 lck_mtx_unlock(&ctx->lock);
625 }
626 key2use = ctx->ks.ikeys[kdx].key_val;
627 } else {
628 key2use = ctx->ckeys[kdx].key_val;
629 }
630
631 cchmac_init(ctx->di, hmac_ctx, ctx->keylen, key2use);
632
633 if (header) {
634 cchmac_update(ctx->di, hmac_ctx, header->length, header->value);
635 }
636
637 cchmac_update(ctx->di, hmac_ctx, bp->length, bp->value);
638
639 if (trailer) {
640 cchmac_update(ctx->di, hmac_ctx, trailer->length, trailer->value);
641 }
642
643 cchmac_final(ctx->di, hmac_ctx, digest);
644
645 if (verify) {
646 *verify = (memcmp(mic, digest, ctx->digest_size) == 0);
647 } else {
648 memcpy(mic, digest, ctx->digest_size);
649 }
650
651 kfree_data(digest, ctx->di->output_size);
652 return 0;
653 }
654
655 int
krb5_mic_mbuf(crypto_ctx_t ctx,gss_buffer_t header,mbuf_t mbp,size_t offset,size_t len,gss_buffer_t trailer,uint8_t * mic,int * verify,int ikey,int reverse)656 krb5_mic_mbuf(crypto_ctx_t ctx, gss_buffer_t header,
657 mbuf_t mbp, size_t offset, size_t len, gss_buffer_t trailer, uint8_t *mic, int *verify, int ikey, int reverse)
658 {
659 struct hmac_walker_ctx wctx;
660 uint8_t *digest = NULL;
661 int error;
662 int kdx = (verify == NULL) ? (reverse ? GSS_RCV : GSS_SND) : (reverse ? GSS_SND : GSS_RCV);
663 void *key2use;
664
665 digest = kalloc_data(ctx->di->output_size, Z_WAITOK | Z_ZERO);
666 if (digest == NULL) {
667 return ENOMEM;
668 }
669 if (ikey) {
670 if (!(ctx->flags & CRYPTO_KS_ALLOCED)) {
671 lck_mtx_lock(&ctx->lock);
672 if (!(ctx->flags & CRYPTO_KS_ALLOCED)) {
673 cc_key_schedule_create(ctx);
674 }
675 ctx->flags |= CRYPTO_KS_ALLOCED;
676 lck_mtx_unlock(&ctx->lock);
677 }
678 key2use = ctx->ks.ikeys[kdx].key_val;
679 } else {
680 key2use = ctx->ckeys[kdx].key_val;
681 }
682
683 do_hmac_init(&wctx, ctx, key2use);
684
685 if (header) {
686 cchmac_update(ctx->di, wctx.hmac_ctx, header->length, header->value);
687 }
688
689 error = mbuf_walk(mbp, offset, len, 1, do_hmac, &wctx);
690
691 if (error) {
692 kfree_data(digest, ctx->di->output_size);
693 return error;
694 }
695 if (trailer) {
696 cchmac_update(ctx->di, wctx.hmac_ctx, trailer->length, trailer->value);
697 }
698
699 cchmac_final(ctx->di, wctx.hmac_ctx, digest);
700 do_hmac_destroy(&wctx, ctx);
701
702 if (verify) {
703 *verify = (memcmp(mic, digest, ctx->digest_size) == 0);
704 if (!*verify) {
705 kfree_data(digest, ctx->di->output_size);
706 return EBADRPC;
707 }
708 } else {
709 memcpy(mic, digest, ctx->digest_size);
710 }
711
712 kfree_data(digest, ctx->di->output_size);
713 return 0;
714 }
715
716 errno_t
717 /* __attribute__((optnone)) */
krb5_crypt_mbuf(crypto_ctx_t ctx,mbuf_t * mbp,size_t len,int encrypt,cccbc_ctx * ks)718 krb5_crypt_mbuf(crypto_ctx_t ctx, mbuf_t *mbp, size_t len, int encrypt, cccbc_ctx *ks)
719 {
720 struct crypt_walker_ctx wctx;
721 const struct ccmode_cbc *ccmode = encrypt ? ctx->enc_mode : ctx->dec_mode;
722 size_t plen = len;
723 size_t cts_len = 0;
724 mbuf_t mb, lmb = NULL;
725 int error;
726
727 if (!(ctx->flags & CRYPTO_KS_ALLOCED)) {
728 lck_mtx_lock(&ctx->lock);
729 if (!(ctx->flags & CRYPTO_KS_ALLOCED)) {
730 cc_key_schedule_create(ctx);
731 }
732 ctx->flags |= CRYPTO_KS_ALLOCED;
733 lck_mtx_unlock(&ctx->lock);
734 }
735 if (!ks) {
736 ks = encrypt ? ctx->ks.enc : ctx->ks.dec;
737 }
738
739 if ((ctx->flags & CRYPTO_CTS_ENABLE) && ctx->mpad == 1) {
740 uint8_t *block = NULL;
741
742 block = kalloc_data(ccmode->block_size, Z_WAITOK | Z_ZERO);
743 if (block == NULL) {
744 return ENOMEM;
745 }
746 /* if the length is less than or equal to a blocksize. We just encrypt the block */
747 if (len <= ccmode->block_size) {
748 if (len < ccmode->block_size) {
749 gss_append_mbuf(*mbp, block, ccmode->block_size);
750 }
751 plen = ccmode->block_size;
752 } else {
753 /* determine where the last two blocks are */
754 size_t r = len % ccmode->block_size;
755
756 cts_len = r ? r + ccmode->block_size : 2 * ccmode->block_size;
757 plen = len - cts_len;
758 /* If plen is 0 we only have two blocks to crypt with ccpad below */
759 if (plen == 0) {
760 lmb = *mbp;
761 } else {
762 gss_normalize_mbuf(*mbp, 0, &plen, &mb, &lmb, 0);
763 assert(*mbp == mb);
764 assert(plen == len - cts_len);
765 assert(gss_mbuf_len(mb, 0) == plen);
766 assert(gss_mbuf_len(lmb, 0) == cts_len);
767 }
768 }
769 kfree_data(block, ccmode->block_size);
770 } else if (len % ctx->mpad) {
771 uint8_t *pad_block = NULL;
772 size_t padlen = ctx->mpad - (len % ctx->mpad);
773
774 pad_block = kalloc_data(ctx->mpad, Z_WAITOK | Z_ZERO);
775 if (pad_block == NULL) {
776 return ENOMEM;
777 }
778 error = gss_append_mbuf(*mbp, pad_block, padlen);
779 if (error) {
780 kfree_data(pad_block, ctx->mpad);
781 return error;
782 }
783 plen = len + padlen;
784 kfree_data(pad_block, ctx->mpad);
785 }
786 do_crypt_init(&wctx, encrypt, ctx, ks);
787 if (plen) {
788 error = mbuf_walk(*mbp, 0, plen, ccmode->block_size, do_crypt, &wctx);
789 if (error) {
790 return error;
791 }
792 }
793
794 if ((ctx->flags & CRYPTO_CTS_ENABLE) && cts_len) {
795 uint8_t *cts_pad = NULL;
796 ccpad_func do_ccpad = encrypt ? ccpad_cts3_encrypt : ccpad_cts3_decrypt;
797
798 cts_pad = kalloc_data(2 * ccmode->block_size, Z_WAITOK | Z_ZERO);
799 if (cts_pad == NULL) {
800 return ENOMEM;
801 }
802 assert(cts_len <= 2 * ccmode->block_size && cts_len > ccmode->block_size);
803 mbuf_copydata(lmb, 0, cts_len, cts_pad);
804 mbuf_freem(lmb);
805 do_ccpad(ccmode, wctx.crypt_ctx, wctx.iv, cts_len, cts_pad, cts_pad);
806 gss_append_mbuf(*mbp, cts_pad, cts_len);
807 kfree_data(cts_pad, 2 * ccmode->block_size);
808 }
809 kfree_data(wctx.iv, wctx.ccmode->block_size);
810
811 return 0;
812 }
813
814 /*
815 * Key derivation routines
816 */
817
818 static int
rr13(unsigned char * buf,size_t len)819 rr13(unsigned char *buf, size_t len)
820 {
821 size_t bytes = (len + 7) / 8;
822 unsigned char *tmp = NULL;
823 size_t i;
824
825 if (len == 0) {
826 return 0;
827 }
828
829 tmp = kalloc_data(bytes, Z_WAITOK | Z_ZERO);
830
831 {
832 const int bits = 13 % len;
833 const int lbit = len % 8;
834
835 memcpy(tmp, buf, bytes);
836 if (lbit) {
837 /* pad final byte with inital bits */
838 tmp[bytes - 1] &= 0xff << (8 - lbit);
839 for (i = lbit; i < 8; i += len) {
840 tmp[bytes - 1] |= buf[0] >> i;
841 }
842 }
843 for (i = 0; i < bytes; i++) {
844 ssize_t bb;
845 ssize_t b1, s1, b2, s2;
846
847 /* calculate first bit position of this byte */
848 bb = 8 * i - bits;
849 while (bb < 0) {
850 bb += len;
851 }
852 /* byte offset and shift count */
853 b1 = bb / 8;
854 s1 = bb % 8;
855 if ((size_t)bb + 8 > bytes * 8) {
856 /* watch for wraparound */
857 s2 = (len + 8 - s1) % 8;
858 } else {
859 s2 = 8 - s1;
860 }
861 b2 = (b1 + 1) % bytes;
862 buf[i] = 0xff & ((tmp[b1] << s1) | (tmp[b2] >> s2));
863 }
864 }
865 kfree_data(tmp, bytes);
866 return 0;
867 }
868
869
870 /* Add `b' to `a', both being one's complement numbers. */
871 static void
add1(unsigned char * a,unsigned char * b,size_t len)872 add1(unsigned char *a, unsigned char *b, size_t len)
873 {
874 ssize_t i;
875 int carry = 0;
876
877 for (i = len - 1; i >= 0; i--) {
878 int x = a[i] + b[i] + carry;
879 carry = x > 0xff;
880 a[i] = x & 0xff;
881 }
882 for (i = len - 1; carry && i >= 0; i--) {
883 int x = a[i] + carry;
884 carry = x > 0xff;
885 a[i] = x & 0xff;
886 }
887 }
888
889
890 static int
krb5_n_fold(const void * instr,size_t len,void * foldstr,size_t size)891 krb5_n_fold(const void *instr, size_t len, void *foldstr, size_t size)
892 {
893 /* if len < size we need at most N * len bytes, ie < 2 * size;
894 * if len > size we need at most 2 * len */
895 int ret = 0;
896 size_t maxlen = 2 * lmax(size, len);
897 size_t l = 0;
898 unsigned char *tmp = NULL;
899 unsigned char *buf = NULL;
900
901 tmp = kalloc_data(maxlen, Z_WAITOK | Z_ZERO);
902 buf = kalloc_data(len, Z_WAITOK | Z_ZERO);
903
904 memcpy(buf, instr, len);
905 memset(foldstr, 0, size);
906 do {
907 memcpy(tmp + l, buf, len);
908 l += len;
909 ret = rr13(buf, len * 8);
910 if (ret) {
911 goto out;
912 }
913 while (l >= size) {
914 add1(foldstr, tmp, size);
915 l -= size;
916 if (l == 0) {
917 break;
918 }
919 memmove(tmp, tmp + size, l);
920 }
921 } while (l != 0);
922 out:
923
924 kfree_data(tmp, maxlen);
925 kfree_data(buf, len);
926 return ret;
927 }
928
929 void
krb5_make_usage(uint32_t usage_no,uint8_t suffix,uint8_t usage_string[KRB5_USAGE_LEN])930 krb5_make_usage(uint32_t usage_no, uint8_t suffix, uint8_t usage_string[KRB5_USAGE_LEN])
931 {
932 uint32_t i;
933
934 for (i = 0; i < 4; i++) {
935 usage_string[i] = ((usage_no >> 8 * (3 - i)) & 0xff);
936 }
937 usage_string[i] = suffix;
938 }
939
940 void
krb5_key_derivation(crypto_ctx_t ctx,const void * cons,size_t conslen,krb5_key_t * dkey,size_t dklen)941 krb5_key_derivation(crypto_ctx_t ctx, const void *cons, size_t conslen, krb5_key_t *dkey, size_t dklen)
942 {
943 size_t blocksize = ctx->enc_mode->block_size;
944 cccbc_iv_decl(blocksize, iv);
945 cccbc_ctx_decl(ctx->enc_mode->size, enc_ctx);
946 size_t ksize = 8 * dklen;
947 size_t nblocks = (ksize + 8 * blocksize - 1) / (8 * blocksize);
948 uint8_t *dkptr;
949 uint8_t *block = NULL;
950
951 block = kalloc_data(blocksize, Z_WAITOK | Z_ZERO);
952 gss_krb5_key_set(dkey, kalloc_data(nblocks * blocksize, Z_WAITOK | Z_ZERO), nblocks * blocksize);
953 dkptr = dkey->key_val;
954
955 krb5_n_fold(cons, conslen, block, blocksize);
956 cccbc_init(ctx->enc_mode, enc_ctx, ctx->keylen, ctx->key);
957 for (size_t i = 0; i < nblocks; i++) {
958 cccbc_set_iv(ctx->enc_mode, iv, NULL);
959 cccbc_update(ctx->enc_mode, enc_ctx, iv, 1, block, block);
960 memcpy(dkptr, block, blocksize);
961 dkptr += blocksize;
962 }
963 kfree_data(block, blocksize);
964 }
965
966 static void
des_make_key(const uint8_t rawkey[7],uint8_t deskey[8])967 des_make_key(const uint8_t rawkey[7], uint8_t deskey[8])
968 {
969 uint8_t val = 0;
970
971 memcpy(deskey, rawkey, 7);
972 for (int i = 0; i < 7; i++) {
973 val |= ((deskey[i] & 1) << (i + 1));
974 }
975 deskey[7] = val;
976 ccdes_key_set_odd_parity(deskey, 8);
977 }
978
979 static void
krb5_3des_key_derivation(crypto_ctx_t ctx,const void * cons,size_t conslen,krb5_key_t * des3key)980 krb5_3des_key_derivation(crypto_ctx_t ctx, const void *cons, size_t conslen, krb5_key_t *des3key)
981 {
982 const struct ccmode_cbc *cbcmode = ctx->enc_mode;
983 krb5_key_t rawkey;
984 size_t rawkey_len;
985 uint8_t *kptr, *rptr;
986
987 gss_krb5_key_set(des3key, kalloc_data(3 * cbcmode->block_size, Z_WAITOK | Z_ZERO), 3 * cbcmode->block_size);
988 rawkey_len = 3 * (cbcmode->block_size - 1);
989 krb5_key_derivation(ctx, cons, conslen, &rawkey, rawkey_len);
990 kptr = des3key->key_val;
991 rptr = rawkey.key_val;
992
993 for (int i = 0; i < 3; i++) {
994 des_make_key(rptr, kptr);
995 rptr += cbcmode->block_size - 1;
996 kptr += cbcmode->block_size;
997 }
998
999 gss_krb5_key_free(&rawkey, 1);
1000 }
1001
1002 /*
1003 * Create a key schecule
1004 *
1005 */
1006 void
cc_key_schedule_create(crypto_ctx_t ctx)1007 cc_key_schedule_create(crypto_ctx_t ctx)
1008 {
1009 uint8_t usage_string[KRB5_USAGE_LEN];
1010 lucid_context_t lctx = ctx->gss_ctx;
1011 krb5_key_t ekey;
1012
1013 switch (lctx->key_data.proto) {
1014 case 0: {
1015 if (ctx->ks.enc == NULL) {
1016 ctx->ks.enc = kalloc_data(ctx->enc_mode->size, Z_WAITOK | Z_ZERO);
1017 cccbc_init(ctx->enc_mode, ctx->ks.enc, ctx->keylen, ctx->key);
1018 }
1019 if (ctx->ks.dec == NULL) {
1020 ctx->ks.dec = kalloc_data(ctx->dec_mode->size, Z_WAITOK | Z_ZERO);
1021 cccbc_init(ctx->dec_mode, ctx->ks.dec, ctx->keylen, ctx->key);
1022 }
1023 }
1024 OS_FALLTHROUGH;
1025 case 1: {
1026 if (ctx->ks.enc == NULL) {
1027 krb5_make_usage(lctx->initiate ?
1028 KRB5_USAGE_INITIATOR_SEAL : KRB5_USAGE_ACCEPTOR_SEAL,
1029 0xAA, usage_string);
1030 krb5_key_derivation(ctx, usage_string, KRB5_USAGE_LEN, &ekey, ctx->keylen);
1031 ctx->ks.enc = kalloc_data(ctx->enc_mode->size, Z_WAITOK | Z_ZERO);
1032 cccbc_init(ctx->enc_mode, ctx->ks.enc, ctx->keylen, ekey.key_val);
1033 gss_krb5_key_free(&ekey, 1);
1034 }
1035 if (ctx->ks.dec == NULL) {
1036 krb5_make_usage(lctx->initiate ?
1037 KRB5_USAGE_ACCEPTOR_SEAL : KRB5_USAGE_INITIATOR_SEAL,
1038 0xAA, usage_string);
1039 krb5_key_derivation(ctx, usage_string, KRB5_USAGE_LEN, &ekey, ctx->keylen);
1040 ctx->ks.dec = kalloc_data(ctx->dec_mode->size, Z_WAITOK | Z_ZERO);
1041 cccbc_init(ctx->dec_mode, ctx->ks.dec, ctx->keylen, ekey.key_val);
1042 gss_krb5_key_free(&ekey, 1);
1043 }
1044 if (ctx->ks.ikeys[GSS_SND].key_val == NULL) {
1045 krb5_make_usage(lctx->initiate ?
1046 KRB5_USAGE_INITIATOR_SEAL : KRB5_USAGE_ACCEPTOR_SEAL,
1047 0x55, usage_string);
1048 krb5_key_derivation(ctx, usage_string, KRB5_USAGE_LEN, &ctx->ks.ikeys[GSS_SND], ctx->keylen);
1049 }
1050 if (ctx->ks.ikeys[GSS_RCV].key_val == NULL) {
1051 krb5_make_usage(lctx->initiate ?
1052 KRB5_USAGE_ACCEPTOR_SEAL : KRB5_USAGE_INITIATOR_SEAL,
1053 0x55, usage_string);
1054 krb5_key_derivation(ctx, usage_string, KRB5_USAGE_LEN, &ctx->ks.ikeys[GSS_RCV], ctx->keylen);
1055 }
1056 }
1057 }
1058 }
1059
1060 void
gss_crypto_ctx_free(crypto_ctx_t ctx)1061 gss_crypto_ctx_free(crypto_ctx_t ctx)
1062 {
1063 lck_mtx_destroy(&ctx->lock, &gss_krb5_mech_grp);
1064
1065 gss_krb5_key_ctx_free(&ctx->ks.ikeys[GSS_SND], ctx->key);
1066 gss_krb5_key_ctx_free(&ctx->ks.ikeys[GSS_RCV], ctx->key);
1067 if (ctx->ks.enc) {
1068 cccbc_ctx_clear(ctx->enc_mode->size, ctx->ks.enc);
1069 kfree_data(ctx->ks.enc, ctx->enc_mode->size);
1070 }
1071 if (ctx->ks.dec) {
1072 cccbc_ctx_clear(ctx->dec_mode->size, ctx->ks.dec);
1073 kfree_data(ctx->ks.dec, ctx->dec_mode->size);
1074 }
1075 gss_krb5_key_ctx_free(&ctx->ckeys[GSS_SND], ctx->key);
1076 gss_krb5_key_ctx_free(&ctx->ckeys[GSS_RCV], ctx->key);
1077 ctx->key = NULL;
1078 ctx->keylen = 0;
1079 }
1080
1081 int
gss_crypto_ctx_init(struct crypto_ctx * ctx,lucid_context_t lucid)1082 gss_crypto_ctx_init(struct crypto_ctx *ctx, lucid_context_t lucid)
1083 {
1084 ctx->gss_ctx = lucid;
1085 void *key;
1086 uint8_t usage_string[KRB5_USAGE_LEN];
1087
1088 ctx->keylen = ctx->gss_ctx->ctx_key.key.key_len;
1089 key = ctx->gss_ctx->ctx_key.key.key_val;
1090 ctx->etype = ctx->gss_ctx->ctx_key.etype;
1091 ctx->key = key;
1092
1093 switch (ctx->etype) {
1094 case AES128_CTS_HMAC_SHA1_96:
1095 case AES256_CTS_HMAC_SHA1_96:
1096 ctx->enc_mode = ccaes_cbc_encrypt_mode();
1097 assert(ctx->enc_mode);
1098 ctx->dec_mode = ccaes_cbc_decrypt_mode();
1099 assert(ctx->dec_mode);
1100 ctx->ks.enc = NULL;
1101 ctx->ks.dec = NULL;
1102 ctx->di = ccsha1_di();
1103 assert(ctx->di);
1104 ctx->flags = CRYPTO_CTS_ENABLE;
1105 ctx->mpad = 1;
1106 ctx->digest_size = 12; /* 96 bits */
1107 krb5_make_usage(ctx->gss_ctx->initiate ?
1108 KRB5_USAGE_INITIATOR_SIGN : KRB5_USAGE_ACCEPTOR_SIGN,
1109 0x99, usage_string);
1110 krb5_key_derivation(ctx, usage_string, KRB5_USAGE_LEN, &ctx->ckeys[GSS_SND], ctx->keylen);
1111 krb5_make_usage(ctx->gss_ctx->initiate ?
1112 KRB5_USAGE_ACCEPTOR_SIGN : KRB5_USAGE_INITIATOR_SIGN,
1113 0x99, usage_string);
1114 krb5_key_derivation(ctx, usage_string, KRB5_USAGE_LEN, &ctx->ckeys[GSS_RCV], ctx->keylen);
1115 break;
1116 case DES3_CBC_SHA1_KD:
1117 ctx->enc_mode = ccdes3_cbc_encrypt_mode();
1118 assert(ctx->enc_mode);
1119 ctx->dec_mode = ccdes3_cbc_decrypt_mode();
1120 assert(ctx->dec_mode);
1121 gss_krb5_key_set(&ctx->ks.ikeys[GSS_SND], ctx->key, ctx->keylen);
1122 gss_krb5_key_set(&ctx->ks.ikeys[GSS_RCV], ctx->key, ctx->keylen);
1123 ctx->di = ccsha1_di();
1124 assert(ctx->di);
1125 ctx->flags = 0;
1126 ctx->mpad = ctx->enc_mode->block_size;
1127 ctx->digest_size = 20; /* 160 bits */
1128 krb5_make_usage(KRB5_USAGE_ACCEPTOR_SIGN, 0x99, usage_string);
1129 krb5_3des_key_derivation(ctx, usage_string, KRB5_USAGE_LEN, &ctx->ckeys[GSS_SND]);
1130 krb5_3des_key_derivation(ctx, usage_string, KRB5_USAGE_LEN, &ctx->ckeys[GSS_RCV]);
1131 break;
1132 default:
1133 return ENOTSUP;
1134 }
1135
1136 lck_mtx_init(&ctx->lock, &gss_krb5_mech_grp, LCK_ATTR_NULL);
1137
1138 return 0;
1139 }
1140
1141 /*
1142 * CFX gss support routines
1143 */
1144 /* From Heimdal cfx.h file RFC 4121 Cryptoo framework extensions */
1145 typedef struct gss_cfx_mic_token_desc_struct {
1146 uint8_t TOK_ID[2]; /* 04 04 */
1147 uint8_t Flags;
1148 uint8_t Filler[5];
1149 uint8_t SND_SEQ[8];
1150 } gss_cfx_mic_token_desc, *gss_cfx_mic_token;
1151
1152 typedef struct gss_cfx_wrap_token_desc_struct {
1153 uint8_t TOK_ID[2]; /* 05 04 */
1154 uint8_t Flags;
1155 uint8_t Filler;
1156 uint8_t EC[2];
1157 uint8_t RRC[2];
1158 uint8_t SND_SEQ[8];
1159 } gss_cfx_wrap_token_desc, *gss_cfx_wrap_token;
1160
1161 /* End of cfx.h file */
1162
1163 #define CFXSentByAcceptor (1 << 0)
1164 #define CFXSealed (1 << 1)
1165 #define CFXAcceptorSubkey (1 << 2)
1166
1167 const gss_cfx_mic_token_desc mic_cfx_token = {
1168 .TOK_ID = "\x04\x04",
1169 .Flags = 0,
1170 .Filler = "\xff\xff\xff\xff\xff",
1171 .SND_SEQ = "\x00\x00\x00\x00\x00\x00\x00\x00"
1172 };
1173
1174 const gss_cfx_wrap_token_desc wrap_cfx_token = {
1175 .TOK_ID = "\x05\04",
1176 .Flags = 0,
1177 .Filler = '\xff',
1178 .EC = "\x00\x00",
1179 .RRC = "\x00\x00",
1180 .SND_SEQ = "\x00\x00\x00\x00\x00\x00\x00\x00"
1181 };
1182
1183 static int
gss_krb5_cfx_verify_mic_token(gss_ctx_id_t ctx,gss_cfx_mic_token token)1184 gss_krb5_cfx_verify_mic_token(gss_ctx_id_t ctx, gss_cfx_mic_token token)
1185 {
1186 int i;
1187 lucid_context_t lctx = &ctx->gss_lucid_ctx;
1188 uint8_t flags = 0;
1189
1190 if (token->TOK_ID[0] != mic_cfx_token.TOK_ID[0] || token->TOK_ID[1] != mic_cfx_token.TOK_ID[1]) {
1191 printf("Bad mic TOK_ID %x %x\n", token->TOK_ID[0], token->TOK_ID[1]);
1192 return EBADRPC;
1193 }
1194 if (lctx->initiate) {
1195 flags |= CFXSentByAcceptor;
1196 }
1197 if (lctx->key_data.lucid_protocol_u.data_4121.acceptor_subkey) {
1198 flags |= CFXAcceptorSubkey;
1199 }
1200 if (token->Flags != flags) {
1201 printf("Bad flags received %x exptect %x\n", token->Flags, flags);
1202 return EBADRPC;
1203 }
1204 for (i = 0; i < 5; i++) {
1205 if (token->Filler[i] != mic_cfx_token.Filler[i]) {
1206 break;
1207 }
1208 }
1209
1210 if (i != 5) {
1211 printf("Bad mic filler %x @ %d\n", token->Filler[i], i);
1212 return EBADRPC;
1213 }
1214
1215 return 0;
1216 }
1217
1218 uint32_t
gss_krb5_cfx_get_mic(uint32_t * minor,gss_ctx_id_t ctx,gss_qop_t qop __unused,gss_buffer_t mbp,gss_buffer_t mic)1219 gss_krb5_cfx_get_mic(uint32_t *minor, /* minor_status */
1220 gss_ctx_id_t ctx, /* context_handle */
1221 gss_qop_t qop __unused, /* qop_req (ignored) */
1222 gss_buffer_t mbp, /* message mbuf */
1223 gss_buffer_t mic /* message_token */)
1224 {
1225 gss_cfx_mic_token_desc token;
1226 lucid_context_t lctx = &ctx->gss_lucid_ctx;
1227 crypto_ctx_t cctx = &ctx->gss_cryptor;
1228 gss_buffer_desc header;
1229 uint32_t rv;
1230 uint64_t seq = htonll(lctx->send_seq);
1231
1232 if (minor == NULL) {
1233 minor = &rv;
1234 }
1235 *minor = 0;
1236 token = mic_cfx_token;
1237 mic->length = sizeof(token) + cctx->digest_size;
1238 mic->value = kalloc_data(mic->length, Z_WAITOK | Z_ZERO);
1239 if (!lctx->initiate) {
1240 token.Flags |= CFXSentByAcceptor;
1241 }
1242 if (lctx->key_data.lucid_protocol_u.data_4121.acceptor_subkey) {
1243 token.Flags |= CFXAcceptorSubkey;
1244 }
1245 memcpy(&token.SND_SEQ, &seq, sizeof(lctx->send_seq));
1246 lctx->send_seq++; //XXX should only update this below on success? Heimdal seems to do it this way
1247 header.value = &token;
1248 header.length = sizeof(gss_cfx_mic_token_desc);
1249
1250 *minor = krb5_mic(cctx, NULL, mbp, &header, (uint8_t *)mic->value + sizeof(token), NULL, 0, 0);
1251
1252 if (*minor) {
1253 mic->length = 0;
1254 kfree_data(mic->value, mic->length);
1255 } else {
1256 memcpy(mic->value, &token, sizeof(token));
1257 }
1258
1259 return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE;
1260 }
1261
1262 uint32_t
gss_krb5_cfx_get_mic_mbuf(uint32_t * minor,gss_ctx_id_t ctx,gss_qop_t qop __unused,mbuf_t mbp,size_t offset,size_t len,gss_buffer_t mic)1263 gss_krb5_cfx_get_mic_mbuf(uint32_t *minor, /* minor_status */
1264 gss_ctx_id_t ctx, /* context_handle */
1265 gss_qop_t qop __unused, /* qop_req (ignored) */
1266 mbuf_t mbp, /* message mbuf */
1267 size_t offset, /* offest */
1268 size_t len, /* length */
1269 gss_buffer_t mic /* message_token */)
1270 {
1271 gss_cfx_mic_token_desc token;
1272 lucid_context_t lctx = &ctx->gss_lucid_ctx;
1273 crypto_ctx_t cctx = &ctx->gss_cryptor;
1274 uint32_t rv;
1275 uint64_t seq = htonll(lctx->send_seq);
1276 gss_buffer_desc header;
1277
1278 if (minor == NULL) {
1279 minor = &rv;
1280 }
1281 *minor = 0;
1282
1283 token = mic_cfx_token;
1284 mic->length = sizeof(token) + cctx->digest_size;
1285 mic->value = kalloc_data(mic->length, Z_WAITOK | Z_ZERO);
1286 if (!lctx->initiate) {
1287 token.Flags |= CFXSentByAcceptor;
1288 }
1289 if (lctx->key_data.lucid_protocol_u.data_4121.acceptor_subkey) {
1290 token.Flags |= CFXAcceptorSubkey;
1291 }
1292
1293 memcpy(&token.SND_SEQ, &seq, sizeof(lctx->send_seq));
1294 lctx->send_seq++; //XXX should only update this below on success? Heimdal seems to do it this way
1295
1296 header.length = sizeof(token);
1297 header.value = &token;
1298
1299 len = len ? len : gss_mbuf_len(mbp, offset);
1300 *minor = krb5_mic_mbuf(cctx, NULL, mbp, offset, len, &header, (uint8_t *)mic->value + sizeof(token), NULL, 0, 0);
1301
1302 if (*minor) {
1303 mic->length = 0;
1304 kfree_data(mic->value, mic->length);
1305 } else {
1306 memcpy(mic->value, &token, sizeof(token));
1307 }
1308
1309 return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE;
1310 }
1311
1312
1313 uint32_t
gss_krb5_cfx_verify_mic_mbuf(uint32_t * minor,gss_ctx_id_t ctx,mbuf_t mbp,size_t offset,size_t len,gss_buffer_t mic,gss_qop_t * qop)1314 gss_krb5_cfx_verify_mic_mbuf(uint32_t *minor, /* minor_status */
1315 gss_ctx_id_t ctx, /* context_handle */
1316 mbuf_t mbp, /* message_buffer */
1317 size_t offset, /* offset */
1318 size_t len, /* length */
1319 gss_buffer_t mic, /* message_token */
1320 gss_qop_t *qop /* qop_state */)
1321 {
1322 gss_cfx_mic_token token = mic->value;
1323 lucid_context_t lctx = &ctx->gss_lucid_ctx;
1324 crypto_ctx_t cctx = &ctx->gss_cryptor;
1325 uint8_t *digest = (uint8_t *)mic->value + sizeof(gss_cfx_mic_token_desc);
1326 int verified;
1327 uint64_t seq;
1328 uint32_t rv;
1329 gss_buffer_desc header;
1330
1331 if (qop) {
1332 *qop = GSS_C_QOP_DEFAULT;
1333 }
1334
1335 if (minor == NULL) {
1336 minor = &rv;
1337 }
1338
1339 *minor = gss_krb5_cfx_verify_mic_token(ctx, token);
1340 if (*minor) {
1341 return GSS_S_FAILURE;
1342 }
1343
1344 header.length = sizeof(gss_cfx_mic_token_desc);
1345 header.value = mic->value;
1346
1347 *minor = krb5_mic_mbuf(cctx, NULL, mbp, offset, len, &header, digest, &verified, 0, 0);
1348 if (*minor) {
1349 return GSS_S_FAILURE;
1350 }
1351
1352 //XXX errors and such? Sequencing and replay? Not Supported RPCSEC_GSS
1353 memcpy(&seq, token->SND_SEQ, sizeof(uint64_t));
1354 seq = ntohll(seq);
1355 lctx->recv_seq = seq;
1356
1357 return verified ? GSS_S_COMPLETE : GSS_S_BAD_SIG;
1358 }
1359
1360 errno_t
krb5_cfx_crypt_mbuf(crypto_ctx_t ctx,mbuf_t * mbp,size_t * len,int encrypt,int reverse)1361 krb5_cfx_crypt_mbuf(crypto_ctx_t ctx, mbuf_t *mbp, size_t *len, int encrypt, int reverse)
1362 {
1363 const struct ccmode_cbc *ccmode = encrypt ? ctx->enc_mode : ctx->dec_mode;
1364 uint8_t *confounder = NULL;
1365 uint8_t *mpad = NULL;
1366 uint8_t digest[CRYPTO_MAX_DIGSET_SIZE];
1367 size_t tlen, r = 0;
1368 errno_t error;
1369
1370 confounder = kalloc_data(ccmode->block_size, Z_WAITOK | Z_ZERO);
1371 if (confounder == NULL) {
1372 error = ENOMEM;
1373 goto out;
1374 }
1375 if (encrypt) {
1376 assert(ccmode->block_size <= UINT_MAX);
1377 read_random(confounder, (u_int)ccmode->block_size);
1378 error = gss_prepend_mbuf(mbp, confounder, ccmode->block_size);
1379 if (error) {
1380 goto out;
1381 }
1382 tlen = *len + ccmode->block_size;
1383 if (ctx->mpad > 1) {
1384 r = ctx->mpad - (tlen % ctx->mpad);
1385 }
1386 /* We expect that r == 0 from krb5_cfx_wrap */
1387 if (r != 0) {
1388 mpad = kalloc_data(r, Z_WAITOK | Z_ZERO);
1389 if (mpad == NULL) {
1390 error = ENOMEM;
1391 goto out;
1392 }
1393 error = gss_append_mbuf(*mbp, mpad, r);
1394 if (error) {
1395 goto out;
1396 }
1397 }
1398 tlen += r;
1399 error = krb5_mic_mbuf(ctx, NULL, *mbp, 0, tlen, NULL, digest, NULL, 1, 0);
1400 if (error) {
1401 goto out;
1402 }
1403 error = krb5_crypt_mbuf(ctx, mbp, tlen, 1, NULL);
1404 if (error) {
1405 goto out;
1406 }
1407 error = gss_append_mbuf(*mbp, digest, ctx->digest_size);
1408 if (error) {
1409 goto out;
1410 }
1411 *len = tlen + ctx->digest_size;
1412 error = 0;
1413 goto out;
1414 } else {
1415 int verf;
1416 cccbc_ctx *ks = NULL;
1417
1418 if (*len < ctx->digest_size + sizeof(confounder)) {
1419 error = EBADRPC;
1420 goto out;
1421 }
1422 tlen = *len - ctx->digest_size;
1423 /* get the digest */
1424 error = mbuf_copydata(*mbp, tlen, ctx->digest_size, digest);
1425 /* Remove the digest from the mbuffer */
1426 error = gss_strip_mbuf(*mbp, -ctx->digest_size);
1427 if (error) {
1428 goto out;
1429 }
1430
1431 if (reverse) {
1432 /*
1433 * Derive a key schedule that the sender can unwrap with. This
1434 * is so that RPCSEC_GSS can restore encrypted arguments for
1435 * resending. We do that because the RPCSEC_GSS sequence number in
1436 * the rpc header is prepended to the body of the message before wrapping.
1437 */
1438 krb5_key_t ekey;
1439 uint8_t usage_string[KRB5_USAGE_LEN];
1440 lucid_context_t lctx = ctx->gss_ctx;
1441
1442 krb5_make_usage(lctx->initiate ?
1443 KRB5_USAGE_INITIATOR_SEAL : KRB5_USAGE_ACCEPTOR_SEAL,
1444 0xAA, usage_string);
1445 krb5_key_derivation(ctx, usage_string, KRB5_USAGE_LEN, &ekey, ctx->keylen);
1446 ks = kalloc_data(ctx->dec_mode->size, Z_WAITOK | Z_ZERO);
1447 cccbc_init(ctx->dec_mode, ks, ctx->keylen, ekey.key_val);
1448 gss_krb5_key_free(&ekey, 1);
1449 }
1450 error = krb5_crypt_mbuf(ctx, mbp, tlen, 0, ks);
1451 kfree_data(ks, ctx->dec_mode->size);
1452 if (error) {
1453 goto out;
1454 }
1455 error = krb5_mic_mbuf(ctx, NULL, *mbp, 0, tlen, NULL, digest, &verf, 1, reverse);
1456 if (error) {
1457 goto out;
1458 }
1459 if (!verf) {
1460 error = EBADRPC;
1461 goto out;
1462 }
1463 /* strip off the confounder */
1464 assert(ccmode->block_size <= INT_MAX);
1465 error = gss_strip_mbuf(*mbp, (int)ccmode->block_size);
1466 if (error) {
1467 goto out;
1468 }
1469 *len = tlen - ccmode->block_size;
1470 }
1471
1472 error = 0;
1473 out:
1474 kfree_data(mpad, r);
1475 kfree_data(confounder, ccmode->block_size);
1476 return error;
1477 }
1478
1479 uint32_t
gss_krb5_cfx_wrap_mbuf(uint32_t * minor,gss_ctx_id_t ctx,int conf_flag,gss_qop_t qop __unused,mbuf_t * mbp,size_t len,int * conf)1480 gss_krb5_cfx_wrap_mbuf(uint32_t *minor, /* minor_status */
1481 gss_ctx_id_t ctx, /* context_handle */
1482 int conf_flag, /* conf_req_flag */
1483 gss_qop_t qop __unused, /* qop_req */
1484 mbuf_t *mbp, /* input/output message_buffer */
1485 size_t len, /* mbuf chain length */
1486 int *conf /* conf_state */)
1487 {
1488 gss_cfx_wrap_token_desc token;
1489 lucid_context_t lctx = &ctx->gss_lucid_ctx;
1490 crypto_ctx_t cctx = &ctx->gss_cryptor;
1491 int error = 0;
1492 uint32_t mv;
1493 uint64_t seq = htonll(lctx->send_seq);
1494
1495 if (minor == NULL) {
1496 minor = &mv;
1497 }
1498 if (conf) {
1499 *conf = conf_flag;
1500 }
1501
1502 *minor = 0;
1503 token = wrap_cfx_token;
1504 if (!lctx->initiate) {
1505 token.Flags |= CFXSentByAcceptor;
1506 }
1507 if (lctx->key_data.lucid_protocol_u.data_4121.acceptor_subkey) {
1508 token.Flags |= CFXAcceptorSubkey;
1509 }
1510 memcpy(&token.SND_SEQ, &seq, sizeof(uint64_t));
1511 lctx->send_seq++;
1512 if (conf_flag) {
1513 uint8_t *pad = NULL;
1514 size_t plen = 0;
1515
1516 pad = kalloc_data(cctx->mpad, Z_WAITOK | Z_ZERO);
1517 if (pad == NULL) {
1518 *minor = ENOMEM;
1519 return GSS_S_FAILURE;
1520 }
1521 token.Flags |= CFXSealed;
1522 if (cctx->mpad > 1) {
1523 size_t val = cctx->mpad - ((len + sizeof(gss_cfx_wrap_token_desc)) % cctx->mpad);
1524 plen = sizeof(val) > sizeof(uint32_t) ? htonll(val) : htonl(val);
1525 token.EC[0] = ((plen >> 8) & 0xff);
1526 token.EC[1] = (plen & 0xff);
1527 }
1528 if (plen) {
1529 error = gss_append_mbuf(*mbp, pad, plen);
1530 len += plen;
1531 }
1532 if (error == 0) {
1533 error = gss_append_mbuf(*mbp, (uint8_t *)&token, sizeof(gss_cfx_wrap_token_desc));
1534 len += sizeof(gss_cfx_wrap_token_desc);
1535 }
1536 if (error == 0) {
1537 error = krb5_cfx_crypt_mbuf(cctx, mbp, &len, 1, 0);
1538 }
1539 if (error == 0) {
1540 error = gss_prepend_mbuf(mbp, (uint8_t *)&token, sizeof(gss_cfx_wrap_token_desc));
1541 }
1542 kfree_data(pad, cctx->mpad);
1543 } else {
1544 uint8_t digest[CRYPTO_MAX_DIGSET_SIZE];
1545 gss_buffer_desc header;
1546
1547 header.length = sizeof(token);
1548 header.value = &token;
1549
1550 error = krb5_mic_mbuf(cctx, NULL, *mbp, 0, len, &header, digest, NULL, 1, 0);
1551 if (error == 0) {
1552 error = gss_append_mbuf(*mbp, digest, cctx->digest_size);
1553 if (error == 0) {
1554 uint32_t plen = htonl(cctx->digest_size);
1555 memcpy(token.EC, &plen, 2);
1556 error = gss_prepend_mbuf(mbp, (uint8_t *)&token, sizeof(gss_cfx_wrap_token_desc));
1557 }
1558 }
1559 }
1560 if (error) {
1561 *minor = error;
1562 return GSS_S_FAILURE;
1563 }
1564
1565 return GSS_S_COMPLETE;
1566 }
1567
1568 /*
1569 * Given a wrap token the has a rrc, move the trailer back to the end.
1570 */
1571 static void
gss_krb5_cfx_unwrap_rrc_mbuf(mbuf_t header,size_t rrc)1572 gss_krb5_cfx_unwrap_rrc_mbuf(mbuf_t header, size_t rrc)
1573 {
1574 mbuf_t body, trailer;
1575
1576 gss_normalize_mbuf(header, sizeof(gss_cfx_wrap_token_desc), &rrc, &trailer, &body, 0);
1577 gss_join_mbuf(header, body, trailer);
1578 }
1579
1580 uint32_t
gss_krb5_cfx_unwrap_mbuf(uint32_t * minor,gss_ctx_id_t ctx,mbuf_t * mbp,size_t len,int * conf_flag,gss_qop_t * qop)1581 gss_krb5_cfx_unwrap_mbuf(uint32_t * minor, /* minor_status */
1582 gss_ctx_id_t ctx, /* context_handle */
1583 mbuf_t *mbp, /* input/output message_buffer */
1584 size_t len, /* mbuf chain length */
1585 int *conf_flag, /* conf_state */
1586 gss_qop_t *qop /* qop state */)
1587 {
1588 gss_cfx_wrap_token_desc token;
1589 lucid_context_t lctx = &ctx->gss_lucid_ctx;
1590 crypto_ctx_t cctx = &ctx->gss_cryptor;
1591 int error, conf;
1592 uint32_t ec = 0, rrc = 0;
1593 uint64_t seq;
1594 int reverse = (*qop == GSS_C_QOP_REVERSE);
1595 int initiate = lctx->initiate ? (reverse ? 0 : 1) : (reverse ? 1 : 0);
1596
1597 error = mbuf_copydata(*mbp, 0, sizeof(gss_cfx_wrap_token_desc), &token);
1598 gss_strip_mbuf(*mbp, sizeof(gss_cfx_wrap_token_desc));
1599 len -= sizeof(gss_cfx_wrap_token_desc);
1600
1601 /* Check for valid token */
1602 if (token.TOK_ID[0] != wrap_cfx_token.TOK_ID[0] ||
1603 token.TOK_ID[1] != wrap_cfx_token.TOK_ID[1] ||
1604 token.Filler != wrap_cfx_token.Filler) {
1605 printf("Token id does not match\n");
1606 goto badrpc;
1607 }
1608 if ((initiate && !(token.Flags & CFXSentByAcceptor)) ||
1609 (lctx->key_data.lucid_protocol_u.data_4121.acceptor_subkey && !(token.Flags & CFXAcceptorSubkey))) {
1610 printf("Bad flags %x\n", token.Flags);
1611 goto badrpc;
1612 }
1613
1614 /* XXX Sequence replay detection */
1615 memcpy(&seq, token.SND_SEQ, sizeof(seq));
1616 seq = ntohll(seq);
1617 lctx->recv_seq = seq;
1618
1619 ec = (token.EC[0] << 8) | token.EC[1];
1620 rrc = (token.RRC[0] << 8) | token.RRC[1];
1621 *qop = GSS_C_QOP_DEFAULT;
1622 conf = ((token.Flags & CFXSealed) == CFXSealed);
1623 if (conf_flag) {
1624 *conf_flag = conf;
1625 }
1626 if (conf) {
1627 gss_cfx_wrap_token_desc etoken;
1628
1629 if (rrc) { /* Handle Right rotation count */
1630 gss_krb5_cfx_unwrap_rrc_mbuf(*mbp, rrc);
1631 }
1632 error = krb5_cfx_crypt_mbuf(cctx, mbp, &len, 0, reverse);
1633 if (error) {
1634 printf("krb5_cfx_crypt_mbuf %d\n", error);
1635 *minor = error;
1636 return GSS_S_FAILURE;
1637 }
1638 if (len >= sizeof(gss_cfx_wrap_token_desc)) {
1639 len -= sizeof(gss_cfx_wrap_token_desc);
1640 } else {
1641 goto badrpc;
1642 }
1643 mbuf_copydata(*mbp, len, sizeof(gss_cfx_wrap_token_desc), &etoken);
1644 /* Verify etoken with the token wich should be the same, except the rc field is always zero */
1645 token.RRC[0] = token.RRC[1] = 0;
1646 if (memcmp(&token, &etoken, sizeof(gss_cfx_wrap_token_desc)) != 0) {
1647 printf("Encrypted token mismach\n");
1648 goto badrpc;
1649 }
1650 /* strip the encrypted token and any pad bytes */
1651 gss_strip_mbuf(*mbp, -(sizeof(gss_cfx_wrap_token_desc) + ec));
1652 len -= (sizeof(gss_cfx_wrap_token_desc) + ec);
1653 } else {
1654 uint8_t digest[CRYPTO_MAX_DIGSET_SIZE];
1655 int verf;
1656 gss_buffer_desc header;
1657
1658 if (ec != cctx->digest_size || len >= cctx->digest_size) {
1659 goto badrpc;
1660 }
1661 len -= cctx->digest_size;
1662 mbuf_copydata(*mbp, len, cctx->digest_size, digest);
1663 gss_strip_mbuf(*mbp, -cctx->digest_size);
1664 /* When calculating the mic header fields ec and rcc must be zero */
1665 token.EC[0] = token.EC[1] = token.RRC[0] = token.RRC[1] = 0;
1666 header.value = &token;
1667 header.length = sizeof(gss_cfx_wrap_token_desc);
1668 error = krb5_mic_mbuf(cctx, NULL, *mbp, 0, len, &header, digest, &verf, 1, reverse);
1669 if (error) {
1670 goto badrpc;
1671 }
1672 }
1673 return GSS_S_COMPLETE;
1674
1675 badrpc:
1676 *minor = EBADRPC;
1677 return GSS_S_FAILURE;
1678 }
1679
1680 /*
1681 * RFC 1964 3DES support
1682 */
1683
1684 typedef struct gss_1964_mic_token_desc_struct {
1685 uint8_t TOK_ID[2]; /* 01 01 */
1686 uint8_t Sign_Alg[2];
1687 uint8_t Filler[4]; /* ff ff ff ff */
1688 } gss_1964_mic_token_desc, *gss_1964_mic_token;
1689
1690 typedef struct gss_1964_wrap_token_desc_struct {
1691 uint8_t TOK_ID[2]; /* 02 01 */
1692 uint8_t Sign_Alg[2];
1693 uint8_t Seal_Alg[2];
1694 uint8_t Filler[2]; /* ff ff */
1695 } gss_1964_wrap_token_desc, *gss_1964_wrap_token;
1696
1697 typedef struct gss_1964_delete_token_desc_struct {
1698 uint8_t TOK_ID[2]; /* 01 02 */
1699 uint8_t Sign_Alg[2];
1700 uint8_t Filler[4]; /* ff ff ff ff */
1701 } gss_1964_delete_token_desc, *gss_1964_delete_token;
1702
1703 typedef struct gss_1964_header_desc_struct {
1704 uint8_t App0; /* 0x60 Application 0 constructed */
1705 uint8_t AppLen[]; /* Variable Der length */
1706 } gss_1964_header_desc, *gss_1964_header;
1707
1708 typedef union {
1709 gss_1964_mic_token_desc mic_tok;
1710 gss_1964_wrap_token_desc wrap_tok;
1711 gss_1964_delete_token_desc del_tok;
1712 } gss_1964_tok_type __attribute__((transparent_union));
1713
1714 typedef struct gss_1964_token_body_struct {
1715 uint8_t OIDType; /* 0x06 */
1716 uint8_t OIDLen; /* 0x09 */
1717 uint8_t kerb_mech[9]; /* Der Encode kerberos mech 1.2.840.113554.1.2.2
1718 * 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x12, 0x01, 0x02, 0x02 */
1719 gss_1964_tok_type body;
1720 uint8_t SND_SEQ[8];
1721 uint8_t Hash[]; /* Mic */
1722 } gss_1964_token_body_desc, *gss_1964_token_body;
1723
1724
1725 gss_1964_header_desc tok_1964_header = {
1726 .App0 = 0x60
1727 };
1728
1729 gss_1964_mic_token_desc mic_1964_token = {
1730 .TOK_ID = "\x01\x01",
1731 .Filler = "\xff\xff\xff\xff"
1732 };
1733
1734 gss_1964_wrap_token_desc wrap_1964_token = {
1735 .TOK_ID = "\x02\x01",
1736 .Filler = "\xff\xff"
1737 };
1738
1739 gss_1964_delete_token_desc del_1964_token = {
1740 .TOK_ID = "\x01\x01",
1741 .Filler = "\xff\xff\xff\xff"
1742 };
1743
1744 gss_1964_token_body_desc body_1964_token = {
1745 .OIDType = 0x06,
1746 .OIDLen = 0x09,
1747 .kerb_mech = "\x2a\x86\x48\x86\xf7\x12\x01\x02\x02",
1748 };
1749
1750 #define GSS_KRB5_3DES_MAXTOKSZ (sizeof(gss_1964_header_desc) + 5 /* max der length supported */ + sizeof(gss_1964_token_body_desc))
1751
1752 uint32_t gss_krb5_3des_get_mic(uint32_t *, gss_ctx_id_t, gss_qop_t, gss_buffer_t, gss_buffer_t);
1753 uint32_t gss_krb5_3des_get_mic_mbuf(uint32_t *, gss_ctx_id_t, gss_qop_t, mbuf_t, size_t, size_t, gss_buffer_t);
1754 uint32_t gss_krb5_3des_verify_mic_mbuf(uint32_t *, gss_ctx_id_t, mbuf_t, size_t, size_t, gss_buffer_t, gss_qop_t *);
1755 uint32_t gss_krb5_3des_wrap_mbuf(uint32_t *, gss_ctx_id_t, int, gss_qop_t, mbuf_t *, size_t, int *);
1756 uint32_t gss_krb5_3des_unwrap_mbuf(uint32_t *, gss_ctx_id_t, mbuf_t *, size_t, int *, gss_qop_t *);
1757
1758 /*
1759 * Decode an ASN.1 DER length field
1760 */
1761 static ssize_t
gss_krb5_der_length_get(uint8_t ** pp)1762 gss_krb5_der_length_get(uint8_t **pp)
1763 {
1764 uint8_t *p = *pp;
1765 uint32_t flen, len = 0;
1766
1767 flen = *p & 0x7f;
1768
1769 if (*p++ & 0x80) {
1770 if (flen > sizeof(uint32_t)) {
1771 return -1;
1772 }
1773 while (flen--) {
1774 len = (len << 8) + *p++;
1775 }
1776 } else {
1777 len = flen;
1778 }
1779 *pp = p;
1780 return len;
1781 }
1782
1783 /*
1784 * Determine size of ASN.1 DER length
1785 */
1786 static int
gss_krb5_der_length_size(size_t len)1787 gss_krb5_der_length_size(size_t len)
1788 {
1789 return
1790 len < (1 << 7) ? 1 :
1791 len < (1 << 8) ? 2 :
1792 len < (1 << 16) ? 3 :
1793 len < (1 << 24) ? 4 : 5;
1794 }
1795
1796 /*
1797 * Encode an ASN.1 DER length field
1798 */
1799 static void
gss_krb5_der_length_put(uint8_t ** pp,size_t len)1800 gss_krb5_der_length_put(uint8_t **pp, size_t len)
1801 {
1802 int sz = gss_krb5_der_length_size(len);
1803 uint8_t *p = *pp;
1804
1805 if (sz == 1) {
1806 *p++ = (uint8_t) len;
1807 } else {
1808 *p++ = (uint8_t) ((sz - 1) | 0x80);
1809 sz -= 1;
1810 while (sz--) {
1811 *p++ = (uint8_t) ((len >> (sz * 8)) & 0xff);
1812 }
1813 }
1814
1815 *pp = p;
1816 }
1817
1818 static void
gss_krb5_3des_token_put(gss_ctx_id_t ctx,gss_1964_tok_type body,gss_buffer_t hash,size_t datalen,gss_buffer_t des3_token)1819 gss_krb5_3des_token_put(gss_ctx_id_t ctx, gss_1964_tok_type body, gss_buffer_t hash, size_t datalen, gss_buffer_t des3_token)
1820 {
1821 gss_1964_header token;
1822 gss_1964_token_body tokbody;
1823 lucid_context_t lctx = &ctx->gss_lucid_ctx;
1824 crypto_ctx_t cctx = &ctx->gss_cryptor;
1825 uint32_t seq = (uint32_t) (lctx->send_seq++ & 0xffff);
1826 size_t toklen = sizeof(gss_1964_token_body_desc) + cctx->digest_size;
1827 size_t alloclen = toklen + sizeof(gss_1964_header_desc) + gss_krb5_der_length_size(toklen + datalen);
1828 uint8_t *tokptr;
1829
1830 token = kalloc_data(alloclen, Z_WAITOK | Z_ZERO);
1831 *token = tok_1964_header;
1832 tokptr = token->AppLen;
1833 gss_krb5_der_length_put(&tokptr, toklen + datalen);
1834 tokbody = (gss_1964_token_body)tokptr;
1835 *tokbody = body_1964_token; /* Initalize the token body */
1836 tokbody->body = body; /* and now set the body to the token type passed in */
1837 seq = htonl(seq);
1838 for (int i = 0; i < 4; i++) {
1839 tokbody->SND_SEQ[i] = (uint8_t)((seq >> (i * 8)) & 0xff);
1840 }
1841 for (int i = 4; i < 8; i++) {
1842 tokbody->SND_SEQ[i] = lctx->initiate ? 0x00 : 0xff;
1843 }
1844
1845 size_t blocksize = cctx->enc_mode->block_size;
1846 cccbc_iv_decl(blocksize, iv);
1847 cccbc_ctx_decl(cctx->enc_mode->size, enc_ctx);
1848 cccbc_set_iv(cctx->enc_mode, iv, hash->value);
1849 cccbc_init(cctx->enc_mode, enc_ctx, cctx->keylen, cctx->key);
1850 cccbc_update(cctx->enc_mode, enc_ctx, iv, 1, tokbody->SND_SEQ, tokbody->SND_SEQ);
1851
1852 assert(hash->length == cctx->digest_size);
1853 memcpy(tokbody->Hash, hash->value, hash->length);
1854 des3_token->length = alloclen;
1855 des3_token->value = token;
1856 }
1857
1858 static int
gss_krb5_3des_token_get(gss_ctx_id_t ctx,gss_buffer_t intok,gss_1964_tok_type body,gss_buffer_t hash,size_t * offset,size_t * len,int reverse)1859 gss_krb5_3des_token_get(gss_ctx_id_t ctx, gss_buffer_t intok,
1860 gss_1964_tok_type body, gss_buffer_t hash, size_t *offset, size_t *len, int reverse)
1861 {
1862 gss_1964_header token = intok->value;
1863 gss_1964_token_body tokbody;
1864 lucid_context_t lctx = &ctx->gss_lucid_ctx;
1865 crypto_ctx_t cctx = &ctx->gss_cryptor;
1866 ssize_t length;
1867 size_t toklen;
1868 uint8_t *tokptr;
1869 uint32_t seq;
1870 int initiate;
1871
1872 if (token->App0 != tok_1964_header.App0) {
1873 printf("%s: bad framing\n", __func__);
1874 printgbuf(__func__, intok);
1875 return EBADRPC;
1876 }
1877 tokptr = token->AppLen;
1878 length = gss_krb5_der_length_get(&tokptr);
1879 if (length < 0) {
1880 printf("%s: invalid length\n", __func__);
1881 printgbuf(__func__, intok);
1882 return EBADRPC;
1883 }
1884 toklen = sizeof(gss_1964_header_desc) + gss_krb5_der_length_size(length)
1885 + sizeof(gss_1964_token_body_desc);
1886
1887 if (intok->length < toklen + cctx->digest_size) {
1888 printf("%s: token to short", __func__);
1889 printf("toklen = %d, length = %d\n", (int)toklen, (int)length);
1890 printgbuf(__func__, intok);
1891 return EBADRPC;
1892 }
1893
1894 if (offset) {
1895 *offset = toklen + cctx->digest_size;
1896 }
1897
1898 if (len) {
1899 *len = length - sizeof(gss_1964_token_body_desc) - cctx->digest_size;
1900 }
1901
1902 tokbody = (gss_1964_token_body)tokptr;
1903 if (tokbody->OIDType != body_1964_token.OIDType ||
1904 tokbody->OIDLen != body_1964_token.OIDLen ||
1905 memcmp(tokbody->kerb_mech, body_1964_token.kerb_mech, tokbody->OIDLen) != 0) {
1906 printf("%s: Invalid mechanism\n", __func__);
1907 printgbuf(__func__, intok);
1908 return EBADRPC;
1909 }
1910 if (memcmp(&tokbody->body, &body, sizeof(gss_1964_tok_type)) != 0) {
1911 printf("%s: Invalid body\n", __func__);
1912 printgbuf(__func__, intok);
1913 return EBADRPC;
1914 }
1915 size_t blocksize = cctx->enc_mode->block_size;
1916 uint8_t *block = tokbody->SND_SEQ;
1917
1918 assert(blocksize == sizeof(tokbody->SND_SEQ));
1919 cccbc_iv_decl(blocksize, iv);
1920 cccbc_ctx_decl(cctx->dec_mode->size, dec_ctx);
1921 cccbc_set_iv(cctx->dec_mode, iv, tokbody->Hash);
1922 cccbc_init(cctx->dec_mode, dec_ctx, cctx->keylen, cctx->key);
1923 cccbc_update(cctx->dec_mode, dec_ctx, iv, 1, block, block);
1924
1925 initiate = lctx->initiate ? (reverse ? 0 : 1) : (reverse ? 1 : 0);
1926 for (int i = 4; i < 8; i++) {
1927 if (tokbody->SND_SEQ[i] != (initiate ? 0xff : 0x00)) {
1928 printf("%s: Invalid des mac\n", __func__);
1929 printgbuf(__func__, intok);
1930 return EAUTH;
1931 }
1932 }
1933
1934 memcpy(&seq, tokbody->SND_SEQ, sizeof(uint32_t));
1935
1936 lctx->recv_seq = ntohl(seq);
1937
1938 assert(hash->length >= cctx->digest_size);
1939 memcpy(hash->value, tokbody->Hash, cctx->digest_size);
1940
1941 return 0;
1942 }
1943
1944 uint32_t
gss_krb5_3des_get_mic(uint32_t * minor,gss_ctx_id_t ctx,gss_qop_t qop __unused,gss_buffer_t mbp,gss_buffer_t mic)1945 gss_krb5_3des_get_mic(uint32_t *minor, /* minor status */
1946 gss_ctx_id_t ctx, /* krb5 context id */
1947 gss_qop_t qop __unused, /* qop_req (ignored) */
1948 gss_buffer_t mbp, /* message buffer in */
1949 gss_buffer_t mic) /* mic token out */
1950 {
1951 gss_1964_mic_token_desc tokbody = mic_1964_token;
1952 crypto_ctx_t cctx = &ctx->gss_cryptor;
1953 gss_buffer_desc hash;
1954 gss_buffer_desc header;
1955 uint8_t hashval[CRYPTO_MAX_DIGSET_SIZE];
1956
1957 hash.length = cctx->digest_size;
1958 hash.value = hashval;
1959 tokbody.Sign_Alg[0] = 0x04; /* lctx->keydata.lucid_protocol_u.data_1964.sign_alg */
1960 tokbody.Sign_Alg[1] = 0x00;
1961 header.length = sizeof(gss_1964_mic_token_desc);
1962 header.value = &tokbody;
1963
1964 /* Hash the data */
1965 *minor = krb5_mic(cctx, &header, mbp, NULL, hashval, NULL, 0, 0);
1966 if (*minor) {
1967 return GSS_S_FAILURE;
1968 }
1969
1970 /* Make the token */
1971 gss_krb5_3des_token_put(ctx, tokbody, &hash, 0, mic);
1972
1973 return GSS_S_COMPLETE;
1974 }
1975
1976 uint32_t
gss_krb5_3des_get_mic_mbuf(uint32_t * minor,gss_ctx_id_t ctx,gss_qop_t qop __unused,mbuf_t mbp,size_t offset,size_t len,gss_buffer_t mic)1977 gss_krb5_3des_get_mic_mbuf(uint32_t *minor,
1978 gss_ctx_id_t ctx,
1979 gss_qop_t qop __unused,
1980 mbuf_t mbp,
1981 size_t offset,
1982 size_t len,
1983 gss_buffer_t mic)
1984 {
1985 gss_1964_mic_token_desc tokbody = mic_1964_token;
1986 crypto_ctx_t cctx = &ctx->gss_cryptor;
1987 gss_buffer_desc header;
1988 gss_buffer_desc hash;
1989 uint8_t hashval[CRYPTO_MAX_DIGSET_SIZE];
1990
1991 hash.length = cctx->digest_size;
1992 hash.value = hashval;
1993 tokbody.Sign_Alg[0] = 0x04; /* lctx->key_data.lucid_protocol_u.data_4121.sign_alg */
1994 tokbody.Sign_Alg[1] = 0x00;
1995 header.length = sizeof(gss_1964_mic_token_desc);
1996 header.value = &tokbody;
1997
1998 /* Hash the data */
1999 *minor = krb5_mic_mbuf(cctx, &header, mbp, offset, len, NULL, hashval, NULL, 0, 0);
2000 if (*minor) {
2001 return GSS_S_FAILURE;
2002 }
2003
2004 /* Make the token */
2005 gss_krb5_3des_token_put(ctx, tokbody, &hash, 0, mic);
2006
2007 return GSS_S_COMPLETE;
2008 }
2009
2010 uint32_t
gss_krb5_3des_verify_mic_mbuf(uint32_t * minor,gss_ctx_id_t ctx,mbuf_t mbp,size_t offset,size_t len,gss_buffer_t mic,gss_qop_t * qop)2011 gss_krb5_3des_verify_mic_mbuf(uint32_t *minor,
2012 gss_ctx_id_t ctx,
2013 mbuf_t mbp,
2014 size_t offset,
2015 size_t len,
2016 gss_buffer_t mic,
2017 gss_qop_t *qop)
2018 {
2019 crypto_ctx_t cctx = &ctx->gss_cryptor;
2020 uint8_t hashval[CRYPTO_MAX_DIGSET_SIZE];
2021 gss_buffer_desc header;
2022 gss_buffer_desc hash;
2023 gss_1964_mic_token_desc mtok = mic_1964_token;
2024 int verf;
2025
2026 mtok.Sign_Alg[0] = 0x04; /* lctx->key_data.lucic_protocol_u.data1964.sign_alg */
2027 mtok.Sign_Alg[1] = 0x00;
2028 hash.length = cctx->digest_size;
2029 hash.value = hashval;
2030 header.length = sizeof(gss_1964_mic_token_desc);
2031 header.value = &mtok;
2032
2033 if (qop) {
2034 *qop = GSS_C_QOP_DEFAULT;
2035 }
2036
2037 *minor = gss_krb5_3des_token_get(ctx, mic, mtok, &hash, NULL, NULL, 0);
2038 if (*minor) {
2039 return GSS_S_FAILURE;
2040 }
2041
2042 *minor = krb5_mic_mbuf(cctx, &header, mbp, offset, len, NULL, hashval, &verf, 0, 0);
2043 if (*minor) {
2044 return GSS_S_FAILURE;
2045 }
2046
2047 return verf ? GSS_S_COMPLETE : GSS_S_BAD_SIG;
2048 }
2049
2050 uint32_t
gss_krb5_3des_wrap_mbuf(uint32_t * minor,gss_ctx_id_t ctx,int conf_flag,gss_qop_t qop __unused,mbuf_t * mbp,size_t len,int * conf_state)2051 gss_krb5_3des_wrap_mbuf(uint32_t *minor,
2052 gss_ctx_id_t ctx,
2053 int conf_flag,
2054 gss_qop_t qop __unused,
2055 mbuf_t *mbp,
2056 size_t len,
2057 int *conf_state)
2058 {
2059 crypto_ctx_t cctx = &ctx->gss_cryptor;
2060 const struct ccmode_cbc *ccmode = cctx->enc_mode;
2061 uint8_t padlen;
2062 uint8_t pad[8];
2063 uint8_t *confounder = NULL;
2064 gss_1964_wrap_token_desc tokbody = wrap_1964_token;
2065 gss_buffer_desc header;
2066 gss_buffer_desc mic;
2067 gss_buffer_desc hash;
2068 uint8_t hashval[CRYPTO_MAX_DIGSET_SIZE];
2069
2070 confounder = kalloc_data(ccmode->block_size, Z_WAITOK | Z_ZERO);
2071 if (confounder == NULL) {
2072 *minor = ENOMEM;
2073 goto out;
2074 }
2075 if (conf_state) {
2076 *conf_state = conf_flag;
2077 }
2078
2079 hash.length = cctx->digest_size;
2080 hash.value = hashval;
2081 tokbody.Sign_Alg[0] = 0x04; /* lctx->key_data.lucid_protocol_u.data_1964.sign_alg */
2082 tokbody.Sign_Alg[1] = 0x00;
2083 /* conf_flag ? lctx->key_data.lucid_protocol_u.data_1964.seal_alg : 0xffff */
2084 tokbody.Seal_Alg[0] = conf_flag ? 0x02 : 0xff;
2085 tokbody.Seal_Alg[1] = conf_flag ? 0x00 : 0xff;
2086 header.length = sizeof(gss_1964_wrap_token_desc);
2087 header.value = &tokbody;
2088
2089 /* Prepend confounder */
2090 assert(ccmode->block_size <= UINT_MAX);
2091 read_random(confounder, (u_int)ccmode->block_size);
2092 *minor = gss_prepend_mbuf(mbp, confounder, ccmode->block_size);
2093 if (*minor) {
2094 goto out;
2095 }
2096
2097 /* Append trailer of up to 8 bytes and set pad length in each trailer byte */
2098 padlen = 8 - len % 8;
2099 for (int i = 0; i < padlen; i++) {
2100 pad[i] = padlen;
2101 }
2102 *minor = gss_append_mbuf(*mbp, pad, padlen);
2103 if (*minor) {
2104 goto out;
2105 }
2106
2107 len += ccmode->block_size + padlen;
2108
2109 /* Hash the data */
2110 *minor = krb5_mic_mbuf(cctx, &header, *mbp, 0, len, NULL, hashval, NULL, 0, 0);
2111 if (*minor) {
2112 goto out;
2113 }
2114
2115 /* Make the token */
2116 gss_krb5_3des_token_put(ctx, tokbody, &hash, len, &mic);
2117
2118 if (conf_flag) {
2119 *minor = krb5_crypt_mbuf(cctx, mbp, len, 1, 0);
2120 if (*minor) {
2121 goto out;
2122 }
2123 }
2124
2125 *minor = gss_prepend_mbuf(mbp, mic.value, mic.length);
2126
2127 out:
2128 kfree_data(confounder, ccmode->block_size);
2129 return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE;
2130 }
2131
2132 uint32_t
gss_krb5_3des_unwrap_mbuf(uint32_t * minor,gss_ctx_id_t ctx,mbuf_t * mbp,size_t len,int * conf_state,gss_qop_t * qop)2133 gss_krb5_3des_unwrap_mbuf(uint32_t *minor,
2134 gss_ctx_id_t ctx,
2135 mbuf_t *mbp,
2136 size_t len,
2137 int *conf_state,
2138 gss_qop_t *qop)
2139 {
2140 crypto_ctx_t cctx = &ctx->gss_cryptor;
2141 const struct ccmode_cbc *ccmode = cctx->dec_mode;
2142 size_t length = 0, offset = 0;
2143 gss_buffer_desc hash;
2144 uint8_t hashval[CRYPTO_MAX_DIGSET_SIZE];
2145 gss_buffer_desc itoken;
2146 uint8_t tbuffer[GSS_KRB5_3DES_MAXTOKSZ + CRYPTO_MAX_DIGSET_SIZE];
2147 itoken.length = GSS_KRB5_3DES_MAXTOKSZ + cctx->digest_size;
2148 itoken.value = tbuffer;
2149 gss_1964_wrap_token_desc wrap = wrap_1964_token;
2150 gss_buffer_desc header;
2151 uint8_t padlen;
2152 mbuf_t smb, tmb;
2153 int cflag, verified, reverse = 0;
2154
2155 if (len < GSS_KRB5_3DES_MAXTOKSZ) {
2156 *minor = EBADRPC;
2157 return GSS_S_FAILURE;
2158 }
2159
2160 if (*qop == GSS_C_QOP_REVERSE) {
2161 reverse = 1;
2162 }
2163 *qop = GSS_C_QOP_DEFAULT;
2164
2165 *minor = mbuf_copydata(*mbp, 0, itoken.length, itoken.value);
2166 if (*minor) {
2167 return GSS_S_FAILURE;
2168 }
2169
2170 hash.length = cctx->digest_size;
2171 hash.value = hashval;
2172 wrap.Sign_Alg[0] = 0x04;
2173 wrap.Sign_Alg[1] = 0x00;
2174 wrap.Seal_Alg[0] = 0x02;
2175 wrap.Seal_Alg[1] = 0x00;
2176
2177 for (cflag = 1; cflag >= 0; cflag--) {
2178 *minor = gss_krb5_3des_token_get(ctx, &itoken, wrap, &hash, &offset, &length, reverse);
2179 if (*minor == 0) {
2180 break;
2181 }
2182 wrap.Seal_Alg[0] = 0xff;
2183 wrap.Seal_Alg[1] = 0xff;
2184 }
2185 if (*minor) {
2186 return GSS_S_FAILURE;
2187 }
2188
2189 if (conf_state) {
2190 *conf_state = cflag;
2191 }
2192
2193 /*
2194 * Seperate off the header
2195 */
2196 *minor = gss_normalize_mbuf(*mbp, offset, &length, &smb, &tmb, 0);
2197 if (*minor) {
2198 return GSS_S_FAILURE;
2199 }
2200
2201 assert(tmb == NULL);
2202
2203 /* Decrypt the chain if needed */
2204 if (cflag) {
2205 *minor = krb5_crypt_mbuf(cctx, &smb, length, 0, NULL);
2206 if (*minor) {
2207 return GSS_S_FAILURE;
2208 }
2209 }
2210
2211 /* Verify the mic */
2212 header.length = sizeof(gss_1964_wrap_token_desc);
2213 header.value = &wrap;
2214
2215 *minor = krb5_mic_mbuf(cctx, &header, smb, 0, length, NULL, hashval, &verified, 0, 0);
2216 if (*minor) {
2217 return GSS_S_FAILURE;
2218 }
2219 if (!verified) {
2220 return GSS_S_BAD_SIG;
2221 }
2222
2223 /* Get the pad bytes */
2224 *minor = mbuf_copydata(smb, length - 1, 1, &padlen);
2225 if (*minor) {
2226 return GSS_S_FAILURE;
2227 }
2228
2229 /* Strip the confounder and trailing pad bytes */
2230 gss_strip_mbuf(smb, -padlen);
2231 assert(ccmode->block_size <= INT_MAX);
2232 gss_strip_mbuf(smb, (int)ccmode->block_size);
2233
2234 if (*mbp != smb) {
2235 mbuf_freem(*mbp);
2236 *mbp = smb;
2237 }
2238
2239 return GSS_S_COMPLETE;
2240 }
2241
2242 static const char *
etype_name(etypes etype)2243 etype_name(etypes etype)
2244 {
2245 switch (etype) {
2246 case DES3_CBC_SHA1_KD:
2247 return "des3-cbc-sha1";
2248 case AES128_CTS_HMAC_SHA1_96:
2249 return "aes128-cts-hmac-sha1-96";
2250 case AES256_CTS_HMAC_SHA1_96:
2251 return "aes-cts-hmac-sha1-96";
2252 default:
2253 return "unknown enctype";
2254 }
2255 }
2256
2257 static int
supported_etype(uint32_t proto,etypes etype)2258 supported_etype(uint32_t proto, etypes etype)
2259 {
2260 const char *proto_name;
2261
2262 switch (proto) {
2263 case 0:
2264 /* RFC 1964 */
2265 proto_name = "RFC 1964 krb5 gss mech";
2266 switch (etype) {
2267 case DES3_CBC_SHA1_KD:
2268 return 1;
2269 default:
2270 break;
2271 }
2272 break;
2273 case 1:
2274 /* RFC 4121 */
2275 proto_name = "RFC 4121 krb5 gss mech";
2276 switch (etype) {
2277 case AES256_CTS_HMAC_SHA1_96:
2278 case AES128_CTS_HMAC_SHA1_96:
2279 return 1;
2280 default:
2281 break;
2282 }
2283 break;
2284 default:
2285 proto_name = "Unknown krb5 gss mech";
2286 break;
2287 }
2288 printf("%s: Non supported encryption %s (%d) type for protocol %s (%d)\n",
2289 __func__, etype_name(etype), etype, proto_name, proto);
2290 return 0;
2291 }
2292
2293 /*
2294 * Kerberos gss mech entry points
2295 */
2296 uint32_t
gss_krb5_get_mic(uint32_t * minor,gss_ctx_id_t ctx,gss_qop_t qop,gss_buffer_t mbp,gss_buffer_t mic)2297 gss_krb5_get_mic(uint32_t *minor, /* minor_status */
2298 gss_ctx_id_t ctx, /* context_handle */
2299 gss_qop_t qop, /* qop_req */
2300 gss_buffer_t mbp, /* message buffer */
2301 gss_buffer_t mic /* message_token */)
2302 {
2303 uint32_t minor_stat = 0;
2304
2305 if (minor == NULL) {
2306 minor = &minor_stat;
2307 }
2308 *minor = 0;
2309
2310 /* Validate context */
2311 if (ctx == NULL || ((lucid_context_version_t)ctx)->version != 1) {
2312 return GSS_S_NO_CONTEXT;
2313 }
2314
2315 if (!supported_etype(ctx->gss_lucid_ctx.key_data.proto, ctx->gss_cryptor.etype)) {
2316 *minor = ENOTSUP;
2317 return GSS_S_FAILURE;
2318 }
2319
2320 switch (ctx->gss_lucid_ctx.key_data.proto) {
2321 case 0:
2322 /* RFC 1964 DES3 case */
2323 return gss_krb5_3des_get_mic(minor, ctx, qop, mbp, mic);
2324 case 1:
2325 /* RFC 4121 CFX case */
2326 return gss_krb5_cfx_get_mic(minor, ctx, qop, mbp, mic);
2327 }
2328
2329 return GSS_S_COMPLETE;
2330 }
2331
2332 uint32_t
gss_krb5_get_mic_mbuf(uint32_t * minor,gss_ctx_id_t ctx,gss_qop_t qop,mbuf_t mbp,size_t offset,size_t len,gss_buffer_t mic)2333 gss_krb5_get_mic_mbuf(uint32_t *minor, /* minor_status */
2334 gss_ctx_id_t ctx, /* context_handle */
2335 gss_qop_t qop, /* qop_req */
2336 mbuf_t mbp, /* message mbuf */
2337 size_t offset, /* offest */
2338 size_t len, /* length */
2339 gss_buffer_t mic /* message_token */)
2340 {
2341 uint32_t minor_stat = 0;
2342
2343 if (minor == NULL) {
2344 minor = &minor_stat;
2345 }
2346 *minor = 0;
2347
2348 if (len == 0) {
2349 len = ~(size_t)0;
2350 }
2351
2352 /* Validate context */
2353 if (ctx == NULL || ((lucid_context_version_t)ctx)->version != 1) {
2354 return GSS_S_NO_CONTEXT;
2355 }
2356
2357 if (!supported_etype(ctx->gss_lucid_ctx.key_data.proto, ctx->gss_cryptor.etype)) {
2358 *minor = ENOTSUP;
2359 return GSS_S_FAILURE;
2360 }
2361
2362 switch (ctx->gss_lucid_ctx.key_data.proto) {
2363 case 0:
2364 /* RFC 1964 DES3 case */
2365 return gss_krb5_3des_get_mic_mbuf(minor, ctx, qop, mbp, offset, len, mic);
2366 case 1:
2367 /* RFC 4121 CFX case */
2368 return gss_krb5_cfx_get_mic_mbuf(minor, ctx, qop, mbp, offset, len, mic);
2369 }
2370
2371 return GSS_S_COMPLETE;
2372 }
2373
2374 uint32_t
gss_krb5_verify_mic_mbuf(uint32_t * minor,gss_ctx_id_t ctx,mbuf_t mbp,size_t offset,size_t len,gss_buffer_t mic,gss_qop_t * qop)2375 gss_krb5_verify_mic_mbuf(uint32_t *minor, /* minor_status */
2376 gss_ctx_id_t ctx, /* context_handle */
2377 mbuf_t mbp, /* message_buffer */
2378 size_t offset, /* offset */
2379 size_t len, /* length */
2380 gss_buffer_t mic, /* message_token */
2381 gss_qop_t *qop /* qop_state */)
2382 {
2383 uint32_t minor_stat = 0;
2384 gss_qop_t qop_val = GSS_C_QOP_DEFAULT;
2385
2386 if (minor == NULL) {
2387 minor = &minor_stat;
2388 }
2389 if (qop == NULL) {
2390 qop = &qop_val;
2391 }
2392
2393 *minor = 0;
2394
2395 if (len == 0) {
2396 len = ~(size_t)0;
2397 }
2398
2399 /* Validate context */
2400 if (ctx == NULL || ((lucid_context_version_t)ctx)->version != 1) {
2401 return GSS_S_NO_CONTEXT;
2402 }
2403
2404 if (!supported_etype(ctx->gss_lucid_ctx.key_data.proto, ctx->gss_cryptor.etype)) {
2405 *minor = ENOTSUP;
2406 return GSS_S_FAILURE;
2407 }
2408
2409 switch (ctx->gss_lucid_ctx.key_data.proto) {
2410 case 0:
2411 /* RFC 1964 DES3 case */
2412 return gss_krb5_3des_verify_mic_mbuf(minor, ctx, mbp, offset, len, mic, qop);
2413 case 1:
2414 /* RFC 4121 CFX case */
2415 return gss_krb5_cfx_verify_mic_mbuf(minor, ctx, mbp, offset, len, mic, qop);
2416 }
2417
2418 return GSS_S_COMPLETE;
2419 }
2420
2421 uint32_t
gss_krb5_wrap_mbuf(uint32_t * minor,gss_ctx_id_t ctx,int conf_flag,gss_qop_t qop,mbuf_t * mbp,size_t offset,size_t len,int * conf_state)2422 gss_krb5_wrap_mbuf(uint32_t *minor, /* minor_status */
2423 gss_ctx_id_t ctx, /* context_handle */
2424 int conf_flag, /* conf_req_flag */
2425 gss_qop_t qop, /* qop_req */
2426 mbuf_t *mbp, /* input/output message_buffer */
2427 size_t offset, /* offset */
2428 size_t len, /* length */
2429 int *conf_state /* conf state */)
2430 {
2431 uint32_t major = GSS_S_FAILURE, minor_stat = 0;
2432 mbuf_t smb, tmb;
2433 int conf_val = 0;
2434
2435 if (minor == NULL) {
2436 minor = &minor_stat;
2437 }
2438 if (conf_state == NULL) {
2439 conf_state = &conf_val;
2440 }
2441
2442 *minor = 0;
2443
2444 /* Validate context */
2445 if (ctx == NULL || ((lucid_context_version_t)ctx)->version != 1) {
2446 return GSS_S_NO_CONTEXT;
2447 }
2448
2449 if (!supported_etype(ctx->gss_lucid_ctx.key_data.proto, ctx->gss_cryptor.etype)) {
2450 *minor = ENOTSUP;
2451 return GSS_S_FAILURE;
2452 }
2453
2454 gss_normalize_mbuf(*mbp, offset, &len, &smb, &tmb, 0);
2455
2456 switch (ctx->gss_lucid_ctx.key_data.proto) {
2457 case 0:
2458 /* RFC 1964 DES3 case */
2459 major = gss_krb5_3des_wrap_mbuf(minor, ctx, conf_flag, qop, &smb, len, conf_state);
2460 break;
2461 case 1:
2462 /* RFC 4121 CFX case */
2463 major = gss_krb5_cfx_wrap_mbuf(minor, ctx, conf_flag, qop, &smb, len, conf_state);
2464 break;
2465 }
2466
2467 if (offset) {
2468 gss_join_mbuf(*mbp, smb, tmb);
2469 } else {
2470 *mbp = smb;
2471 gss_join_mbuf(smb, tmb, NULL);
2472 }
2473
2474 return major;
2475 }
2476
2477 uint32_t
gss_krb5_unwrap_mbuf(uint32_t * minor,gss_ctx_id_t ctx,mbuf_t * mbp,size_t offset,size_t len,int * conf_flag,gss_qop_t * qop)2478 gss_krb5_unwrap_mbuf(uint32_t * minor, /* minor_status */
2479 gss_ctx_id_t ctx, /* context_handle */
2480 mbuf_t *mbp, /* input/output message_buffer */
2481 size_t offset, /* offset */
2482 size_t len, /* length */
2483 int *conf_flag, /* conf_state */
2484 gss_qop_t *qop /* qop state */)
2485 {
2486 uint32_t major = GSS_S_FAILURE, minor_stat = 0;
2487 gss_qop_t qop_val = GSS_C_QOP_DEFAULT;
2488 int conf_val = 0;
2489 mbuf_t smb, tmb;
2490
2491 if (minor == NULL) {
2492 minor = &minor_stat;
2493 }
2494 if (qop == NULL) {
2495 qop = &qop_val;
2496 }
2497 if (conf_flag == NULL) {
2498 conf_flag = &conf_val;
2499 }
2500
2501 /* Validate context */
2502 if (ctx == NULL || ((lucid_context_version_t)ctx)->version != 1) {
2503 return GSS_S_NO_CONTEXT;
2504 }
2505
2506 if (!supported_etype(ctx->gss_lucid_ctx.key_data.proto, ctx->gss_cryptor.etype)) {
2507 *minor = ENOTSUP;
2508 return GSS_S_FAILURE;
2509 }
2510
2511 gss_normalize_mbuf(*mbp, offset, &len, &smb, &tmb, 0);
2512
2513 switch (ctx->gss_lucid_ctx.key_data.proto) {
2514 case 0:
2515 /* RFC 1964 DES3 case */
2516 major = gss_krb5_3des_unwrap_mbuf(minor, ctx, &smb, len, conf_flag, qop);
2517 break;
2518 case 1:
2519 /* RFC 4121 CFX case */
2520 major = gss_krb5_cfx_unwrap_mbuf(minor, ctx, &smb, len, conf_flag, qop);
2521 break;
2522 }
2523
2524 if (offset) {
2525 gss_join_mbuf(*mbp, smb, tmb);
2526 } else {
2527 *mbp = smb;
2528 gss_join_mbuf(smb, tmb, NULL);
2529 }
2530
2531 return major;
2532 }
2533
2534 #include <nfs/xdr_subs.h>
2535
2536 static int
xdr_lucid_context(void * data,uint32_t length,lucid_context_t lctx)2537 xdr_lucid_context(void *data, uint32_t length, lucid_context_t lctx)
2538 {
2539 struct xdrbuf xb;
2540 int error = 0;
2541 uint32_t keylen = 0;
2542
2543 xb_init_buffer(&xb, data, length);
2544 xb_get_32(error, &xb, lctx->vers);
2545 if (!error && lctx->vers != 1) {
2546 error = EINVAL;
2547 printf("%s: invalid version %d\n", __func__, (int)lctx->vers);
2548 goto out;
2549 }
2550 xb_get_32(error, &xb, lctx->initiate);
2551 if (error) {
2552 printf("%s: Could not decode initiate\n", __func__);
2553 goto out;
2554 }
2555 xb_get_32(error, &xb, lctx->endtime);
2556 if (error) {
2557 printf("%s: Could not decode endtime\n", __func__);
2558 goto out;
2559 }
2560 xb_get_64(error, &xb, lctx->send_seq);
2561 if (error) {
2562 printf("%s: Could not decode send_seq\n", __func__);
2563 goto out;
2564 }
2565 xb_get_64(error, &xb, lctx->recv_seq);
2566 if (error) {
2567 printf("%s: Could not decode recv_seq\n", __func__);
2568 goto out;
2569 }
2570 xb_get_32(error, &xb, lctx->key_data.proto);
2571 if (error) {
2572 printf("%s: Could not decode mech protocol\n", __func__);
2573 goto out;
2574 }
2575 switch (lctx->key_data.proto) {
2576 case 0:
2577 xb_get_32(error, &xb, lctx->key_data.lucid_protocol_u.data_1964.sign_alg);
2578 xb_get_32(error, &xb, lctx->key_data.lucid_protocol_u.data_1964.seal_alg);
2579 if (error) {
2580 printf("%s: Could not decode rfc1964 sign and seal\n", __func__);
2581 }
2582 break;
2583 case 1:
2584 xb_get_32(error, &xb, lctx->key_data.lucid_protocol_u.data_4121.acceptor_subkey);
2585 if (error) {
2586 printf("%s: Could not decode rfc4121 acceptor_subkey", __func__);
2587 }
2588 break;
2589 default:
2590 printf("%s: Invalid mech protocol %d\n", __func__, (int)lctx->key_data.proto);
2591 error = EINVAL;
2592 }
2593 if (error) {
2594 goto out;
2595 }
2596 xb_get_32(error, &xb, lctx->ctx_key.etype);
2597 if (error) {
2598 printf("%s: Could not decode key enctype\n", __func__);
2599 goto out;
2600 }
2601 switch (lctx->ctx_key.etype) {
2602 case DES3_CBC_SHA1_KD:
2603 keylen = 24;
2604 break;
2605 case AES128_CTS_HMAC_SHA1_96:
2606 keylen = 16;
2607 break;
2608 case AES256_CTS_HMAC_SHA1_96:
2609 keylen = 32;
2610 break;
2611 default:
2612 error = ENOTSUP;
2613 goto out;
2614 }
2615 xb_get_32(error, &xb, lctx->ctx_key.key.key_len);
2616 if (error) {
2617 printf("%s: could not decode key length\n", __func__);
2618 goto out;
2619 }
2620 if (lctx->ctx_key.key.key_len != keylen) {
2621 error = EINVAL;
2622 printf("%s: etype = %d keylen = %d expected keylen = %d\n", __func__,
2623 lctx->ctx_key.etype, lctx->ctx_key.key.key_len, keylen);
2624 goto out;
2625 }
2626
2627 lctx->ctx_key.key.key_val = xb_malloc(keylen);
2628 if (lctx->ctx_key.key.key_val == NULL) {
2629 printf("%s: could not get memory for key\n", __func__);
2630 error = ENOMEM;
2631 goto out;
2632 }
2633 error = xb_get_bytes(&xb, (char *)lctx->ctx_key.key.key_val, keylen, 1);
2634 if (error) {
2635 printf("%s: could get key value\n", __func__);
2636 xb_free_size(lctx->ctx_key.key.key_val, keylen);
2637 }
2638 out:
2639 return error;
2640 }
2641
2642 gss_ctx_id_t
gss_krb5_make_context(void * data,uint32_t datalen)2643 gss_krb5_make_context(void *data, uint32_t datalen)
2644 {
2645 gss_ctx_id_t ctx;
2646
2647 if (!corecrypto_available()) {
2648 return NULL;
2649 }
2650
2651 gss_krb5_mech_init();
2652 ctx = kalloc_type(struct gss_ctx_id_desc, Z_WAITOK | Z_ZERO);
2653 if (xdr_lucid_context(data, datalen, &ctx->gss_lucid_ctx) ||
2654 !supported_etype(ctx->gss_lucid_ctx.key_data.proto, ctx->gss_lucid_ctx.ctx_key.etype)) {
2655 kfree_type(struct gss_ctx_id_desc, ctx);
2656 return NULL;
2657 }
2658
2659 /* Set up crypto context */
2660 gss_crypto_ctx_init(&ctx->gss_cryptor, &ctx->gss_lucid_ctx);
2661 return ctx;
2662 }
2663
2664 void
gss_krb5_destroy_context(gss_ctx_id_t ctx)2665 gss_krb5_destroy_context(gss_ctx_id_t ctx)
2666 {
2667 if (ctx == NULL) {
2668 return;
2669 }
2670 gss_crypto_ctx_free(&ctx->gss_cryptor);
2671 xb_free(ctx->gss_lucid_ctx.ctx_key.key.key_val);
2672 cc_clear(sizeof(lucid_context_t), &ctx->gss_lucid_ctx);
2673 kfree_type(struct gss_ctx_id_desc, ctx);
2674 }
2675