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