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
75LCK_GRP_DECLARE(gss_krb5_mech_grp, "gss_krb5_mech");
76
77typedef 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
84typedef struct hmac_walker_ctx {
85 const struct ccdigest_info *di;
86 struct cchmac_ctx *hmac_ctx;
87} *hmac_walker_ctx_t;
88
89typedef size_t (*ccpad_func)(const struct ccmode_cbc *, cccbc_ctx *, cccbc_iv *,
90 size_t nbytes, const void *, void *);
91
92static int krb5_n_fold(const void *instr, size_t len, void *foldstr, size_t size);
93
94size_t gss_mbuf_len(mbuf_t, size_t);
95errno_t gss_prepend_mbuf(mbuf_t *, uint8_t *, size_t);
96errno_t gss_append_mbuf(mbuf_t, uint8_t *, size_t);
97errno_t gss_strip_mbuf(mbuf_t, int);
98int mbuf_walk(mbuf_t, size_t, size_t, size_t, int (*)(void *, uint8_t *, size_t), void *);
99
100void do_crypt_init(crypt_walker_ctx_t, int, crypto_ctx_t, cccbc_ctx *);
101int do_crypt(void *, uint8_t *, size_t);
102void do_hmac_init(hmac_walker_ctx_t, crypto_ctx_t, void *);
103int do_hmac(void *, uint8_t *, size_t);
104void do_hmac_destroy(hmac_walker_ctx_t, crypto_ctx_t);
105
106void krb5_make_usage(uint32_t, uint8_t, uint8_t[KRB5_USAGE_LEN]);
107void krb5_key_derivation(crypto_ctx_t, const void *, size_t, krb5_key_t *, size_t);
108void cc_key_schedule_create(crypto_ctx_t);
109void gss_crypto_ctx_free(crypto_ctx_t);
110int gss_crypto_ctx_init(struct crypto_ctx *, lucid_context_t);
111
112errno_t krb5_crypt_mbuf(crypto_ctx_t, mbuf_t *, size_t, int, cccbc_ctx *);
113int krb5_mic(crypto_ctx_t, gss_buffer_t, gss_buffer_t, gss_buffer_t, uint8_t *, int *, int, int);
114int krb5_mic_mbuf(crypto_ctx_t, gss_buffer_t, mbuf_t, size_t, size_t, gss_buffer_t, uint8_t *, int *, int, int);
115
116uint32_t gss_krb5_cfx_get_mic(uint32_t *, gss_ctx_id_t, gss_qop_t, gss_buffer_t, gss_buffer_t);
117uint32_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);
118uint32_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 *);
119errno_t krb5_cfx_crypt_mbuf(crypto_ctx_t, mbuf_t *, size_t *, int, int);
120uint32_t gss_krb5_cfx_wrap_mbuf(uint32_t *, gss_ctx_id_t, int, gss_qop_t, mbuf_t *, size_t, int *);
121uint32_t gss_krb5_cfx_unwrap_mbuf(uint32_t *, gss_ctx_id_t, mbuf_t *, size_t, int *, gss_qop_t *);
122
123int gss_krb5_mech_is_initialized(void);
124void gss_krb5_mech_init(void);
125
126/* Debugging routines */
127void
128printmbuf(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(mbuf: mb)) {
136 if (offset >= mbuf_len(mbuf: mb)) {
137 offset -= mbuf_len(mbuf: mb);
138 continue;
139 }
140 for (i = offset; len && i < mbuf_len(mbuf: mb); i++) {
141 const char *s = (cout % 8) ? " " : (cout % 16) ? " " : "\n";
142 printf("%02x%s", ((uint8_t *)mbuf_data(mbuf: 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
154void
155printgbuf(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
176static volatile uint32_t gss_krb5_mech_initted = GSS_KRB5_NOT_INITIALIZED;
177
178int
179gss_krb5_mech_is_initialized(void)
180{
181 return gss_krb5_mech_initted == GSS_KRB5_NOT_INITIALIZED;
182}
183
184static void
185gss_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
191static void
192gss_krb5_key_free(krb5_key_t *krb_key, int free)
193{
194 if (free) {
195 cc_clear(len: krb_key->key_len, dst: krb_key->key_val);
196 kfree_data(krb_key->key_val, krb_key->key_len);
197 }
198 memset(s: krb_key, c: 0, n: sizeof(krb5_key_t));
199}
200
201static void
202gss_krb5_key_ctx_free(krb5_key_t *krb_key, void *ctx_key)
203{
204 gss_krb5_key_free(krb_key, free: krb_key->key_val && ctx_key != krb_key->key_val);
205}
206
207void
208gss_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(milliseconds: 10);
220 }
221 return;
222 }
223 gss_krb5_mech_initted = GSS_KRB5_INITIALIZED;
224}
225
226uint32_t
227gss_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
244size_t
245gss_mbuf_len(mbuf_t mb, size_t offset)
246{
247 size_t len;
248
249 for (len = 0; mb; mb = mbuf_next(mbuf: mb)) {
250 len += mbuf_len(mbuf: 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 */
263static errno_t
264split_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(mbuf: mb) == offset) {
276 *nmb = mbuf_next(mbuf: mb);
277 if (!join) {
278 mbuf_setnext(mbuf: mb, NULL);
279 }
280 return 0;
281 }
282
283 if (offset > mbuf_len(mbuf: mb)) {
284 return EINVAL;
285 }
286
287 error = mbuf_split(src: mb, offset, how: MBUF_WAITOK, new_mbuf: nmb);
288 if (error) {
289 return error;
290 }
291
292 if (mbuf_flags(mbuf: *nmb) & MBUF_PKTHDR) {
293 /* We don't want to copy the pkthdr. mbuf_split does that. */
294 error = mbuf_setflags_mask(mbuf: *nmb, flags: ~MBUF_PKTHDR, mask: MBUF_PKTHDR);
295 }
296
297 if (join) {
298 /* Join the chain again */
299 mbuf_setnext(mbuf: mb, next: *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
319errno_t
320gss_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(mbuf: mb); mb = mbuf_next(mbuf: mb)) {
334 len -= mbuf_len(mbuf: 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, offset: len, nmb: 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(mb: *subchain, offset: 0);
351 length = (length > len) ? len : length;
352 *subchain_length = length;
353
354 for (len = length, mb = *subchain; mb && len > mbuf_len(mbuf: mb); mb = mbuf_next(mbuf: mb)) {
355 len -= mbuf_len(mbuf: mb);
356 }
357
358 error = split_one_mbuf(mb, offset: len, nmb: tail, join);
359
360 return error;
361}
362
363mbuf_t
364gss_join_mbuf(mbuf_t head, mbuf_t body, mbuf_t tail)
365{
366 mbuf_t mb;
367
368 for (mb = head; mb && mbuf_next(mbuf: mb); mb = mbuf_next(mbuf: mb)) {
369 ;
370 }
371 if (mb) {
372 mbuf_setnext(mbuf: mb, next: body);
373 }
374 for (mb = body; mb && mbuf_next(mbuf: mb); mb = mbuf_next(mbuf: mb)) {
375 ;
376 }
377 if (mb) {
378 mbuf_setnext(mbuf: mb, next: tail);
379 }
380 mb = head ? head : (body ? body : tail);
381 return mb;
382}
383
384/*
385 * Prepend size bytes to the mbuf chain.
386 */
387errno_t
388gss_prepend_mbuf(mbuf_t *chain, uint8_t *bytes, size_t size)
389{
390 uint8_t *data = mbuf_data(mbuf: *chain);
391 size_t leading = mbuf_leadingspace(mbuf: *chain);
392 size_t trailing = mbuf_trailingspace(mbuf: *chain);
393 size_t mlen = mbuf_len(mbuf: *chain);
394 errno_t error;
395
396 if (size > leading && size <= leading + trailing) {
397 data = memmove(dst: data + size - leading, src: data, n: mlen);
398 mbuf_setdata(mbuf: *chain, data, len: mlen);
399 }
400
401 error = mbuf_prepend(mbuf: chain, len: size, how: MBUF_WAITOK);
402 if (error) {
403 return error;
404 }
405 data = mbuf_data(mbuf: *chain);
406 memcpy(dst: data, src: bytes, n: size);
407
408 return 0;
409}
410
411errno_t
412gss_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(mbuf: mb)) {
422 len += mbuf_len(mbuf: mb);
423 }
424
425 return mbuf_copyback(mbuf: chain, offset: len, length: size, data: bytes, how: MBUF_WAITOK);
426}
427
428errno_t
429gss_strip_mbuf(mbuf_t chain, int size)
430{
431 if (chain == NULL) {
432 return EINVAL;
433 }
434
435 mbuf_adj(mbuf: chain, len: 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 */
451int
452mbuf_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(mbuf: mb)) {
461 ptr = mbuf_data(mbuf: mb);
462 mlen = mbuf_len(mbuf: 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(mbuf: 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(len: blocksize, dst: block);
521 }
522 memcpy(dst: block, src: ptr, n: residue);
523 if (len && nmb) {
524 mlen = mbuf_len(mbuf: nmb);
525 if (mlen < offset) {
526 error = mbuf_pullup(mbuf: &nmb, len: offset - mlen);
527 if (error) {
528 mbuf_setnext(mbuf: mb, NULL);
529 kfree_data(block, blocksize);
530 return error;
531 }
532 }
533 nptr = mbuf_data(mbuf: nmb);
534 memcpy(dst: block + residue, src: nptr, n: 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(dst: ptr, src: block, n: residue);
543 if (nptr) {
544 memcpy(dst: nptr, src: block + residue, n: offset);
545 }
546 kfree_data(block, blocksize);
547 }
548 }
549
550 return error;
551}
552
553void
554do_crypt_init(crypt_walker_ctx_t wctx, int encrypt, crypto_ctx_t cctx, cccbc_ctx *ks)
555{
556 memset(s: wctx, c: 0, n: 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(mode: wctx->ccmode, iv_ctx: wctx->iv, NULL);
562}
563
564int
565do_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(mode: wctx->ccmode, ctx: wctx->crypt_ctx, iv: wctx->iv, nblocks, in: data, out: data);
573 wctx->length += len;
574
575 return 0;
576}
577
578void
579do_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(di: cctx->di, ctx: wctx->hmac_ctx, key_len: cctx->keylen, key);
586}
587
588int
589do_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(di: wctx->di, ctx: wctx->hmac_ctx, data_len: len, data);
594
595 return 0;
596}
597
598void
599do_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
605int
606krb5_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(lck: &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(lck: &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(di: ctx->di, ctx: hmac_ctx, key_len: ctx->keylen, key: key2use);
632
633 if (header) {
634 cchmac_update(di: ctx->di, ctx: hmac_ctx, data_len: header->length, data: header->value);
635 }
636
637 cchmac_update(di: ctx->di, ctx: hmac_ctx, data_len: bp->length, data: bp->value);
638
639 if (trailer) {
640 cchmac_update(di: ctx->di, ctx: hmac_ctx, data_len: trailer->length, data: trailer->value);
641 }
642
643 cchmac_final(di: ctx->di, ctx: hmac_ctx, mac: digest);
644
645 if (verify) {
646 *verify = (memcmp(s1: mic, s2: digest, n: ctx->digest_size) == 0);
647 } else {
648 memcpy(dst: mic, src: digest, n: ctx->digest_size);
649 }
650
651 kfree_data(digest, ctx->di->output_size);
652 return 0;
653}
654
655int
656krb5_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(lck: &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(lck: &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: &wctx, cctx: ctx, key: key2use);
684
685 if (header) {
686 cchmac_update(di: ctx->di, ctx: wctx.hmac_ctx, data_len: header->length, data: header->value);
687 }
688
689 error = mbuf_walk(mbp, offset, len, blocksize: 1, crypto_fn: do_hmac, ctx: &wctx);
690
691 if (error) {
692 kfree_data(digest, ctx->di->output_size);
693 return error;
694 }
695 if (trailer) {
696 cchmac_update(di: ctx->di, ctx: wctx.hmac_ctx, data_len: trailer->length, data: trailer->value);
697 }
698
699 cchmac_final(di: ctx->di, ctx: wctx.hmac_ctx, mac: digest);
700 do_hmac_destroy(wctx: &wctx, cctx: ctx);
701
702 if (verify) {
703 *verify = (memcmp(s1: mic, s2: digest, n: ctx->digest_size) == 0);
704 if (!*verify) {
705 kfree_data(digest, ctx->di->output_size);
706 return EBADRPC;
707 }
708 } else {
709 memcpy(dst: mic, src: digest, n: ctx->digest_size);
710 }
711
712 kfree_data(digest, ctx->di->output_size);
713 return 0;
714}
715
716errno_t
717/* __attribute__((optnone)) */
718krb5_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(lck: &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(lck: &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(chain: *mbp, bytes: block, size: 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(chain: *mbp, offset: 0, subchain_length: &plen, subchain: &mb, tail: &lmb, join: 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(chain: *mbp, bytes: pad_block, size: 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: &wctx, encrypt, cctx: ctx, ks);
787 if (plen) {
788 error = mbuf_walk(mbp: *mbp, offset: 0, len: plen, blocksize: ccmode->block_size, crypto_fn: do_crypt, ctx: &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(mbuf: lmb, offset: 0, length: cts_len, out_data: cts_pad);
804 mbuf_freem(mbuf: lmb);
805 do_ccpad(ccmode, wctx.crypt_ctx, wctx.iv, cts_len, cts_pad, cts_pad);
806 gss_append_mbuf(chain: *mbp, bytes: cts_pad, size: 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
818static int
819rr13(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(dst: tmp, src: buf, n: 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. */
871static void
872add1(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
890static int
891krb5_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(a: size, b: 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(dst: buf, src: instr, n: len);
905 memset(s: foldstr, c: 0, n: size);
906 do {
907 memcpy(dst: tmp + l, src: buf, n: len);
908 l += len;
909 ret = rr13(buf, len: len * 8);
910 if (ret) {
911 goto out;
912 }
913 while (l >= size) {
914 add1(a: foldstr, b: tmp, len: size);
915 l -= size;
916 if (l == 0) {
917 break;
918 }
919 memmove(dst: tmp, src: tmp + size, n: l);
920 }
921 } while (l != 0);
922out:
923
924 kfree_data(tmp, maxlen);
925 kfree_data(buf, len);
926 return ret;
927}
928
929void
930krb5_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
940void
941krb5_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(krb_key: dkey, kalloc_data(nblocks * blocksize, Z_WAITOK | Z_ZERO), len: nblocks * blocksize);
953 dkptr = dkey->key_val;
954
955 krb5_n_fold(instr: cons, len: conslen, foldstr: block, size: blocksize);
956 cccbc_init(mode: ctx->enc_mode, ctx: enc_ctx, key_len: ctx->keylen, key: ctx->key);
957 for (size_t i = 0; i < nblocks; i++) {
958 cccbc_set_iv(mode: ctx->enc_mode, iv_ctx: iv, NULL);
959 cccbc_update(mode: ctx->enc_mode, ctx: enc_ctx, iv, nblocks: 1, in: block, out: block);
960 memcpy(dst: dkptr, src: block, n: blocksize);
961 dkptr += blocksize;
962 }
963 kfree_data(block, blocksize);
964}
965
966static void
967des_make_key(const uint8_t rawkey[7], uint8_t deskey[8])
968{
969 uint8_t val = 0;
970
971 memcpy(dst: deskey, src: rawkey, n: 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(key: deskey, length: 8);
977}
978
979static void
980krb5_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(krb_key: des3key, kalloc_data(3 * cbcmode->block_size, Z_WAITOK | Z_ZERO), len: 3 * cbcmode->block_size);
988 rawkey_len = 3 * (cbcmode->block_size - 1);
989 krb5_key_derivation(ctx, cons, conslen, dkey: &rawkey, dklen: 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(rawkey: rptr, deskey: kptr);
995 rptr += cbcmode->block_size - 1;
996 kptr += cbcmode->block_size;
997 }
998
999 gss_krb5_key_free(krb_key: &rawkey, free: 1);
1000}
1001
1002/*
1003 * Create a key schecule
1004 *
1005 */
1006void
1007cc_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(mode: ctx->enc_mode, ctx: ctx->ks.enc, key_len: ctx->keylen, key: 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(mode: ctx->dec_mode, ctx: ctx->ks.dec, key_len: ctx->keylen, key: ctx->key);
1022 }
1023 }
1024 OS_FALLTHROUGH;
1025 case 1: {
1026 if (ctx->ks.enc == NULL) {
1027 krb5_make_usage(usage_no: lctx->initiate ?
1028 KRB5_USAGE_INITIATOR_SEAL : KRB5_USAGE_ACCEPTOR_SEAL,
1029 suffix: 0xAA, usage_string);
1030 krb5_key_derivation(ctx, cons: usage_string, KRB5_USAGE_LEN, dkey: &ekey, dklen: ctx->keylen);
1031 ctx->ks.enc = kalloc_data(ctx->enc_mode->size, Z_WAITOK | Z_ZERO);
1032 cccbc_init(mode: ctx->enc_mode, ctx: ctx->ks.enc, key_len: ctx->keylen, key: ekey.key_val);
1033 gss_krb5_key_free(krb_key: &ekey, free: 1);
1034 }
1035 if (ctx->ks.dec == NULL) {
1036 krb5_make_usage(usage_no: lctx->initiate ?
1037 KRB5_USAGE_ACCEPTOR_SEAL : KRB5_USAGE_INITIATOR_SEAL,
1038 suffix: 0xAA, usage_string);
1039 krb5_key_derivation(ctx, cons: usage_string, KRB5_USAGE_LEN, dkey: &ekey, dklen: ctx->keylen);
1040 ctx->ks.dec = kalloc_data(ctx->dec_mode->size, Z_WAITOK | Z_ZERO);
1041 cccbc_init(mode: ctx->dec_mode, ctx: ctx->ks.dec, key_len: ctx->keylen, key: ekey.key_val);
1042 gss_krb5_key_free(krb_key: &ekey, free: 1);
1043 }
1044 if (ctx->ks.ikeys[GSS_SND].key_val == NULL) {
1045 krb5_make_usage(usage_no: lctx->initiate ?
1046 KRB5_USAGE_INITIATOR_SEAL : KRB5_USAGE_ACCEPTOR_SEAL,
1047 suffix: 0x55, usage_string);
1048 krb5_key_derivation(ctx, cons: usage_string, KRB5_USAGE_LEN, dkey: &ctx->ks.ikeys[GSS_SND], dklen: ctx->keylen);
1049 }
1050 if (ctx->ks.ikeys[GSS_RCV].key_val == NULL) {
1051 krb5_make_usage(usage_no: lctx->initiate ?
1052 KRB5_USAGE_ACCEPTOR_SEAL : KRB5_USAGE_INITIATOR_SEAL,
1053 suffix: 0x55, usage_string);
1054 krb5_key_derivation(ctx, cons: usage_string, KRB5_USAGE_LEN, dkey: &ctx->ks.ikeys[GSS_RCV], dklen: ctx->keylen);
1055 }
1056 }
1057 }
1058}
1059
1060void
1061gss_crypto_ctx_free(crypto_ctx_t ctx)
1062{
1063 lck_mtx_destroy(lck: &ctx->lock, grp: &gss_krb5_mech_grp);
1064
1065 gss_krb5_key_ctx_free(krb_key: &ctx->ks.ikeys[GSS_SND], ctx_key: ctx->key);
1066 gss_krb5_key_ctx_free(krb_key: &ctx->ks.ikeys[GSS_RCV], ctx_key: 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(krb_key: &ctx->ckeys[GSS_SND], ctx_key: ctx->key);
1076 gss_krb5_key_ctx_free(krb_key: &ctx->ckeys[GSS_RCV], ctx_key: ctx->key);
1077 ctx->key = NULL;
1078 ctx->keylen = 0;
1079}
1080
1081int
1082gss_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(usage_no: ctx->gss_ctx->initiate ?
1108 KRB5_USAGE_INITIATOR_SIGN : KRB5_USAGE_ACCEPTOR_SIGN,
1109 suffix: 0x99, usage_string);
1110 krb5_key_derivation(ctx, cons: usage_string, KRB5_USAGE_LEN, dkey: &ctx->ckeys[GSS_SND], dklen: ctx->keylen);
1111 krb5_make_usage(usage_no: ctx->gss_ctx->initiate ?
1112 KRB5_USAGE_ACCEPTOR_SIGN : KRB5_USAGE_INITIATOR_SIGN,
1113 suffix: 0x99, usage_string);
1114 krb5_key_derivation(ctx, cons: usage_string, KRB5_USAGE_LEN, dkey: &ctx->ckeys[GSS_RCV], dklen: 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(krb_key: &ctx->ks.ikeys[GSS_SND], key: ctx->key, len: ctx->keylen);
1122 gss_krb5_key_set(krb_key: &ctx->ks.ikeys[GSS_RCV], key: ctx->key, len: 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, suffix: 0x99, usage_string);
1129 krb5_3des_key_derivation(ctx, cons: usage_string, KRB5_USAGE_LEN, des3key: &ctx->ckeys[GSS_SND]);
1130 krb5_3des_key_derivation(ctx, cons: usage_string, KRB5_USAGE_LEN, des3key: &ctx->ckeys[GSS_RCV]);
1131 break;
1132 default:
1133 return ENOTSUP;
1134 }
1135
1136 lck_mtx_init(lck: &ctx->lock, grp: &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 */
1145typedef 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
1152typedef 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
1167const 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
1174const 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
1183static int
1184gss_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
1218uint32_t
1219gss_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(dst: &token.SND_SEQ, src: &seq, n: 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(ctx: cctx, NULL, bp: mbp, trailer: &header, mic: (uint8_t *)mic->value + sizeof(token), NULL, ikey: 0, reverse: 0);
1251
1252 if (*minor) {
1253 mic->length = 0;
1254 kfree_data(mic->value, mic->length);
1255 } else {
1256 memcpy(dst: mic->value, src: &token, n: sizeof(token));
1257 }
1258
1259 return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE;
1260}
1261
1262uint32_t
1263gss_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(dst: &token.SND_SEQ, src: &seq, n: 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(mb: mbp, offset);
1300 *minor = krb5_mic_mbuf(ctx: cctx, NULL, mbp, offset, len, trailer: &header, mic: (uint8_t *)mic->value + sizeof(token), NULL, ikey: 0, reverse: 0);
1301
1302 if (*minor) {
1303 mic->length = 0;
1304 kfree_data(mic->value, mic->length);
1305 } else {
1306 memcpy(dst: mic->value, src: &token, n: sizeof(token));
1307 }
1308
1309 return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE;
1310}
1311
1312
1313uint32_t
1314gss_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(ctx: cctx, NULL, mbp, offset, len, trailer: &header, mic: digest, verify: &verified, ikey: 0, reverse: 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(dst: &seq, src: token->SND_SEQ, n: 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
1360errno_t
1361krb5_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(buffer: confounder, numBytes: (u_int)ccmode->block_size);
1378 error = gss_prepend_mbuf(chain: mbp, bytes: confounder, size: 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(chain: *mbp, bytes: mpad, size: r);
1394 if (error) {
1395 goto out;
1396 }
1397 }
1398 tlen += r;
1399 error = krb5_mic_mbuf(ctx, NULL, mbp: *mbp, offset: 0, len: tlen, NULL, mic: digest, NULL, ikey: 1, reverse: 0);
1400 if (error) {
1401 goto out;
1402 }
1403 error = krb5_crypt_mbuf(ctx, mbp, len: tlen, encrypt: 1, NULL);
1404 if (error) {
1405 goto out;
1406 }
1407 error = gss_append_mbuf(chain: *mbp, bytes: digest, size: 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(mbuf: *mbp, offset: tlen, length: ctx->digest_size, out_data: digest);
1425 /* Remove the digest from the mbuffer */
1426 error = gss_strip_mbuf(chain: *mbp, size: -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(usage_no: lctx->initiate ?
1443 KRB5_USAGE_INITIATOR_SEAL : KRB5_USAGE_ACCEPTOR_SEAL,
1444 suffix: 0xAA, usage_string);
1445 krb5_key_derivation(ctx, cons: usage_string, KRB5_USAGE_LEN, dkey: &ekey, dklen: ctx->keylen);
1446 ks = kalloc_data(ctx->dec_mode->size, Z_WAITOK | Z_ZERO);
1447 cccbc_init(mode: ctx->dec_mode, ctx: ks, key_len: ctx->keylen, key: ekey.key_val);
1448 gss_krb5_key_free(krb_key: &ekey, free: 1);
1449 }
1450 error = krb5_crypt_mbuf(ctx, mbp, len: tlen, encrypt: 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: *mbp, offset: 0, len: tlen, NULL, mic: digest, verify: &verf, ikey: 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(chain: *mbp, size: (int)ccmode->block_size);
1466 if (error) {
1467 goto out;
1468 }
1469 *len = tlen - ccmode->block_size;
1470 }
1471
1472 error = 0;
1473out:
1474 kfree_data(mpad, r);
1475 kfree_data(confounder, ccmode->block_size);
1476 return error;
1477}
1478
1479uint32_t
1480gss_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(dst: &token.SND_SEQ, src: &seq, n: 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(chain: *mbp, bytes: pad, size: plen);
1530 len += plen;
1531 }
1532 if (error == 0) {
1533 error = gss_append_mbuf(chain: *mbp, bytes: (uint8_t *)&token, size: 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(ctx: cctx, mbp, len: &len, encrypt: 1, reverse: 0);
1538 }
1539 if (error == 0) {
1540 error = gss_prepend_mbuf(chain: mbp, bytes: (uint8_t *)&token, size: 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(ctx: cctx, NULL, mbp: *mbp, offset: 0, len, trailer: &header, mic: digest, NULL, ikey: 1, reverse: 0);
1551 if (error == 0) {
1552 error = gss_append_mbuf(chain: *mbp, bytes: digest, size: cctx->digest_size);
1553 if (error == 0) {
1554 uint32_t plen = htonl(cctx->digest_size);
1555 memcpy(dst: token.EC, src: &plen, n: 2);
1556 error = gss_prepend_mbuf(chain: mbp, bytes: (uint8_t *)&token, size: 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 */
1571static void
1572gss_krb5_cfx_unwrap_rrc_mbuf(mbuf_t header, size_t rrc)
1573{
1574 mbuf_t body, trailer;
1575
1576 gss_normalize_mbuf(chain: header, offset: sizeof(gss_cfx_wrap_token_desc), subchain_length: &rrc, subchain: &trailer, tail: &body, join: 0);
1577 gss_join_mbuf(head: header, body, tail: trailer);
1578}
1579
1580uint32_t
1581gss_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(mbuf: *mbp, offset: 0, length: sizeof(gss_cfx_wrap_token_desc), out_data: &token);
1598 gss_strip_mbuf(chain: *mbp, size: 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(dst: &seq, src: token.SND_SEQ, n: 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(header: *mbp, rrc);
1631 }
1632 error = krb5_cfx_crypt_mbuf(ctx: cctx, mbp, len: &len, encrypt: 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(mbuf: *mbp, offset: len, length: sizeof(gss_cfx_wrap_token_desc), out_data: &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(s1: &token, s2: &etoken, n: 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(chain: *mbp, size: -(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(mbuf: *mbp, offset: len, length: cctx->digest_size, out_data: digest);
1663 gss_strip_mbuf(chain: *mbp, size: -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(ctx: cctx, NULL, mbp: *mbp, offset: 0, len, trailer: &header, mic: digest, verify: &verf, ikey: 1, reverse);
1669 if (error) {
1670 goto badrpc;
1671 }
1672 }
1673 return GSS_S_COMPLETE;
1674
1675badrpc:
1676 *minor = EBADRPC;
1677 return GSS_S_FAILURE;
1678}
1679
1680/*
1681 * RFC 1964 3DES support
1682 */
1683
1684typedef 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
1690typedef 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
1697typedef 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
1703typedef 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
1708typedef 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
1714typedef 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
1725gss_1964_header_desc tok_1964_header = {
1726 .App0 = 0x60
1727};
1728
1729gss_1964_mic_token_desc mic_1964_token = {
1730 .TOK_ID = "\x01\x01",
1731 .Filler = "\xff\xff\xff\xff"
1732};
1733
1734gss_1964_wrap_token_desc wrap_1964_token = {
1735 .TOK_ID = "\x02\x01",
1736 .Filler = "\xff\xff"
1737};
1738
1739gss_1964_delete_token_desc del_1964_token = {
1740 .TOK_ID = "\x01\x01",
1741 .Filler = "\xff\xff\xff\xff"
1742};
1743
1744gss_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
1752uint32_t gss_krb5_3des_get_mic(uint32_t *, gss_ctx_id_t, gss_qop_t, gss_buffer_t, gss_buffer_t);
1753uint32_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);
1754uint32_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 *);
1755uint32_t gss_krb5_3des_wrap_mbuf(uint32_t *, gss_ctx_id_t, int, gss_qop_t, mbuf_t *, size_t, int *);
1756uint32_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 */
1761static ssize_t
1762gss_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 */
1786static int
1787gss_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 */
1799static void
1800gss_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
1818static void
1819gss_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(len: 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(pp: &tokptr, len: 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(mode: cctx->enc_mode, iv_ctx: iv, iv: hash->value);
1849 cccbc_init(mode: cctx->enc_mode, ctx: enc_ctx, key_len: cctx->keylen, key: cctx->key);
1850 cccbc_update(mode: cctx->enc_mode, ctx: enc_ctx, iv, nblocks: 1, in: tokbody->SND_SEQ, out: tokbody->SND_SEQ);
1851
1852 assert(hash->length == cctx->digest_size);
1853 memcpy(dst: tokbody->Hash, src: hash->value, n: hash->length);
1854 des3_token->length = alloclen;
1855 des3_token->value = token;
1856}
1857
1858static int
1859gss_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(str: __func__, buf: intok);
1875 return EBADRPC;
1876 }
1877 tokptr = token->AppLen;
1878 length = gss_krb5_der_length_get(pp: &tokptr);
1879 if (length < 0) {
1880 printf("%s: invalid length\n", __func__);
1881 printgbuf(str: __func__, buf: intok);
1882 return EBADRPC;
1883 }
1884 toklen = sizeof(gss_1964_header_desc) + gss_krb5_der_length_size(len: 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(str: __func__, buf: 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(s1: tokbody->kerb_mech, s2: body_1964_token.kerb_mech, n: tokbody->OIDLen) != 0) {
1906 printf("%s: Invalid mechanism\n", __func__);
1907 printgbuf(str: __func__, buf: intok);
1908 return EBADRPC;
1909 }
1910 if (memcmp(s1: &tokbody->body, s2: &body, n: sizeof(gss_1964_tok_type)) != 0) {
1911 printf("%s: Invalid body\n", __func__);
1912 printgbuf(str: __func__, buf: 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(mode: cctx->dec_mode, iv_ctx: iv, iv: tokbody->Hash);
1922 cccbc_init(mode: cctx->dec_mode, ctx: dec_ctx, key_len: cctx->keylen, key: cctx->key);
1923 cccbc_update(mode: cctx->dec_mode, ctx: dec_ctx, iv, nblocks: 1, in: block, out: 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(str: __func__, buf: intok);
1930 return EAUTH;
1931 }
1932 }
1933
1934 memcpy(dst: &seq, src: tokbody->SND_SEQ, n: sizeof(uint32_t));
1935
1936 lctx->recv_seq = ntohl(seq);
1937
1938 assert(hash->length >= cctx->digest_size);
1939 memcpy(dst: hash->value, src: tokbody->Hash, n: cctx->digest_size);
1940
1941 return 0;
1942}
1943
1944uint32_t
1945gss_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(ctx: cctx, header: &header, bp: mbp, NULL, mic: hashval, NULL, ikey: 0, reverse: 0);
1966 if (*minor) {
1967 return GSS_S_FAILURE;
1968 }
1969
1970 /* Make the token */
1971 gss_krb5_3des_token_put(ctx, body: tokbody, hash: &hash, datalen: 0, des3_token: mic);
1972
1973 return GSS_S_COMPLETE;
1974}
1975
1976uint32_t
1977gss_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(ctx: cctx, header: &header, mbp, offset, len, NULL, mic: hashval, NULL, ikey: 0, reverse: 0);
2000 if (*minor) {
2001 return GSS_S_FAILURE;
2002 }
2003
2004 /* Make the token */
2005 gss_krb5_3des_token_put(ctx, body: tokbody, hash: &hash, datalen: 0, des3_token: mic);
2006
2007 return GSS_S_COMPLETE;
2008}
2009
2010uint32_t
2011gss_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, intok: mic, body: mtok, hash: &hash, NULL, NULL, reverse: 0);
2038 if (*minor) {
2039 return GSS_S_FAILURE;
2040 }
2041
2042 *minor = krb5_mic_mbuf(ctx: cctx, header: &header, mbp, offset, len, NULL, mic: hashval, verify: &verf, ikey: 0, reverse: 0);
2043 if (*minor) {
2044 return GSS_S_FAILURE;
2045 }
2046
2047 return verf ? GSS_S_COMPLETE : GSS_S_BAD_SIG;
2048}
2049
2050uint32_t
2051gss_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(buffer: confounder, numBytes: (u_int)ccmode->block_size);
2092 *minor = gss_prepend_mbuf(chain: mbp, bytes: confounder, size: 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(chain: *mbp, bytes: pad, size: 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(ctx: cctx, header: &header, mbp: *mbp, offset: 0, len, NULL, mic: hashval, NULL, ikey: 0, reverse: 0);
2111 if (*minor) {
2112 goto out;
2113 }
2114
2115 /* Make the token */
2116 gss_krb5_3des_token_put(ctx, body: tokbody, hash: &hash, datalen: len, des3_token: &mic);
2117
2118 if (conf_flag) {
2119 *minor = krb5_crypt_mbuf(ctx: cctx, mbp, len, encrypt: 1, ks: 0);
2120 if (*minor) {
2121 goto out;
2122 }
2123 }
2124
2125 *minor = gss_prepend_mbuf(chain: mbp, bytes: mic.value, size: mic.length);
2126
2127out:
2128 kfree_data(confounder, ccmode->block_size);
2129 return *minor ? GSS_S_FAILURE : GSS_S_COMPLETE;
2130}
2131
2132uint32_t
2133gss_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(mbuf: *mbp, offset: 0, length: itoken.length, out_data: 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, intok: &itoken, body: wrap, hash: &hash, offset: &offset, len: &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(chain: *mbp, offset, subchain_length: &length, subchain: &smb, tail: &tmb, join: 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(ctx: cctx, mbp: &smb, len: length, encrypt: 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(ctx: cctx, header: &header, mbp: smb, offset: 0, len: length, NULL, mic: hashval, verify: &verified, ikey: 0, reverse: 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(mbuf: smb, offset: length - 1, length: 1, out_data: &padlen);
2225 if (*minor) {
2226 return GSS_S_FAILURE;
2227 }
2228
2229 /* Strip the confounder and trailing pad bytes */
2230 gss_strip_mbuf(chain: smb, size: -padlen);
2231 assert(ccmode->block_size <= INT_MAX);
2232 gss_strip_mbuf(chain: smb, size: (int)ccmode->block_size);
2233
2234 if (*mbp != smb) {
2235 mbuf_freem(mbuf: *mbp);
2236 *mbp = smb;
2237 }
2238
2239 return GSS_S_COMPLETE;
2240}
2241
2242static const char *
2243etype_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
2257static int
2258supported_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 */
2296uint32_t
2297gss_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(proto: ctx->gss_lucid_ctx.key_data.proto, etype: 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
2332uint32_t
2333gss_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(proto: ctx->gss_lucid_ctx.key_data.proto, etype: 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
2374uint32_t
2375gss_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(proto: ctx->gss_lucid_ctx.key_data.proto, etype: 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
2421uint32_t
2422gss_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(proto: ctx->gss_lucid_ctx.key_data.proto, etype: ctx->gss_cryptor.etype)) {
2450 *minor = ENOTSUP;
2451 return GSS_S_FAILURE;
2452 }
2453
2454 gss_normalize_mbuf(chain: *mbp, offset, subchain_length: &len, subchain: &smb, tail: &tmb, join: 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, mbp: &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, mbp: &smb, len, conf: conf_state);
2464 break;
2465 }
2466
2467 if (offset) {
2468 gss_join_mbuf(head: *mbp, body: smb, tail: tmb);
2469 } else {
2470 *mbp = smb;
2471 gss_join_mbuf(head: smb, body: tmb, NULL);
2472 }
2473
2474 return major;
2475}
2476
2477uint32_t
2478gss_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(proto: ctx->gss_lucid_ctx.key_data.proto, etype: ctx->gss_cryptor.etype)) {
2507 *minor = ENOTSUP;
2508 return GSS_S_FAILURE;
2509 }
2510
2511 gss_normalize_mbuf(chain: *mbp, offset, subchain_length: &len, subchain: &smb, tail: &tmb, join: 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, mbp: &smb, len, conf_state: conf_flag, qop);
2517 break;
2518 case 1:
2519 /* RFC 4121 CFX case */
2520 major = gss_krb5_cfx_unwrap_mbuf(minor, ctx, mbp: &smb, len, conf_flag, qop);
2521 break;
2522 }
2523
2524 if (offset) {
2525 gss_join_mbuf(head: *mbp, body: smb, tail: tmb);
2526 } else {
2527 *mbp = smb;
2528 gss_join_mbuf(head: smb, body: tmb, NULL);
2529 }
2530
2531 return major;
2532}
2533
2534#include <nfs/xdr_subs.h>
2535
2536static int
2537xdr_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 }
2638out:
2639 return error;
2640}
2641
2642gss_ctx_id_t
2643gss_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, length: datalen, lctx: &ctx->gss_lucid_ctx) ||
2654 !supported_etype(proto: ctx->gss_lucid_ctx.key_data.proto, etype: 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: &ctx->gss_cryptor, lucid: &ctx->gss_lucid_ctx);
2661 return ctx;
2662}
2663
2664void
2665gss_krb5_destroy_context(gss_ctx_id_t ctx)
2666{
2667 if (ctx == NULL) {
2668 return;
2669 }
2670 gss_crypto_ctx_free(ctx: &ctx->gss_cryptor);
2671 xb_free(ctx->gss_lucid_ctx.ctx_key.key.key_val);
2672 cc_clear(len: sizeof(lucid_context_t), dst: &ctx->gss_lucid_ctx);
2673 kfree_type(struct gss_ctx_id_desc, ctx);
2674}
2675