1 /*
2 * Copyright (c) 2003, PADL Software Pty Ltd.
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 *
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 *
16 * 3. Neither the name of PADL Software nor the names of its contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 */
32
33 #include "gsskrb5_locl.h"
34
35 /*
36 * Implementation of RFC 4121
37 */
38
39 #define CFXSentByAcceptor (1 << 0)
40 #define CFXSealed (1 << 1)
41 #define CFXAcceptorSubkey (1 << 2)
42
43 krb5_error_code
_gsskrb5cfx_wrap_length_cfx(krb5_context context,krb5_crypto crypto,int conf_req_flag,int dce_style,size_t input_length,size_t * output_length,size_t * cksumsize,uint16_t * padlength)44 _gsskrb5cfx_wrap_length_cfx(krb5_context context,
45 krb5_crypto crypto,
46 int conf_req_flag,
47 int dce_style,
48 size_t input_length,
49 size_t *output_length,
50 size_t *cksumsize,
51 uint16_t *padlength)
52 {
53 krb5_error_code ret;
54 krb5_cksumtype type;
55
56 /* 16-byte header is always first */
57 *output_length = sizeof(gss_cfx_wrap_token_desc);
58 *padlength = 0;
59
60 ret = krb5_crypto_get_checksum_type(context, crypto, &type);
61 if (ret)
62 return ret;
63
64 ret = krb5_checksumsize(context, type, cksumsize);
65 if (ret)
66 return ret;
67
68 if (conf_req_flag) {
69 size_t padsize;
70
71 /* Header is concatenated with data before encryption */
72 input_length += sizeof(gss_cfx_wrap_token_desc);
73
74 if (dce_style) {
75 ret = krb5_crypto_getblocksize(context, crypto, &padsize);
76 } else {
77 ret = krb5_crypto_getpadsize(context, crypto, &padsize);
78 }
79 if (ret) {
80 return ret;
81 }
82 if (padsize > 1) {
83 /* XXX check this */
84 *padlength = padsize - (input_length % padsize);
85
86 /* We add the pad ourselves (noted here for completeness only) */
87 input_length += *padlength;
88 }
89
90 *output_length += krb5_get_wrapped_length(context,
91 crypto, input_length);
92 } else {
93 /* Checksum is concatenated with data */
94 *output_length += input_length + *cksumsize;
95 }
96
97 assert(*output_length > input_length);
98
99 return 0;
100 }
101
102 OM_uint32
_gssapi_wrap_size_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,OM_uint32 req_output_size,OM_uint32 * max_input_size)103 _gssapi_wrap_size_cfx(OM_uint32 *minor_status,
104 const gsskrb5_ctx ctx,
105 krb5_context context,
106 int conf_req_flag,
107 gss_qop_t qop_req,
108 OM_uint32 req_output_size,
109 OM_uint32 *max_input_size)
110 {
111 krb5_error_code ret;
112
113 *max_input_size = 0;
114
115 /* 16-byte header is always first */
116 if (req_output_size < 16)
117 return 0;
118 req_output_size -= 16;
119
120 if (conf_req_flag) {
121 size_t wrapped_size, sz;
122
123 wrapped_size = req_output_size + 1;
124 do {
125 wrapped_size--;
126 sz = krb5_get_wrapped_length(context,
127 ctx->crypto, wrapped_size);
128 } while (wrapped_size && sz > req_output_size);
129 if (wrapped_size == 0)
130 return 0;
131
132 /* inner header */
133 if (wrapped_size < 16)
134 return 0;
135
136 wrapped_size -= 16;
137
138 *max_input_size = wrapped_size;
139 } else {
140 krb5_cksumtype type;
141 size_t cksumsize;
142
143 ret = krb5_crypto_get_checksum_type(context, ctx->crypto, &type);
144 if (ret)
145 return ret;
146
147 ret = krb5_checksumsize(context, type, &cksumsize);
148 if (ret)
149 return ret;
150
151 if (req_output_size < cksumsize)
152 return 0;
153
154 /* Checksum is concatenated with data */
155 *max_input_size = req_output_size - cksumsize;
156 }
157
158 return 0;
159 }
160
161 /*
162 * Rotate "rrc" bytes to the front or back
163 */
164
165 static krb5_error_code
rrc_rotate(void * data,size_t len,uint16_t rrc,krb5_boolean unrotate)166 rrc_rotate(void *data, size_t len, uint16_t rrc, krb5_boolean unrotate)
167 {
168 u_char *tmp, buf[256];
169 size_t left;
170
171 if (len == 0)
172 return 0;
173
174 rrc %= len;
175
176 if (rrc == 0)
177 return 0;
178
179 left = len - rrc;
180
181 if (rrc <= sizeof(buf)) {
182 tmp = buf;
183 } else {
184 tmp = malloc(rrc);
185 if (tmp == NULL)
186 return ENOMEM;
187 }
188
189 if (unrotate) {
190 memcpy(tmp, data, rrc);
191 memmove(data, (u_char *)data + rrc, left);
192 memcpy((u_char *)data + left, tmp, rrc);
193 } else {
194 memcpy(tmp, (u_char *)data + left, rrc);
195 memmove((u_char *)data + rrc, data, left);
196 memcpy(data, tmp, rrc);
197 }
198
199 if (rrc > sizeof(buf))
200 free(tmp);
201
202 return 0;
203 }
204
205 gss_iov_buffer_desc *
_gk_find_buffer(gss_iov_buffer_desc * iov,int iov_count,OM_uint32 type)206 _gk_find_buffer(gss_iov_buffer_desc *iov, int iov_count, OM_uint32 type)
207 {
208 int i;
209
210 for (i = 0; i < iov_count; i++)
211 if (type == GSS_IOV_BUFFER_TYPE(iov[i].type))
212 return &iov[i];
213 return NULL;
214 }
215
216 OM_uint32
_gk_allocate_buffer(OM_uint32 * minor_status,gss_iov_buffer_desc * buffer,size_t size)217 _gk_allocate_buffer(OM_uint32 *minor_status, gss_iov_buffer_desc *buffer, size_t size)
218 {
219 if (buffer->type & GSS_IOV_BUFFER_FLAG_ALLOCATED) {
220 if (buffer->buffer.length == size)
221 return GSS_S_COMPLETE;
222 free(buffer->buffer.value);
223 }
224
225 buffer->buffer.value = malloc(size);
226 buffer->buffer.length = size;
227 if (buffer->buffer.value == NULL) {
228 *minor_status = ENOMEM;
229 return GSS_S_FAILURE;
230 }
231 buffer->type |= GSS_IOV_BUFFER_FLAG_ALLOCATED;
232
233 return GSS_S_COMPLETE;
234 }
235
236
237 OM_uint32
_gk_verify_buffers(OM_uint32 * minor_status,const gsskrb5_ctx ctx,const gss_iov_buffer_desc * header,const gss_iov_buffer_desc * padding,const gss_iov_buffer_desc * trailer)238 _gk_verify_buffers(OM_uint32 *minor_status,
239 const gsskrb5_ctx ctx,
240 const gss_iov_buffer_desc *header,
241 const gss_iov_buffer_desc *padding,
242 const gss_iov_buffer_desc *trailer)
243 {
244 if (header == NULL) {
245 *minor_status = EINVAL;
246 return GSS_S_FAILURE;
247 }
248
249 if (IS_DCE_STYLE(ctx)) {
250 /*
251 * In DCE style mode we reject having a padding or trailer buffer
252 */
253 if (padding) {
254 *minor_status = EINVAL;
255 return GSS_S_FAILURE;
256 }
257 if (trailer) {
258 *minor_status = EINVAL;
259 return GSS_S_FAILURE;
260 }
261 } else {
262 /*
263 * In non-DCE style mode we require having a padding buffer
264 */
265 if (padding == NULL) {
266 *minor_status = EINVAL;
267 return GSS_S_FAILURE;
268 }
269 }
270
271 *minor_status = 0;
272 return GSS_S_COMPLETE;
273 }
274
275 #if 0
276 OM_uint32
277 _gssapi_wrap_cfx_iov(OM_uint32 *minor_status,
278 gsskrb5_ctx ctx,
279 krb5_context context,
280 int conf_req_flag,
281 int *conf_state,
282 gss_iov_buffer_desc *iov,
283 int iov_count)
284 {
285 OM_uint32 major_status, junk;
286 gss_iov_buffer_desc *header, *trailer, *padding;
287 size_t gsshsize, k5hsize;
288 size_t gsstsize, k5tsize;
289 size_t rrc = 0, ec = 0;
290 int i;
291 gss_cfx_wrap_token token;
292 krb5_error_code ret;
293 int32_t seq_number;
294 unsigned usage;
295 krb5_crypto_iov *data = NULL;
296
297 header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
298 if (header == NULL) {
299 *minor_status = EINVAL;
300 return GSS_S_FAILURE;
301 }
302
303 padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
304 if (padding != NULL) {
305 padding->buffer.length = 0;
306 }
307
308 trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
309
310 major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
311 if (major_status != GSS_S_COMPLETE) {
312 return major_status;
313 }
314
315 if (conf_req_flag) {
316 size_t k5psize = 0;
317 size_t k5pbase = 0;
318 size_t k5bsize = 0;
319 size_t size = 0;
320
321 for (i = 0; i < iov_count; i++) {
322 switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
323 case GSS_IOV_BUFFER_TYPE_DATA:
324 size += iov[i].buffer.length;
325 break;
326 default:
327 break;
328 }
329 }
330
331 size += sizeof(gss_cfx_wrap_token_desc);
332
333 *minor_status = krb5_crypto_length(context, ctx->crypto,
334 KRB5_CRYPTO_TYPE_HEADER,
335 &k5hsize);
336 if (*minor_status)
337 return GSS_S_FAILURE;
338
339 *minor_status = krb5_crypto_length(context, ctx->crypto,
340 KRB5_CRYPTO_TYPE_TRAILER,
341 &k5tsize);
342 if (*minor_status)
343 return GSS_S_FAILURE;
344
345 *minor_status = krb5_crypto_length(context, ctx->crypto,
346 KRB5_CRYPTO_TYPE_PADDING,
347 &k5pbase);
348 if (*minor_status)
349 return GSS_S_FAILURE;
350
351 if (k5pbase > 1) {
352 k5psize = k5pbase - (size % k5pbase);
353 } else {
354 k5psize = 0;
355 }
356
357 if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
358 *minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
359 &k5bsize);
360 if (*minor_status)
361 return GSS_S_FAILURE;
362 ec = k5bsize;
363 } else {
364 ec = k5psize;
365 }
366
367 gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
368 gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize;
369 } else {
370 if (IS_DCE_STYLE(ctx)) {
371 *minor_status = EINVAL;
372 return GSS_S_FAILURE;
373 }
374
375 k5hsize = 0;
376 *minor_status = krb5_crypto_length(context, ctx->crypto,
377 KRB5_CRYPTO_TYPE_CHECKSUM,
378 &k5tsize);
379 if (*minor_status)
380 return GSS_S_FAILURE;
381
382 gsshsize = sizeof(gss_cfx_wrap_token_desc);
383 gsstsize = k5tsize;
384 }
385
386 /*
387 *
388 */
389
390 if (trailer == NULL) {
391 rrc = gsstsize;
392 if (IS_DCE_STYLE(ctx))
393 rrc -= ec;
394 gsshsize += gsstsize;
395 gsstsize = 0;
396 } else if (GSS_IOV_BUFFER_FLAGS(trailer->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
397 major_status = _gk_allocate_buffer(minor_status, trailer, gsstsize);
398 if (major_status)
399 goto failure;
400 } else if (trailer->buffer.length < gsstsize) {
401 *minor_status = KRB5_BAD_MSIZE;
402 major_status = GSS_S_FAILURE;
403 goto failure;
404 } else
405 trailer->buffer.length = gsstsize;
406
407 /*
408 *
409 */
410
411 if (GSS_IOV_BUFFER_FLAGS(header->type) & GSS_IOV_BUFFER_FLAG_ALLOCATE) {
412 major_status = _gk_allocate_buffer(minor_status, header, gsshsize);
413 if (major_status != GSS_S_COMPLETE)
414 goto failure;
415 } else if (header->buffer.length < gsshsize) {
416 *minor_status = KRB5_BAD_MSIZE;
417 major_status = GSS_S_FAILURE;
418 goto failure;
419 } else
420 header->buffer.length = gsshsize;
421
422 token = (gss_cfx_wrap_token)header->buffer.value;
423
424 token->TOK_ID[0] = 0x05;
425 token->TOK_ID[1] = 0x04;
426 token->Flags = 0;
427 token->Filler = 0xFF;
428
429 if ((ctx->more_flags & LOCAL) == 0)
430 token->Flags |= CFXSentByAcceptor;
431
432 if (ctx->more_flags & ACCEPTOR_SUBKEY)
433 token->Flags |= CFXAcceptorSubkey;
434
435 if (ctx->more_flags & LOCAL)
436 usage = KRB5_KU_USAGE_INITIATOR_SEAL;
437 else
438 usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
439
440 if (conf_req_flag) {
441 /*
442 * In Wrap tokens with confidentiality, the EC field is
443 * used to encode the size (in bytes) of the random filler.
444 */
445 token->Flags |= CFXSealed;
446 token->EC[0] = (ec >> 8) & 0xFF;
447 token->EC[1] = (ec >> 0) & 0xFF;
448
449 } else {
450 /*
451 * In Wrap tokens without confidentiality, the EC field is
452 * used to encode the size (in bytes) of the trailing
453 * checksum.
454 *
455 * This is not used in the checksum calcuation itself,
456 * because the checksum length could potentially vary
457 * depending on the data length.
458 */
459 token->EC[0] = 0;
460 token->EC[1] = 0;
461 }
462
463 /*
464 * In Wrap tokens that provide for confidentiality, the RRC
465 * field in the header contains the hex value 00 00 before
466 * encryption.
467 *
468 * In Wrap tokens that do not provide for confidentiality,
469 * both the EC and RRC fields in the appended checksum
470 * contain the hex value 00 00 for the purpose of calculating
471 * the checksum.
472 */
473 token->RRC[0] = 0;
474 token->RRC[1] = 0;
475
476 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
477 krb5_auth_con_getlocalseqnumber(context,
478 ctx->auth_context,
479 &seq_number);
480 _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
481 _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
482 krb5_auth_con_setlocalseqnumber(context,
483 ctx->auth_context,
484 ++seq_number);
485 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
486
487 data = calloc(iov_count + 3, sizeof(data[0]));
488 if (data == NULL) {
489 *minor_status = ENOMEM;
490 major_status = GSS_S_FAILURE;
491 goto failure;
492 }
493
494 if (conf_req_flag) {
495 /*
496 plain packet:
497
498 {"header" | encrypt(plaintext-data | ec-padding | E"header")}
499
500 Expanded, this is with with RRC = 0:
501
502 {"header" | krb5-header | plaintext-data | ec-padding | E"header" | krb5-trailer }
503
504 In DCE-RPC mode == no trailer: RRC = gss "trailer" == length(ec-padding | E"header" | krb5-trailer)
505
506 {"header" | ec-padding | E"header" | krb5-trailer | krb5-header | plaintext-data }
507 */
508
509 i = 0;
510 data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
511 data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
512 data[i].data.length = k5hsize;
513
514 for (i = 1; i < iov_count + 1; i++) {
515 switch (GSS_IOV_BUFFER_TYPE(iov[i - 1].type)) {
516 case GSS_IOV_BUFFER_TYPE_DATA:
517 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
518 break;
519 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
520 data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
521 break;
522 default:
523 data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
524 break;
525 }
526 data[i].data.length = iov[i - 1].buffer.length;
527 data[i].data.data = iov[i - 1].buffer.value;
528 }
529
530 /*
531 * Any necessary padding is added here to ensure that the
532 * encrypted token header is always at the end of the
533 * ciphertext.
534 */
535
536 /* encrypted CFX header in trailer (or after the header if in
537 DCE mode). Copy in header into E"header"
538 */
539 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
540 if (trailer)
541 data[i].data.data = trailer->buffer.value;
542 else
543 data[i].data.data = ((uint8_t *)header->buffer.value) + sizeof(*token);
544
545 data[i].data.length = ec + sizeof(*token);
546 memset(data[i].data.data, 0xFF, ec);
547 memcpy(((uint8_t *)data[i].data.data) + ec, token, sizeof(*token));
548 i++;
549
550 /* Kerberos trailer comes after the gss trailer */
551 data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
552 data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
553 data[i].data.length = k5tsize;
554 i++;
555
556 ret = krb5_encrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
557 if (ret != 0) {
558 *minor_status = ret;
559 major_status = GSS_S_FAILURE;
560 goto failure;
561 }
562
563 if (rrc) {
564 token->RRC[0] = (rrc >> 8) & 0xFF;
565 token->RRC[1] = (rrc >> 0) & 0xFF;
566 }
567
568 } else {
569 /*
570 plain packet:
571
572 {data | "header" | gss-trailer (krb5 checksum)
573
574 don't do RRC != 0
575
576 */
577
578 for (i = 0; i < iov_count; i++) {
579 switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
580 case GSS_IOV_BUFFER_TYPE_DATA:
581 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
582 break;
583 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
584 data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
585 break;
586 default:
587 data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
588 break;
589 }
590 data[i].data.length = iov[i].buffer.length;
591 data[i].data.data = iov[i].buffer.value;
592 }
593
594 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
595 data[i].data.data = header->buffer.value;
596 data[i].data.length = sizeof(gss_cfx_wrap_token_desc);
597 i++;
598
599 data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
600 if (trailer) {
601 data[i].data.data = trailer->buffer.value;
602 } else {
603 data[i].data.data = (uint8_t *)header->buffer.value +
604 sizeof(gss_cfx_wrap_token_desc);
605 }
606 data[i].data.length = k5tsize;
607 i++;
608
609 ret = krb5_create_checksum_iov(context, ctx->crypto, usage, data, i, NULL);
610 if (ret) {
611 *minor_status = ret;
612 major_status = GSS_S_FAILURE;
613 goto failure;
614 }
615
616 if (rrc) {
617 token->RRC[0] = (rrc >> 8) & 0xFF;
618 token->RRC[1] = (rrc >> 0) & 0xFF;
619 }
620
621 token->EC[0] = (k5tsize >> 8) & 0xFF;
622 token->EC[1] = (k5tsize >> 0) & 0xFF;
623 }
624
625 if (conf_state != NULL)
626 *conf_state = conf_req_flag;
627
628 free(data);
629
630 *minor_status = 0;
631 return GSS_S_COMPLETE;
632
633 failure:
634 if (data)
635 free(data);
636
637 gss_release_iov_buffer(&junk, iov, iov_count);
638
639 return major_status;
640 }
641 #endif
642
643 /* This is slowpath */
644 static OM_uint32
unrotate_iov(OM_uint32 * minor_status,size_t rrc,gss_iov_buffer_desc * iov,int iov_count)645 unrotate_iov(OM_uint32 *minor_status, size_t rrc, gss_iov_buffer_desc *iov, int iov_count)
646 {
647 uint8_t *p, *q;
648 size_t len = 0, skip;
649 int i;
650
651 for (i = 0; i < iov_count; i++)
652 if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
653 GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
654 GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
655 len += iov[i].buffer.length;
656
657 p = malloc(len);
658 if (p == NULL) {
659 *minor_status = ENOMEM;
660 return GSS_S_FAILURE;
661 }
662 q = p;
663
664 /* copy up */
665
666 for (i = 0; i < iov_count; i++) {
667 if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
668 GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
669 GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
670 {
671 memcpy(q, iov[i].buffer.value, iov[i].buffer.length);
672 q += iov[i].buffer.length;
673 }
674 }
675 assert((size_t)(q - p) == len);
676
677 /* unrotate first part */
678 q = p + rrc;
679 skip = rrc;
680 for (i = 0; i < iov_count; i++) {
681 if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
682 GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
683 GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
684 {
685 if (iov[i].buffer.length <= skip) {
686 skip -= iov[i].buffer.length;
687 } else {
688 memcpy(((uint8_t *)iov[i].buffer.value) + skip, q, iov[i].buffer.length - skip);
689 q += iov[i].buffer.length - skip;
690 skip = 0;
691 }
692 }
693 }
694 /* copy trailer */
695 q = p;
696 skip = rrc;
697 for (i = 0; i < iov_count; i++) {
698 if (GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_DATA ||
699 GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_PADDING ||
700 GSS_IOV_BUFFER_TYPE(iov[i].type) == GSS_IOV_BUFFER_TYPE_TRAILER)
701 {
702 memcpy(q, iov[i].buffer.value, min(iov[i].buffer.length, skip));
703 if (iov[i].buffer.length > skip)
704 break;
705 skip -= iov[i].buffer.length;
706 q += iov[i].buffer.length;
707 }
708 }
709 return GSS_S_COMPLETE;
710 }
711
712 #if 0
713
714 OM_uint32
715 _gssapi_unwrap_cfx_iov(OM_uint32 *minor_status,
716 gsskrb5_ctx ctx,
717 krb5_context context,
718 int *conf_state,
719 gss_qop_t *qop_state,
720 gss_iov_buffer_desc *iov,
721 int iov_count)
722 {
723 OM_uint32 seq_number_lo, seq_number_hi, major_status, junk;
724 gss_iov_buffer_desc *header, *trailer, *padding;
725 gss_cfx_wrap_token token, ttoken;
726 u_char token_flags;
727 krb5_error_code ret;
728 unsigned usage;
729 uint16_t ec, rrc;
730 krb5_crypto_iov *data = NULL;
731 int i, j;
732
733 *minor_status = 0;
734
735 header = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_HEADER);
736 if (header == NULL) {
737 *minor_status = EINVAL;
738 return GSS_S_FAILURE;
739 }
740
741 if (header->buffer.length < sizeof(*token)) /* we check exact below */
742 return GSS_S_DEFECTIVE_TOKEN;
743
744 padding = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_PADDING);
745 if (padding != NULL && padding->buffer.length != 0) {
746 *minor_status = EINVAL;
747 return GSS_S_FAILURE;
748 }
749
750 trailer = _gk_find_buffer(iov, iov_count, GSS_IOV_BUFFER_TYPE_TRAILER);
751
752 major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
753 if (major_status != GSS_S_COMPLETE) {
754 return major_status;
755 }
756
757 token = (gss_cfx_wrap_token)header->buffer.value;
758
759 if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04)
760 return GSS_S_DEFECTIVE_TOKEN;
761
762 /* Ignore unknown flags */
763 token_flags = token->Flags &
764 (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
765
766 if (token_flags & CFXSentByAcceptor) {
767 if ((ctx->more_flags & LOCAL) == 0)
768 return GSS_S_DEFECTIVE_TOKEN;
769 }
770
771 if (ctx->more_flags & ACCEPTOR_SUBKEY) {
772 if ((token_flags & CFXAcceptorSubkey) == 0)
773 return GSS_S_DEFECTIVE_TOKEN;
774 } else {
775 if (token_flags & CFXAcceptorSubkey)
776 return GSS_S_DEFECTIVE_TOKEN;
777 }
778
779 if (token->Filler != 0xFF)
780 return GSS_S_DEFECTIVE_TOKEN;
781
782 if (conf_state != NULL)
783 *conf_state = (token_flags & CFXSealed) ? 1 : 0;
784
785 ec = (token->EC[0] << 8) | token->EC[1];
786 rrc = (token->RRC[0] << 8) | token->RRC[1];
787
788 /*
789 * Check sequence number
790 */
791 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
792 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
793 if (seq_number_hi) {
794 /* no support for 64-bit sequence numbers */
795 *minor_status = ERANGE;
796 return GSS_S_UNSEQ_TOKEN;
797 }
798
799 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
800 ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
801 if (ret != 0) {
802 *minor_status = 0;
803 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
804 return ret;
805 }
806 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
807
808 /*
809 * Decrypt and/or verify checksum
810 */
811
812 if (ctx->more_flags & LOCAL) {
813 usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
814 } else {
815 usage = KRB5_KU_USAGE_INITIATOR_SEAL;
816 }
817
818 data = calloc(iov_count + 3, sizeof(data[0]));
819 if (data == NULL) {
820 *minor_status = ENOMEM;
821 major_status = GSS_S_FAILURE;
822 goto failure;
823 }
824
825 if (token_flags & CFXSealed) {
826 size_t k5tsize, k5hsize;
827
828 krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_HEADER, &k5hsize);
829 krb5_crypto_length(context, ctx->crypto, KRB5_CRYPTO_TYPE_TRAILER, &k5tsize);
830
831 /* Rotate by RRC; bogus to do this in-place XXX */
832 /* Check RRC */
833
834 if (trailer == NULL) {
835 size_t gsstsize = k5tsize + sizeof(*token);
836 size_t gsshsize = k5hsize + sizeof(*token);
837
838 if (rrc != gsstsize) {
839 major_status = GSS_S_DEFECTIVE_TOKEN;
840 goto failure;
841 }
842
843 if (IS_DCE_STYLE(ctx))
844 gsstsize += ec;
845
846 gsshsize += gsstsize;
847
848 if (header->buffer.length != gsshsize) {
849 major_status = GSS_S_DEFECTIVE_TOKEN;
850 goto failure;
851 }
852 } else if (trailer->buffer.length != sizeof(*token) + k5tsize) {
853 major_status = GSS_S_DEFECTIVE_TOKEN;
854 goto failure;
855 } else if (header->buffer.length != sizeof(*token) + k5hsize) {
856 major_status = GSS_S_DEFECTIVE_TOKEN;
857 goto failure;
858 } else if (rrc != 0) {
859 /* go though slowpath */
860 major_status = unrotate_iov(minor_status, rrc, iov, iov_count);
861 if (major_status)
862 goto failure;
863 }
864
865 i = 0;
866 data[i].flags = KRB5_CRYPTO_TYPE_HEADER;
867 data[i].data.data = ((uint8_t *)header->buffer.value) + header->buffer.length - k5hsize;
868 data[i].data.length = k5hsize;
869 i++;
870
871 for (j = 0; j < iov_count; i++, j++) {
872 switch (GSS_IOV_BUFFER_TYPE(iov[j].type)) {
873 case GSS_IOV_BUFFER_TYPE_DATA:
874 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
875 break;
876 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
877 data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
878 break;
879 default:
880 data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
881 break;
882 }
883 data[i].data.length = iov[j].buffer.length;
884 data[i].data.data = iov[j].buffer.value;
885 }
886
887 /* encrypted CFX header in trailer (or after the header if in
888 DCE mode). Copy in header into E"header"
889 */
890 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
891 if (trailer) {
892 data[i].data.data = trailer->buffer.value;
893 } else {
894 data[i].data.data = ((uint8_t *)header->buffer.value) +
895 header->buffer.length - k5hsize - k5tsize - ec- sizeof(*token);
896 }
897
898 data[i].data.length = ec + sizeof(*token);
899 ttoken = (gss_cfx_wrap_token)(((uint8_t *)data[i].data.data) + ec);
900 i++;
901
902 /* Kerberos trailer comes after the gss trailer */
903 data[i].flags = KRB5_CRYPTO_TYPE_TRAILER;
904 data[i].data.data = ((uint8_t *)data[i-1].data.data) + ec + sizeof(*token);
905 data[i].data.length = k5tsize;
906 i++;
907
908 ret = krb5_decrypt_iov_ivec(context, ctx->crypto, usage, data, i, NULL);
909 if (ret != 0) {
910 *minor_status = ret;
911 major_status = GSS_S_FAILURE;
912 goto failure;
913 }
914
915 ttoken->RRC[0] = token->RRC[0];
916 ttoken->RRC[1] = token->RRC[1];
917
918 /* Check the integrity of the header */
919 if (ct_memcmp(ttoken, token, sizeof(*token)) != 0) {
920 major_status = GSS_S_BAD_MIC;
921 goto failure;
922 }
923 } else {
924 size_t gsstsize = ec;
925 size_t gsshsize = sizeof(*token);
926
927 if (trailer == NULL) {
928 /* Check RRC */
929 if (rrc != gsstsize) {
930 *minor_status = EINVAL;
931 major_status = GSS_S_FAILURE;
932 goto failure;
933 }
934
935 gsshsize += gsstsize;
936 gsstsize = 0;
937 } else if (trailer->buffer.length != gsstsize) {
938 major_status = GSS_S_DEFECTIVE_TOKEN;
939 goto failure;
940 } else if (rrc != 0) {
941 /* Check RRC */
942 *minor_status = EINVAL;
943 major_status = GSS_S_FAILURE;
944 goto failure;
945 }
946
947 if (header->buffer.length != gsshsize) {
948 major_status = GSS_S_DEFECTIVE_TOKEN;
949 goto failure;
950 }
951
952 for (i = 0; i < iov_count; i++) {
953 switch (GSS_IOV_BUFFER_TYPE(iov[i].type)) {
954 case GSS_IOV_BUFFER_TYPE_DATA:
955 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
956 break;
957 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
958 data[i].flags = KRB5_CRYPTO_TYPE_SIGN_ONLY;
959 break;
960 default:
961 data[i].flags = KRB5_CRYPTO_TYPE_EMPTY;
962 break;
963 }
964 data[i].data.length = iov[i].buffer.length;
965 data[i].data.data = iov[i].buffer.value;
966 }
967
968 data[i].flags = KRB5_CRYPTO_TYPE_DATA;
969 data[i].data.data = header->buffer.value;
970 data[i].data.length = sizeof(*token);
971 i++;
972
973 data[i].flags = KRB5_CRYPTO_TYPE_CHECKSUM;
974 if (trailer) {
975 data[i].data.data = trailer->buffer.value;
976 } else {
977 data[i].data.data = (uint8_t *)header->buffer.value +
978 sizeof(*token);
979 }
980 data[i].data.length = ec;
981 i++;
982
983 token = (gss_cfx_wrap_token)header->buffer.value;
984 token->EC[0] = 0;
985 token->EC[1] = 0;
986 token->RRC[0] = 0;
987 token->RRC[1] = 0;
988
989 ret = krb5_verify_checksum_iov(context, ctx->crypto, usage, data, i, NULL);
990 if (ret) {
991 *minor_status = ret;
992 major_status = GSS_S_FAILURE;
993 goto failure;
994 }
995 }
996
997 if (qop_state != NULL) {
998 *qop_state = GSS_C_QOP_DEFAULT;
999 }
1000
1001 free(data);
1002
1003 *minor_status = 0;
1004 return GSS_S_COMPLETE;
1005
1006 failure:
1007 if (data)
1008 free(data);
1009
1010 gss_release_iov_buffer(&junk, iov, iov_count);
1011
1012 return major_status;
1013 }
1014 #endif
1015
1016 OM_uint32
_gssapi_wrap_iov_length_cfx(OM_uint32 * minor_status,gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,gss_qop_t qop_req,int * conf_state,gss_iov_buffer_desc * iov,int iov_count)1017 _gssapi_wrap_iov_length_cfx(OM_uint32 *minor_status,
1018 gsskrb5_ctx ctx,
1019 krb5_context context,
1020 int conf_req_flag,
1021 gss_qop_t qop_req,
1022 int *conf_state,
1023 gss_iov_buffer_desc *iov,
1024 int iov_count)
1025 {
1026 OM_uint32 major_status;
1027 size_t size;
1028 int i;
1029 gss_iov_buffer_desc *header = NULL;
1030 gss_iov_buffer_desc *padding = NULL;
1031 gss_iov_buffer_desc *trailer = NULL;
1032 size_t gsshsize = 0;
1033 size_t gsstsize = 0;
1034 size_t k5hsize = 0;
1035 size_t k5tsize = 0;
1036
1037 GSSAPI_KRB5_INIT (&context);
1038 *minor_status = 0;
1039
1040 for (size = 0, i = 0; i < iov_count; i++) {
1041 switch(GSS_IOV_BUFFER_TYPE(iov[i].type)) {
1042 case GSS_IOV_BUFFER_TYPE_EMPTY:
1043 break;
1044 case GSS_IOV_BUFFER_TYPE_DATA:
1045 size += iov[i].buffer.length;
1046 break;
1047 case GSS_IOV_BUFFER_TYPE_HEADER:
1048 if (header != NULL) {
1049 *minor_status = 0;
1050 return GSS_S_FAILURE;
1051 }
1052 header = &iov[i];
1053 break;
1054 case GSS_IOV_BUFFER_TYPE_TRAILER:
1055 if (trailer != NULL) {
1056 *minor_status = 0;
1057 return GSS_S_FAILURE;
1058 }
1059 trailer = &iov[i];
1060 break;
1061 case GSS_IOV_BUFFER_TYPE_PADDING:
1062 if (padding != NULL) {
1063 *minor_status = 0;
1064 return GSS_S_FAILURE;
1065 }
1066 padding = &iov[i];
1067 break;
1068 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY:
1069 break;
1070 default:
1071 *minor_status = EINVAL;
1072 return GSS_S_FAILURE;
1073 }
1074 }
1075
1076 major_status = _gk_verify_buffers(minor_status, ctx, header, padding, trailer);
1077 if (major_status != GSS_S_COMPLETE) {
1078 return major_status;
1079 }
1080
1081 if (conf_req_flag) {
1082 size_t k5psize = 0;
1083 size_t k5pbase = 0;
1084 size_t k5bsize = 0;
1085 size_t ec = 0;
1086
1087 size += sizeof(gss_cfx_wrap_token_desc);
1088
1089 *minor_status = krb5_crypto_length(context, ctx->crypto,
1090 KRB5_CRYPTO_TYPE_HEADER,
1091 &k5hsize);
1092 if (*minor_status)
1093 return GSS_S_FAILURE;
1094
1095 *minor_status = krb5_crypto_length(context, ctx->crypto,
1096 KRB5_CRYPTO_TYPE_TRAILER,
1097 &k5tsize);
1098 if (*minor_status)
1099 return GSS_S_FAILURE;
1100
1101 *minor_status = krb5_crypto_length(context, ctx->crypto,
1102 KRB5_CRYPTO_TYPE_PADDING,
1103 &k5pbase);
1104 if (*minor_status)
1105 return GSS_S_FAILURE;
1106
1107 if (k5pbase > 1) {
1108 k5psize = k5pbase - (size % k5pbase);
1109 } else {
1110 k5psize = 0;
1111 }
1112
1113 if (k5psize == 0 && IS_DCE_STYLE(ctx)) {
1114 *minor_status = krb5_crypto_getblocksize(context, ctx->crypto,
1115 &k5bsize);
1116 if (*minor_status)
1117 return GSS_S_FAILURE;
1118
1119 ec = k5bsize;
1120 } else {
1121 ec = k5psize;
1122 }
1123
1124 gsshsize = sizeof(gss_cfx_wrap_token_desc) + k5hsize;
1125 gsstsize = sizeof(gss_cfx_wrap_token_desc) + ec + k5tsize;
1126 } else {
1127 *minor_status = krb5_crypto_length(context, ctx->crypto,
1128 KRB5_CRYPTO_TYPE_CHECKSUM,
1129 &k5tsize);
1130 if (*minor_status)
1131 return GSS_S_FAILURE;
1132
1133 gsshsize = sizeof(gss_cfx_wrap_token_desc);
1134 gsstsize = k5tsize;
1135 }
1136
1137 if (trailer != NULL) {
1138 trailer->buffer.length = gsstsize;
1139 } else {
1140 gsshsize += gsstsize;
1141 }
1142
1143 header->buffer.length = gsshsize;
1144
1145 if (padding) {
1146 /* padding is done via EC and is contained in the header or trailer */
1147 padding->buffer.length = 0;
1148 }
1149
1150 if (conf_state) {
1151 *conf_state = conf_req_flag;
1152 }
1153
1154 return GSS_S_COMPLETE;
1155 }
1156
1157
1158
1159
_gssapi_wrap_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,int conf_req_flag,const gss_buffer_t input_message_buffer,int * conf_state,gss_buffer_t output_message_buffer)1160 OM_uint32 _gssapi_wrap_cfx(OM_uint32 *minor_status,
1161 const gsskrb5_ctx ctx,
1162 krb5_context context,
1163 int conf_req_flag,
1164 const gss_buffer_t input_message_buffer,
1165 int *conf_state,
1166 gss_buffer_t output_message_buffer)
1167 {
1168 gss_cfx_wrap_token token;
1169 krb5_error_code ret;
1170 unsigned usage;
1171 krb5_data cipher;
1172 size_t wrapped_len, cksumsize;
1173 uint16_t padlength, rrc = 0;
1174 int32_t seq_number;
1175 u_char *p;
1176
1177 ret = _gsskrb5cfx_wrap_length_cfx(context,
1178 ctx->crypto, conf_req_flag,
1179 IS_DCE_STYLE(ctx),
1180 input_message_buffer->length,
1181 &wrapped_len, &cksumsize, &padlength);
1182 if (ret != 0) {
1183 *minor_status = ret;
1184 return GSS_S_FAILURE;
1185 }
1186
1187 /* Always rotate encrypted token (if any) and checksum to header */
1188 rrc = (conf_req_flag ? sizeof(*token) : 0) + (uint16_t)cksumsize;
1189
1190 output_message_buffer->length = wrapped_len;
1191 output_message_buffer->value = malloc(output_message_buffer->length);
1192 if (output_message_buffer->value == NULL) {
1193 *minor_status = ENOMEM;
1194 return GSS_S_FAILURE;
1195 }
1196
1197 p = output_message_buffer->value;
1198 token = (gss_cfx_wrap_token)p;
1199 token->TOK_ID[0] = 0x05;
1200 token->TOK_ID[1] = 0x04;
1201 token->Flags = 0;
1202 token->Filler = 0xFF;
1203 if ((ctx->more_flags & LOCAL) == 0)
1204 token->Flags |= CFXSentByAcceptor;
1205 if (ctx->more_flags & ACCEPTOR_SUBKEY)
1206 token->Flags |= CFXAcceptorSubkey;
1207 if (conf_req_flag) {
1208 /*
1209 * In Wrap tokens with confidentiality, the EC field is
1210 * used to encode the size (in bytes) of the random filler.
1211 */
1212 token->Flags |= CFXSealed;
1213 token->EC[0] = (padlength >> 8) & 0xFF;
1214 token->EC[1] = (padlength >> 0) & 0xFF;
1215 } else {
1216 /*
1217 * In Wrap tokens without confidentiality, the EC field is
1218 * used to encode the size (in bytes) of the trailing
1219 * checksum.
1220 *
1221 * This is not used in the checksum calcuation itself,
1222 * because the checksum length could potentially vary
1223 * depending on the data length.
1224 */
1225 token->EC[0] = 0;
1226 token->EC[1] = 0;
1227 }
1228
1229 /*
1230 * In Wrap tokens that provide for confidentiality, the RRC
1231 * field in the header contains the hex value 00 00 before
1232 * encryption.
1233 *
1234 * In Wrap tokens that do not provide for confidentiality,
1235 * both the EC and RRC fields in the appended checksum
1236 * contain the hex value 00 00 for the purpose of calculating
1237 * the checksum.
1238 */
1239 token->RRC[0] = 0;
1240 token->RRC[1] = 0;
1241
1242 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1243 krb5_auth_con_getlocalseqnumber(context,
1244 ctx->auth_context,
1245 &seq_number);
1246 _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
1247 _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
1248 krb5_auth_con_setlocalseqnumber(context,
1249 ctx->auth_context,
1250 ++seq_number);
1251 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1252
1253 /*
1254 * If confidentiality is requested, the token header is
1255 * appended to the plaintext before encryption; the resulting
1256 * token is {"header" | encrypt(plaintext | pad | "header")}.
1257 *
1258 * If no confidentiality is requested, the checksum is
1259 * calculated over the plaintext concatenated with the
1260 * token header.
1261 */
1262 if (ctx->more_flags & LOCAL) {
1263 usage = KRB5_KU_USAGE_INITIATOR_SEAL;
1264 } else {
1265 usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
1266 }
1267
1268 if (conf_req_flag) {
1269 /*
1270 * Any necessary padding is added here to ensure that the
1271 * encrypted token header is always at the end of the
1272 * ciphertext.
1273 *
1274 * The specification does not require that the padding
1275 * bytes are initialized.
1276 */
1277 p += sizeof(*token);
1278 memcpy(p, input_message_buffer->value, input_message_buffer->length);
1279 memset(p + input_message_buffer->length, 0xFF, padlength);
1280 memcpy(p + input_message_buffer->length + padlength,
1281 token, sizeof(*token));
1282
1283 ret = krb5_encrypt(context, ctx->crypto,
1284 usage, p,
1285 input_message_buffer->length + padlength +
1286 sizeof(*token),
1287 &cipher);
1288 if (ret != 0) {
1289 *minor_status = ret;
1290 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1291 return GSS_S_FAILURE;
1292 }
1293 assert(sizeof(*token) + cipher.length == wrapped_len);
1294 token->RRC[0] = (rrc >> 8) & 0xFF;
1295 token->RRC[1] = (rrc >> 0) & 0xFF;
1296
1297 /*
1298 * this is really ugly, but needed against windows
1299 * for DCERPC, as windows rotates by EC+RRC.
1300 */
1301 if (IS_DCE_STYLE(ctx)) {
1302 ret = rrc_rotate(cipher.data, cipher.length, rrc+padlength, FALSE);
1303 } else {
1304 ret = rrc_rotate(cipher.data, cipher.length, rrc, FALSE);
1305 }
1306 if (ret != 0) {
1307 *minor_status = ret;
1308 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1309 return GSS_S_FAILURE;
1310 }
1311 memcpy(p, cipher.data, cipher.length);
1312 krb5_data_free(&cipher);
1313 } else {
1314 char *buf;
1315 Checksum cksum;
1316
1317 buf = malloc(input_message_buffer->length + sizeof(*token));
1318 if (buf == NULL) {
1319 *minor_status = ENOMEM;
1320 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1321 return GSS_S_FAILURE;
1322 }
1323 memcpy(buf, input_message_buffer->value, input_message_buffer->length);
1324 memcpy(buf + input_message_buffer->length, token, sizeof(*token));
1325
1326 ret = krb5_create_checksum(context, ctx->crypto,
1327 usage, 0, buf,
1328 input_message_buffer->length +
1329 sizeof(*token),
1330 &cksum);
1331 if (ret != 0) {
1332 *minor_status = ret;
1333 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1334 free(buf);
1335 return GSS_S_FAILURE;
1336 }
1337
1338 free(buf);
1339
1340 assert(cksum.checksum.length == cksumsize);
1341 token->EC[0] = (cksum.checksum.length >> 8) & 0xFF;
1342 token->EC[1] = (cksum.checksum.length >> 0) & 0xFF;
1343 token->RRC[0] = (rrc >> 8) & 0xFF;
1344 token->RRC[1] = (rrc >> 0) & 0xFF;
1345
1346 p += sizeof(*token);
1347 memcpy(p, input_message_buffer->value, input_message_buffer->length);
1348 memcpy(p + input_message_buffer->length,
1349 cksum.checksum.data, cksum.checksum.length);
1350
1351 ret = rrc_rotate(p,
1352 input_message_buffer->length + cksum.checksum.length, rrc, FALSE);
1353 if (ret != 0) {
1354 *minor_status = ret;
1355 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1356 free_Checksum(&cksum);
1357 return GSS_S_FAILURE;
1358 }
1359 free_Checksum(&cksum);
1360 }
1361
1362 if (conf_state != NULL) {
1363 *conf_state = conf_req_flag;
1364 }
1365
1366 *minor_status = 0;
1367 return GSS_S_COMPLETE;
1368 }
1369
_gssapi_unwrap_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,const gss_buffer_t input_message_buffer,gss_buffer_t output_message_buffer,int * conf_state,gss_qop_t * qop_state)1370 OM_uint32 _gssapi_unwrap_cfx(OM_uint32 *minor_status,
1371 const gsskrb5_ctx ctx,
1372 krb5_context context,
1373 const gss_buffer_t input_message_buffer,
1374 gss_buffer_t output_message_buffer,
1375 int *conf_state,
1376 gss_qop_t *qop_state)
1377 {
1378 gss_cfx_wrap_token token;
1379 u_char token_flags;
1380 krb5_error_code ret;
1381 unsigned usage;
1382 krb5_data data;
1383 uint16_t ec, rrc;
1384 OM_uint32 seq_number_lo, seq_number_hi;
1385 size_t len;
1386 u_char *p;
1387
1388 *minor_status = 0;
1389
1390 if (input_message_buffer->length < sizeof(*token)) {
1391 return GSS_S_DEFECTIVE_TOKEN;
1392 }
1393
1394 p = input_message_buffer->value;
1395
1396 token = (gss_cfx_wrap_token)p;
1397
1398 if (token->TOK_ID[0] != 0x05 || token->TOK_ID[1] != 0x04) {
1399 return GSS_S_DEFECTIVE_TOKEN;
1400 }
1401
1402 /* Ignore unknown flags */
1403 token_flags = token->Flags &
1404 (CFXSentByAcceptor | CFXSealed | CFXAcceptorSubkey);
1405
1406 if (token_flags & CFXSentByAcceptor) {
1407 if ((ctx->more_flags & LOCAL) == 0)
1408 return GSS_S_DEFECTIVE_TOKEN;
1409 }
1410
1411 if (ctx->more_flags & ACCEPTOR_SUBKEY) {
1412 if ((token_flags & CFXAcceptorSubkey) == 0)
1413 return GSS_S_DEFECTIVE_TOKEN;
1414 } else {
1415 if (token_flags & CFXAcceptorSubkey)
1416 return GSS_S_DEFECTIVE_TOKEN;
1417 }
1418
1419 if (token->Filler != 0xFF) {
1420 return GSS_S_DEFECTIVE_TOKEN;
1421 }
1422
1423 if (conf_state != NULL) {
1424 *conf_state = (token_flags & CFXSealed) ? 1 : 0;
1425 }
1426
1427 ec = (token->EC[0] << 8) | token->EC[1];
1428 rrc = (token->RRC[0] << 8) | token->RRC[1];
1429
1430 /*
1431 * Check sequence number
1432 */
1433 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
1434 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
1435 if (seq_number_hi) {
1436 /* no support for 64-bit sequence numbers */
1437 *minor_status = ERANGE;
1438 return GSS_S_UNSEQ_TOKEN;
1439 }
1440
1441 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1442 ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
1443 if (ret != 0) {
1444 *minor_status = 0;
1445 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1446 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1447 return ret;
1448 }
1449 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1450
1451 /*
1452 * Decrypt and/or verify checksum
1453 */
1454
1455 if (ctx->more_flags & LOCAL) {
1456 usage = KRB5_KU_USAGE_ACCEPTOR_SEAL;
1457 } else {
1458 usage = KRB5_KU_USAGE_INITIATOR_SEAL;
1459 }
1460
1461 p += sizeof(*token);
1462 len = input_message_buffer->length;
1463 len -= (p - (u_char *)input_message_buffer->value);
1464
1465 if (token_flags & CFXSealed) {
1466 /*
1467 * this is really ugly, but needed against windows
1468 * for DCERPC, as windows rotates by EC+RRC.
1469 */
1470 if (IS_DCE_STYLE(ctx)) {
1471 *minor_status = rrc_rotate(p, len, rrc+ec, TRUE);
1472 } else {
1473 *minor_status = rrc_rotate(p, len, rrc, TRUE);
1474 }
1475 if (*minor_status != 0) {
1476 return GSS_S_FAILURE;
1477 }
1478
1479 ret = krb5_decrypt(context, ctx->crypto, usage,
1480 p, len, &data);
1481 if (ret != 0) {
1482 *minor_status = ret;
1483 return GSS_S_BAD_MIC;
1484 }
1485
1486 /* Check that there is room for the pad and token header */
1487 if (data.length < ec + sizeof(*token)) {
1488 krb5_data_free(&data);
1489 return GSS_S_DEFECTIVE_TOKEN;
1490 }
1491 p = data.data;
1492 p += data.length - sizeof(*token);
1493
1494 /* RRC is unprotected; don't modify input buffer */
1495 ((gss_cfx_wrap_token)p)->RRC[0] = token->RRC[0];
1496 ((gss_cfx_wrap_token)p)->RRC[1] = token->RRC[1];
1497
1498 /* Check the integrity of the header */
1499 if (ct_memcmp(p, token, sizeof(*token)) != 0) {
1500 krb5_data_free(&data);
1501 return GSS_S_BAD_MIC;
1502 }
1503
1504 output_message_buffer->value = data.data;
1505 output_message_buffer->length = data.length - ec - sizeof(*token);
1506 } else {
1507 Checksum cksum;
1508
1509 /* Rotate by RRC; bogus to do this in-place XXX */
1510 *minor_status = rrc_rotate(p, len, rrc, TRUE);
1511 if (*minor_status != 0) {
1512 return GSS_S_FAILURE;
1513 }
1514
1515 /* Determine checksum type */
1516 ret = krb5_crypto_get_checksum_type(context,
1517 ctx->crypto,
1518 &cksum.cksumtype);
1519 if (ret != 0) {
1520 *minor_status = ret;
1521 return GSS_S_FAILURE;
1522 }
1523
1524 cksum.checksum.length = ec;
1525
1526 /* Check we have at least as much data as the checksum */
1527 if (len < cksum.checksum.length) {
1528 *minor_status = ERANGE;
1529 return GSS_S_BAD_MIC;
1530 }
1531
1532 /* Length now is of the plaintext only, no checksum */
1533 len -= cksum.checksum.length;
1534 cksum.checksum.data = p + len;
1535
1536 output_message_buffer->length = len; /* for later */
1537 output_message_buffer->value = malloc(len + sizeof(*token));
1538 if (output_message_buffer->value == NULL) {
1539 *minor_status = ENOMEM;
1540 return GSS_S_FAILURE;
1541 }
1542
1543 /* Checksum is over (plaintext-data | "header") */
1544 memcpy(output_message_buffer->value, p, len);
1545 memcpy((u_char *)output_message_buffer->value + len,
1546 token, sizeof(*token));
1547
1548 /* EC is not included in checksum calculation */
1549 token = (gss_cfx_wrap_token)((u_char *)output_message_buffer->value +
1550 len);
1551 token->EC[0] = 0;
1552 token->EC[1] = 0;
1553 token->RRC[0] = 0;
1554 token->RRC[1] = 0;
1555
1556 ret = krb5_verify_checksum(context, ctx->crypto,
1557 usage,
1558 output_message_buffer->value,
1559 len + sizeof(*token),
1560 &cksum);
1561 if (ret != 0) {
1562 *minor_status = ret;
1563 _gsskrb5_release_buffer(minor_status, output_message_buffer);
1564 return GSS_S_BAD_MIC;
1565 }
1566 }
1567
1568 if (qop_state != NULL) {
1569 *qop_state = GSS_C_QOP_DEFAULT;
1570 }
1571
1572 *minor_status = 0;
1573 return GSS_S_COMPLETE;
1574 }
1575
_gssapi_mic_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,gss_qop_t qop_req,const gss_buffer_t message_buffer,gss_buffer_t message_token)1576 OM_uint32 _gssapi_mic_cfx(OM_uint32 *minor_status,
1577 const gsskrb5_ctx ctx,
1578 krb5_context context,
1579 gss_qop_t qop_req,
1580 const gss_buffer_t message_buffer,
1581 gss_buffer_t message_token)
1582 {
1583 gss_cfx_mic_token token;
1584 krb5_error_code ret;
1585 unsigned usage;
1586 Checksum cksum;
1587 u_char *buf;
1588 size_t len;
1589 int32_t seq_number;
1590
1591 len = message_buffer->length + sizeof(*token);
1592 buf = malloc(len);
1593 if (buf == NULL) {
1594 *minor_status = ENOMEM;
1595 return GSS_S_FAILURE;
1596 }
1597
1598 memcpy(buf, message_buffer->value, message_buffer->length);
1599
1600 token = (gss_cfx_mic_token)(buf + message_buffer->length);
1601 token->TOK_ID[0] = 0x04;
1602 token->TOK_ID[1] = 0x04;
1603 token->Flags = 0;
1604 if ((ctx->more_flags & LOCAL) == 0)
1605 token->Flags |= CFXSentByAcceptor;
1606 if (ctx->more_flags & ACCEPTOR_SUBKEY)
1607 token->Flags |= CFXAcceptorSubkey;
1608 memset(token->Filler, 0xFF, 5);
1609
1610 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1611 krb5_auth_con_getlocalseqnumber(context,
1612 ctx->auth_context,
1613 &seq_number);
1614 _gsskrb5_encode_be_om_uint32(0, &token->SND_SEQ[0]);
1615 _gsskrb5_encode_be_om_uint32(seq_number, &token->SND_SEQ[4]);
1616 krb5_auth_con_setlocalseqnumber(context,
1617 ctx->auth_context,
1618 ++seq_number);
1619 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1620
1621 if (ctx->more_flags & LOCAL) {
1622 usage = KRB5_KU_USAGE_INITIATOR_SIGN;
1623 } else {
1624 usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
1625 }
1626
1627 ret = krb5_create_checksum(context, ctx->crypto,
1628 usage, 0, buf, len, &cksum);
1629 if (ret != 0) {
1630 *minor_status = ret;
1631 free(buf);
1632 return GSS_S_FAILURE;
1633 }
1634
1635 /* Determine MIC length */
1636 message_token->length = sizeof(*token) + cksum.checksum.length;
1637 message_token->value = malloc(message_token->length);
1638 if (message_token->value == NULL) {
1639 *minor_status = ENOMEM;
1640 free_Checksum(&cksum);
1641 free(buf);
1642 return GSS_S_FAILURE;
1643 }
1644
1645 /* Token is { "header" | get_mic("header" | plaintext-data) } */
1646 memcpy(message_token->value, token, sizeof(*token));
1647 memcpy((u_char *)message_token->value + sizeof(*token),
1648 cksum.checksum.data, cksum.checksum.length);
1649
1650 free_Checksum(&cksum);
1651 free(buf);
1652
1653 *minor_status = 0;
1654 return GSS_S_COMPLETE;
1655 }
1656
_gssapi_verify_mic_cfx(OM_uint32 * minor_status,const gsskrb5_ctx ctx,krb5_context context,const gss_buffer_t message_buffer,const gss_buffer_t token_buffer,gss_qop_t * qop_state)1657 OM_uint32 _gssapi_verify_mic_cfx(OM_uint32 *minor_status,
1658 const gsskrb5_ctx ctx,
1659 krb5_context context,
1660 const gss_buffer_t message_buffer,
1661 const gss_buffer_t token_buffer,
1662 gss_qop_t *qop_state)
1663 {
1664 gss_cfx_mic_token token;
1665 u_char token_flags;
1666 krb5_error_code ret;
1667 unsigned usage;
1668 OM_uint32 seq_number_lo, seq_number_hi;
1669 u_char *buf, *p;
1670 Checksum cksum;
1671
1672 *minor_status = 0;
1673
1674 if (token_buffer->length < sizeof(*token)) {
1675 return GSS_S_DEFECTIVE_TOKEN;
1676 }
1677
1678 p = token_buffer->value;
1679
1680 token = (gss_cfx_mic_token)p;
1681
1682 if (token->TOK_ID[0] != 0x04 || token->TOK_ID[1] != 0x04) {
1683 return GSS_S_DEFECTIVE_TOKEN;
1684 }
1685
1686 /* Ignore unknown flags */
1687 token_flags = token->Flags & (CFXSentByAcceptor | CFXAcceptorSubkey);
1688
1689 if (token_flags & CFXSentByAcceptor) {
1690 if ((ctx->more_flags & LOCAL) == 0)
1691 return GSS_S_DEFECTIVE_TOKEN;
1692 }
1693 if (ctx->more_flags & ACCEPTOR_SUBKEY) {
1694 if ((token_flags & CFXAcceptorSubkey) == 0)
1695 return GSS_S_DEFECTIVE_TOKEN;
1696 } else {
1697 if (token_flags & CFXAcceptorSubkey)
1698 return GSS_S_DEFECTIVE_TOKEN;
1699 }
1700
1701 if (ct_memcmp(token->Filler, "\xff\xff\xff\xff\xff", 5) != 0) {
1702 return GSS_S_DEFECTIVE_TOKEN;
1703 }
1704
1705 /*
1706 * Check sequence number
1707 */
1708 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[0], &seq_number_hi);
1709 _gsskrb5_decode_be_om_uint32(&token->SND_SEQ[4], &seq_number_lo);
1710 if (seq_number_hi) {
1711 *minor_status = ERANGE;
1712 return GSS_S_UNSEQ_TOKEN;
1713 }
1714
1715 HEIMDAL_MUTEX_lock(&ctx->ctx_id_mutex);
1716 ret = _gssapi_msg_order_check(ctx->order, seq_number_lo);
1717 if (ret != 0) {
1718 *minor_status = 0;
1719 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1720 return ret;
1721 }
1722 HEIMDAL_MUTEX_unlock(&ctx->ctx_id_mutex);
1723
1724 /*
1725 * Verify checksum
1726 */
1727 ret = krb5_crypto_get_checksum_type(context, ctx->crypto,
1728 &cksum.cksumtype);
1729 if (ret != 0) {
1730 *minor_status = ret;
1731 return GSS_S_FAILURE;
1732 }
1733
1734 cksum.checksum.data = p + sizeof(*token);
1735 cksum.checksum.length = token_buffer->length - sizeof(*token);
1736
1737 if (ctx->more_flags & LOCAL) {
1738 usage = KRB5_KU_USAGE_ACCEPTOR_SIGN;
1739 } else {
1740 usage = KRB5_KU_USAGE_INITIATOR_SIGN;
1741 }
1742
1743 buf = malloc(message_buffer->length + sizeof(*token));
1744 if (buf == NULL) {
1745 *minor_status = ENOMEM;
1746 return GSS_S_FAILURE;
1747 }
1748 memcpy(buf, message_buffer->value, message_buffer->length);
1749 memcpy(buf + message_buffer->length, token, sizeof(*token));
1750
1751 ret = krb5_verify_checksum(context, ctx->crypto,
1752 usage,
1753 buf,
1754 sizeof(*token) + message_buffer->length,
1755 &cksum);
1756 if (ret != 0) {
1757 *minor_status = ret;
1758 free(buf);
1759 return GSS_S_BAD_MIC;
1760 }
1761
1762 free(buf);
1763
1764 if (qop_state != NULL) {
1765 *qop_state = GSS_C_QOP_DEFAULT;
1766 }
1767
1768 return GSS_S_COMPLETE;
1769 }
1770