1 /* $NetBSD: cfx.c,v 1.1.1.2 2014/04/24 12:45:29 pettai Exp $ */
4 * Copyright (c) 2003, PADL Software Pty Ltd.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
14 * 2. Redistributions in binary form must reproduce the above copyright
15 * notice, this list of conditions and the following disclaimer in the
16 * documentation and/or other materials provided with the distribution.
18 * 3. Neither the name of PADL Software nor the names of its contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY PADL SOFTWARE AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL PADL SOFTWARE OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35 #include "gsskrb5_locl.h"
38 * Implementation of RFC 4121
41 #define CFXSentByAcceptor (1 << 0)
42 #define CFXSealed (1 << 1)
43 #define CFXAcceptorSubkey (1 << 2)
46 _gsskrb5cfx_wrap_length_cfx(krb5_context context
,
51 size_t *output_length
,
58 /* 16-byte header is always first */
59 *output_length
= sizeof(gss_cfx_wrap_token_desc
);
62 ret
= krb5_crypto_get_checksum_type(context
, crypto
, &type
);
66 ret
= krb5_checksumsize(context
, type
, cksumsize
);
73 /* Header is concatenated with data before encryption */
74 input_length
+= sizeof(gss_cfx_wrap_token_desc
);
77 ret
= krb5_crypto_getblocksize(context
, crypto
, &padsize
);
79 ret
= krb5_crypto_getpadsize(context
, crypto
, &padsize
);
86 *padlength
= padsize
- (input_length
% padsize
);
88 /* We add the pad ourselves (noted here for completeness only) */
89 input_length
+= *padlength
;
92 *output_length
+= krb5_get_wrapped_length(context
,
93 crypto
, input_length
);
95 /* Checksum is concatenated with data */
96 *output_length
+= input_length
+ *cksumsize
;
99 assert(*output_length
> input_length
);
105 _gssapi_wrap_size_cfx(OM_uint32
*minor_status
,
106 const gsskrb5_ctx ctx
,
107 krb5_context context
,
110 OM_uint32 req_output_size
,
111 OM_uint32
*max_input_size
)
117 /* 16-byte header is always first */
118 if (req_output_size
< 16)
120 req_output_size
-= 16;
123 size_t wrapped_size
, sz
;
125 wrapped_size
= req_output_size
+ 1;
128 sz
= krb5_get_wrapped_length(context
,
129 ctx
->crypto
, wrapped_size
);
130 } while (wrapped_size
&& sz
> req_output_size
);
131 if (wrapped_size
== 0)
135 if (wrapped_size
< 16)
140 *max_input_size
= wrapped_size
;
145 ret
= krb5_crypto_get_checksum_type(context
, ctx
->crypto
, &type
);
149 ret
= krb5_checksumsize(context
, type
, &cksumsize
);
153 if (req_output_size
< cksumsize
)
156 /* Checksum is concatenated with data */
157 *max_input_size
= req_output_size
- cksumsize
;
164 * Rotate "rrc" bytes to the front or back
167 static krb5_error_code
168 rrc_rotate(void *data
, size_t len
, uint16_t rrc
, krb5_boolean unrotate
)
170 u_char
*tmp
, buf
[256];
183 if (rrc
<= sizeof(buf
)) {
192 memcpy(tmp
, data
, rrc
);
193 memmove(data
, (u_char
*)data
+ rrc
, left
);
194 memcpy((u_char
*)data
+ left
, tmp
, rrc
);
196 memcpy(tmp
, (u_char
*)data
+ left
, rrc
);
197 memmove((u_char
*)data
+ rrc
, data
, left
);
198 memcpy(data
, tmp
, rrc
);
201 if (rrc
> sizeof(buf
))
207 gss_iov_buffer_desc
*
208 _gk_find_buffer(gss_iov_buffer_desc
*iov
, int iov_count
, OM_uint32 type
)
212 for (i
= 0; i
< iov_count
; i
++)
213 if (type
== GSS_IOV_BUFFER_TYPE(iov
[i
].type
))
219 _gk_allocate_buffer(OM_uint32
*minor_status
, gss_iov_buffer_desc
*buffer
, size_t size
)
221 if (buffer
->type
& GSS_IOV_BUFFER_FLAG_ALLOCATED
) {
222 if (buffer
->buffer
.length
== size
)
223 return GSS_S_COMPLETE
;
224 free(buffer
->buffer
.value
);
227 buffer
->buffer
.value
= malloc(size
);
228 buffer
->buffer
.length
= size
;
229 if (buffer
->buffer
.value
== NULL
) {
230 *minor_status
= ENOMEM
;
231 return GSS_S_FAILURE
;
233 buffer
->type
|= GSS_IOV_BUFFER_FLAG_ALLOCATED
;
235 return GSS_S_COMPLETE
;
240 _gk_verify_buffers(OM_uint32
*minor_status
,
241 const gsskrb5_ctx ctx
,
242 const gss_iov_buffer_desc
*header
,
243 const gss_iov_buffer_desc
*padding
,
244 const gss_iov_buffer_desc
*trailer
)
246 if (header
== NULL
) {
247 *minor_status
= EINVAL
;
248 return GSS_S_FAILURE
;
251 if (IS_DCE_STYLE(ctx
)) {
253 * In DCE style mode we reject having a padding or trailer buffer
256 *minor_status
= EINVAL
;
257 return GSS_S_FAILURE
;
260 *minor_status
= EINVAL
;
261 return GSS_S_FAILURE
;
265 * In non-DCE style mode we require having a padding buffer
267 if (padding
== NULL
) {
268 *minor_status
= EINVAL
;
269 return GSS_S_FAILURE
;
274 return GSS_S_COMPLETE
;
278 _gssapi_wrap_cfx_iov(OM_uint32
*minor_status
,
280 krb5_context context
,
283 gss_iov_buffer_desc
*iov
,
286 OM_uint32 major_status
, junk
;
287 gss_iov_buffer_desc
*header
, *trailer
, *padding
;
288 size_t gsshsize
, k5hsize
;
289 size_t gsstsize
, k5tsize
;
290 size_t rrc
= 0, ec
= 0;
292 gss_cfx_wrap_token token
;
296 krb5_crypto_iov
*data
= NULL
;
298 header
= _gk_find_buffer(iov
, iov_count
, GSS_IOV_BUFFER_TYPE_HEADER
);
299 if (header
== NULL
) {
300 *minor_status
= EINVAL
;
301 return GSS_S_FAILURE
;
304 padding
= _gk_find_buffer(iov
, iov_count
, GSS_IOV_BUFFER_TYPE_PADDING
);
305 if (padding
!= NULL
) {
306 padding
->buffer
.length
= 0;
309 trailer
= _gk_find_buffer(iov
, iov_count
, GSS_IOV_BUFFER_TYPE_TRAILER
);
311 major_status
= _gk_verify_buffers(minor_status
, ctx
, header
, padding
, trailer
);
312 if (major_status
!= GSS_S_COMPLETE
) {
322 for (i
= 0; i
< iov_count
; i
++) {
323 switch (GSS_IOV_BUFFER_TYPE(iov
[i
].type
)) {
324 case GSS_IOV_BUFFER_TYPE_DATA
:
325 size
+= iov
[i
].buffer
.length
;
332 size
+= sizeof(gss_cfx_wrap_token_desc
);
334 *minor_status
= krb5_crypto_length(context
, ctx
->crypto
,
335 KRB5_CRYPTO_TYPE_HEADER
,
338 return GSS_S_FAILURE
;
340 *minor_status
= krb5_crypto_length(context
, ctx
->crypto
,
341 KRB5_CRYPTO_TYPE_TRAILER
,
344 return GSS_S_FAILURE
;
346 *minor_status
= krb5_crypto_length(context
, ctx
->crypto
,
347 KRB5_CRYPTO_TYPE_PADDING
,
350 return GSS_S_FAILURE
;
353 k5psize
= k5pbase
- (size
% k5pbase
);
358 if (k5psize
== 0 && IS_DCE_STYLE(ctx
)) {
359 *minor_status
= krb5_crypto_getblocksize(context
, ctx
->crypto
,
362 return GSS_S_FAILURE
;
368 gsshsize
= sizeof(gss_cfx_wrap_token_desc
) + k5hsize
;
369 gsstsize
= sizeof(gss_cfx_wrap_token_desc
) + ec
+ k5tsize
;
371 if (IS_DCE_STYLE(ctx
)) {
372 *minor_status
= EINVAL
;
373 return GSS_S_FAILURE
;
377 *minor_status
= krb5_crypto_length(context
, ctx
->crypto
,
378 KRB5_CRYPTO_TYPE_CHECKSUM
,
381 return GSS_S_FAILURE
;
383 gsshsize
= sizeof(gss_cfx_wrap_token_desc
);
391 if (trailer
== NULL
) {
393 if (IS_DCE_STYLE(ctx
))
395 gsshsize
+= gsstsize
;
397 } else if (GSS_IOV_BUFFER_FLAGS(trailer
->type
) & GSS_IOV_BUFFER_FLAG_ALLOCATE
) {
398 major_status
= _gk_allocate_buffer(minor_status
, trailer
, gsstsize
);
401 } else if (trailer
->buffer
.length
< gsstsize
) {
402 *minor_status
= KRB5_BAD_MSIZE
;
403 major_status
= GSS_S_FAILURE
;
406 trailer
->buffer
.length
= gsstsize
;
412 if (GSS_IOV_BUFFER_FLAGS(header
->type
) & GSS_IOV_BUFFER_FLAG_ALLOCATE
) {
413 major_status
= _gk_allocate_buffer(minor_status
, header
, gsshsize
);
414 if (major_status
!= GSS_S_COMPLETE
)
416 } else if (header
->buffer
.length
< gsshsize
) {
417 *minor_status
= KRB5_BAD_MSIZE
;
418 major_status
= GSS_S_FAILURE
;
421 header
->buffer
.length
= gsshsize
;
423 token
= (gss_cfx_wrap_token
)header
->buffer
.value
;
425 token
->TOK_ID
[0] = 0x05;
426 token
->TOK_ID
[1] = 0x04;
428 token
->Filler
= 0xFF;
430 if ((ctx
->more_flags
& LOCAL
) == 0)
431 token
->Flags
|= CFXSentByAcceptor
;
433 if (ctx
->more_flags
& ACCEPTOR_SUBKEY
)
434 token
->Flags
|= CFXAcceptorSubkey
;
436 if (ctx
->more_flags
& LOCAL
)
437 usage
= KRB5_KU_USAGE_INITIATOR_SEAL
;
439 usage
= KRB5_KU_USAGE_ACCEPTOR_SEAL
;
443 * In Wrap tokens with confidentiality, the EC field is
444 * used to encode the size (in bytes) of the random filler.
446 token
->Flags
|= CFXSealed
;
447 token
->EC
[0] = (ec
>> 8) & 0xFF;
448 token
->EC
[1] = (ec
>> 0) & 0xFF;
452 * In Wrap tokens without confidentiality, the EC field is
453 * used to encode the size (in bytes) of the trailing
456 * This is not used in the checksum calcuation itself,
457 * because the checksum length could potentially vary
458 * depending on the data length.
465 * In Wrap tokens that provide for confidentiality, the RRC
466 * field in the header contains the hex value 00 00 before
469 * In Wrap tokens that do not provide for confidentiality,
470 * both the EC and RRC fields in the appended checksum
471 * contain the hex value 00 00 for the purpose of calculating
477 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
478 krb5_auth_con_getlocalseqnumber(context
,
481 _gsskrb5_encode_be_om_uint32(0, &token
->SND_SEQ
[0]);
482 _gsskrb5_encode_be_om_uint32(seq_number
, &token
->SND_SEQ
[4]);
483 krb5_auth_con_setlocalseqnumber(context
,
486 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
488 data
= calloc(iov_count
+ 3, sizeof(data
[0]));
490 *minor_status
= ENOMEM
;
491 major_status
= GSS_S_FAILURE
;
499 {"header" | encrypt(plaintext-data | ec-padding | E"header")}
501 Expanded, this is with with RRC = 0:
503 {"header" | krb5-header | plaintext-data | ec-padding | E"header" | krb5-trailer }
505 In DCE-RPC mode == no trailer: RRC = gss "trailer" == length(ec-padding | E"header" | krb5-trailer)
507 {"header" | ec-padding | E"header" | krb5-trailer | krb5-header | plaintext-data }
511 data
[i
].flags
= KRB5_CRYPTO_TYPE_HEADER
;
512 data
[i
].data
.data
= ((uint8_t *)header
->buffer
.value
) + header
->buffer
.length
- k5hsize
;
513 data
[i
].data
.length
= k5hsize
;
515 for (i
= 1; i
< iov_count
+ 1; i
++) {
516 switch (GSS_IOV_BUFFER_TYPE(iov
[i
- 1].type
)) {
517 case GSS_IOV_BUFFER_TYPE_DATA
:
518 data
[i
].flags
= KRB5_CRYPTO_TYPE_DATA
;
520 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY
:
521 data
[i
].flags
= KRB5_CRYPTO_TYPE_SIGN_ONLY
;
524 data
[i
].flags
= KRB5_CRYPTO_TYPE_EMPTY
;
527 data
[i
].data
.length
= iov
[i
- 1].buffer
.length
;
528 data
[i
].data
.data
= iov
[i
- 1].buffer
.value
;
532 * Any necessary padding is added here to ensure that the
533 * encrypted token header is always at the end of the
537 /* encrypted CFX header in trailer (or after the header if in
538 DCE mode). Copy in header into E"header"
540 data
[i
].flags
= KRB5_CRYPTO_TYPE_DATA
;
542 data
[i
].data
.data
= trailer
->buffer
.value
;
544 data
[i
].data
.data
= ((uint8_t *)header
->buffer
.value
) + sizeof(*token
);
546 data
[i
].data
.length
= ec
+ sizeof(*token
);
547 memset(data
[i
].data
.data
, 0xFF, ec
);
548 memcpy(((uint8_t *)data
[i
].data
.data
) + ec
, token
, sizeof(*token
));
551 /* Kerberos trailer comes after the gss trailer */
552 data
[i
].flags
= KRB5_CRYPTO_TYPE_TRAILER
;
553 data
[i
].data
.data
= ((uint8_t *)data
[i
-1].data
.data
) + ec
+ sizeof(*token
);
554 data
[i
].data
.length
= k5tsize
;
557 ret
= krb5_encrypt_iov_ivec(context
, ctx
->crypto
, usage
, data
, i
, NULL
);
560 major_status
= GSS_S_FAILURE
;
565 token
->RRC
[0] = (rrc
>> 8) & 0xFF;
566 token
->RRC
[1] = (rrc
>> 0) & 0xFF;
573 {data | "header" | gss-trailer (krb5 checksum)
579 for (i
= 0; i
< iov_count
; i
++) {
580 switch (GSS_IOV_BUFFER_TYPE(iov
[i
].type
)) {
581 case GSS_IOV_BUFFER_TYPE_DATA
:
582 data
[i
].flags
= KRB5_CRYPTO_TYPE_DATA
;
584 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY
:
585 data
[i
].flags
= KRB5_CRYPTO_TYPE_SIGN_ONLY
;
588 data
[i
].flags
= KRB5_CRYPTO_TYPE_EMPTY
;
591 data
[i
].data
.length
= iov
[i
].buffer
.length
;
592 data
[i
].data
.data
= iov
[i
].buffer
.value
;
595 data
[i
].flags
= KRB5_CRYPTO_TYPE_DATA
;
596 data
[i
].data
.data
= header
->buffer
.value
;
597 data
[i
].data
.length
= sizeof(gss_cfx_wrap_token_desc
);
600 data
[i
].flags
= KRB5_CRYPTO_TYPE_CHECKSUM
;
602 data
[i
].data
.data
= trailer
->buffer
.value
;
604 data
[i
].data
.data
= (uint8_t *)header
->buffer
.value
+
605 sizeof(gss_cfx_wrap_token_desc
);
607 data
[i
].data
.length
= k5tsize
;
610 ret
= krb5_create_checksum_iov(context
, ctx
->crypto
, usage
, data
, i
, NULL
);
613 major_status
= GSS_S_FAILURE
;
618 token
->RRC
[0] = (rrc
>> 8) & 0xFF;
619 token
->RRC
[1] = (rrc
>> 0) & 0xFF;
622 token
->EC
[0] = (k5tsize
>> 8) & 0xFF;
623 token
->EC
[1] = (k5tsize
>> 0) & 0xFF;
626 if (conf_state
!= NULL
)
627 *conf_state
= conf_req_flag
;
632 return GSS_S_COMPLETE
;
638 gss_release_iov_buffer(&junk
, iov
, iov_count
);
643 /* This is slowpath */
645 unrotate_iov(OM_uint32
*minor_status
, size_t rrc
, gss_iov_buffer_desc
*iov
, int iov_count
)
648 size_t len
= 0, skip
;
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
;
659 *minor_status
= ENOMEM
;
660 return GSS_S_FAILURE
;
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
)
671 memcpy(q
, iov
[i
].buffer
.value
, iov
[i
].buffer
.length
);
672 q
+= iov
[i
].buffer
.length
;
675 assert((size_t)(q
- p
) == len
);
677 /* unrotate first part */
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
)
685 if (iov
[i
].buffer
.length
<= skip
) {
686 skip
-= iov
[i
].buffer
.length
;
688 memcpy(((uint8_t *)iov
[i
].buffer
.value
) + skip
, q
, iov
[i
].buffer
.length
- skip
);
689 q
+= iov
[i
].buffer
.length
- skip
;
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
)
702 memcpy(q
, iov
[i
].buffer
.value
, min(iov
[i
].buffer
.length
, skip
));
703 if (iov
[i
].buffer
.length
> skip
)
705 skip
-= iov
[i
].buffer
.length
;
706 q
+= iov
[i
].buffer
.length
;
709 return GSS_S_COMPLETE
;
714 _gssapi_unwrap_cfx_iov(OM_uint32
*minor_status
,
716 krb5_context context
,
718 gss_qop_t
*qop_state
,
719 gss_iov_buffer_desc
*iov
,
722 OM_uint32 seq_number_lo
, seq_number_hi
, major_status
, junk
;
723 gss_iov_buffer_desc
*header
, *trailer
, *padding
;
724 gss_cfx_wrap_token token
, ttoken
;
729 krb5_crypto_iov
*data
= NULL
;
734 header
= _gk_find_buffer(iov
, iov_count
, GSS_IOV_BUFFER_TYPE_HEADER
);
735 if (header
== NULL
) {
736 *minor_status
= EINVAL
;
737 return GSS_S_FAILURE
;
740 if (header
->buffer
.length
< sizeof(*token
)) /* we check exact below */
741 return GSS_S_DEFECTIVE_TOKEN
;
743 padding
= _gk_find_buffer(iov
, iov_count
, GSS_IOV_BUFFER_TYPE_PADDING
);
744 if (padding
!= NULL
&& padding
->buffer
.length
!= 0) {
745 *minor_status
= EINVAL
;
746 return GSS_S_FAILURE
;
749 trailer
= _gk_find_buffer(iov
, iov_count
, GSS_IOV_BUFFER_TYPE_TRAILER
);
751 major_status
= _gk_verify_buffers(minor_status
, ctx
, header
, padding
, trailer
);
752 if (major_status
!= GSS_S_COMPLETE
) {
756 token
= (gss_cfx_wrap_token
)header
->buffer
.value
;
758 if (token
->TOK_ID
[0] != 0x05 || token
->TOK_ID
[1] != 0x04)
759 return GSS_S_DEFECTIVE_TOKEN
;
761 /* Ignore unknown flags */
762 token_flags
= token
->Flags
&
763 (CFXSentByAcceptor
| CFXSealed
| CFXAcceptorSubkey
);
765 if (token_flags
& CFXSentByAcceptor
) {
766 if ((ctx
->more_flags
& LOCAL
) == 0)
767 return GSS_S_DEFECTIVE_TOKEN
;
770 if (ctx
->more_flags
& ACCEPTOR_SUBKEY
) {
771 if ((token_flags
& CFXAcceptorSubkey
) == 0)
772 return GSS_S_DEFECTIVE_TOKEN
;
774 if (token_flags
& CFXAcceptorSubkey
)
775 return GSS_S_DEFECTIVE_TOKEN
;
778 if (token
->Filler
!= 0xFF)
779 return GSS_S_DEFECTIVE_TOKEN
;
781 if (conf_state
!= NULL
)
782 *conf_state
= (token_flags
& CFXSealed
) ? 1 : 0;
784 ec
= (token
->EC
[0] << 8) | token
->EC
[1];
785 rrc
= (token
->RRC
[0] << 8) | token
->RRC
[1];
788 * Check sequence number
790 _gsskrb5_decode_be_om_uint32(&token
->SND_SEQ
[0], &seq_number_hi
);
791 _gsskrb5_decode_be_om_uint32(&token
->SND_SEQ
[4], &seq_number_lo
);
793 /* no support for 64-bit sequence numbers */
794 *minor_status
= ERANGE
;
795 return GSS_S_UNSEQ_TOKEN
;
798 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
799 ret
= _gssapi_msg_order_check(ctx
->order
, seq_number_lo
);
802 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
805 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
808 * Decrypt and/or verify checksum
811 if (ctx
->more_flags
& LOCAL
) {
812 usage
= KRB5_KU_USAGE_ACCEPTOR_SEAL
;
814 usage
= KRB5_KU_USAGE_INITIATOR_SEAL
;
817 data
= calloc(iov_count
+ 3, sizeof(data
[0]));
819 *minor_status
= ENOMEM
;
820 major_status
= GSS_S_FAILURE
;
824 if (token_flags
& CFXSealed
) {
825 size_t k5tsize
, k5hsize
;
827 krb5_crypto_length(context
, ctx
->crypto
, KRB5_CRYPTO_TYPE_HEADER
, &k5hsize
);
828 krb5_crypto_length(context
, ctx
->crypto
, KRB5_CRYPTO_TYPE_TRAILER
, &k5tsize
);
830 /* Rotate by RRC; bogus to do this in-place XXX */
833 if (trailer
== NULL
) {
834 size_t gsstsize
= k5tsize
+ sizeof(*token
);
835 size_t gsshsize
= k5hsize
+ sizeof(*token
);
837 if (rrc
!= gsstsize
) {
838 major_status
= GSS_S_DEFECTIVE_TOKEN
;
842 if (IS_DCE_STYLE(ctx
))
845 gsshsize
+= gsstsize
;
847 if (header
->buffer
.length
!= gsshsize
) {
848 major_status
= GSS_S_DEFECTIVE_TOKEN
;
851 } else if (trailer
->buffer
.length
!= sizeof(*token
) + k5tsize
) {
852 major_status
= GSS_S_DEFECTIVE_TOKEN
;
854 } else if (header
->buffer
.length
!= sizeof(*token
) + k5hsize
) {
855 major_status
= GSS_S_DEFECTIVE_TOKEN
;
857 } else if (rrc
!= 0) {
858 /* go though slowpath */
859 major_status
= unrotate_iov(minor_status
, rrc
, iov
, iov_count
);
865 data
[i
].flags
= KRB5_CRYPTO_TYPE_HEADER
;
866 data
[i
].data
.data
= ((uint8_t *)header
->buffer
.value
) + header
->buffer
.length
- k5hsize
;
867 data
[i
].data
.length
= k5hsize
;
870 for (j
= 0; j
< iov_count
; i
++, j
++) {
871 switch (GSS_IOV_BUFFER_TYPE(iov
[j
].type
)) {
872 case GSS_IOV_BUFFER_TYPE_DATA
:
873 data
[i
].flags
= KRB5_CRYPTO_TYPE_DATA
;
875 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY
:
876 data
[i
].flags
= KRB5_CRYPTO_TYPE_SIGN_ONLY
;
879 data
[i
].flags
= KRB5_CRYPTO_TYPE_EMPTY
;
882 data
[i
].data
.length
= iov
[j
].buffer
.length
;
883 data
[i
].data
.data
= iov
[j
].buffer
.value
;
886 /* encrypted CFX header in trailer (or after the header if in
887 DCE mode). Copy in header into E"header"
889 data
[i
].flags
= KRB5_CRYPTO_TYPE_DATA
;
891 data
[i
].data
.data
= trailer
->buffer
.value
;
893 data
[i
].data
.data
= ((uint8_t *)header
->buffer
.value
) +
894 header
->buffer
.length
- k5hsize
- k5tsize
- ec
- sizeof(*token
);
897 data
[i
].data
.length
= ec
+ sizeof(*token
);
898 ttoken
= (gss_cfx_wrap_token
)(((uint8_t *)data
[i
].data
.data
) + ec
);
901 /* Kerberos trailer comes after the gss trailer */
902 data
[i
].flags
= KRB5_CRYPTO_TYPE_TRAILER
;
903 data
[i
].data
.data
= ((uint8_t *)data
[i
-1].data
.data
) + ec
+ sizeof(*token
);
904 data
[i
].data
.length
= k5tsize
;
907 ret
= krb5_decrypt_iov_ivec(context
, ctx
->crypto
, usage
, data
, i
, NULL
);
910 major_status
= GSS_S_FAILURE
;
914 ttoken
->RRC
[0] = token
->RRC
[0];
915 ttoken
->RRC
[1] = token
->RRC
[1];
917 /* Check the integrity of the header */
918 if (ct_memcmp(ttoken
, token
, sizeof(*token
)) != 0) {
919 major_status
= GSS_S_BAD_MIC
;
923 size_t gsstsize
= ec
;
924 size_t gsshsize
= sizeof(*token
);
926 if (trailer
== NULL
) {
928 if (rrc
!= gsstsize
) {
929 *minor_status
= EINVAL
;
930 major_status
= GSS_S_FAILURE
;
934 gsshsize
+= gsstsize
;
936 } else if (trailer
->buffer
.length
!= gsstsize
) {
937 major_status
= GSS_S_DEFECTIVE_TOKEN
;
939 } else if (rrc
!= 0) {
941 *minor_status
= EINVAL
;
942 major_status
= GSS_S_FAILURE
;
946 if (header
->buffer
.length
!= gsshsize
) {
947 major_status
= GSS_S_DEFECTIVE_TOKEN
;
951 for (i
= 0; i
< iov_count
; i
++) {
952 switch (GSS_IOV_BUFFER_TYPE(iov
[i
].type
)) {
953 case GSS_IOV_BUFFER_TYPE_DATA
:
954 data
[i
].flags
= KRB5_CRYPTO_TYPE_DATA
;
956 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY
:
957 data
[i
].flags
= KRB5_CRYPTO_TYPE_SIGN_ONLY
;
960 data
[i
].flags
= KRB5_CRYPTO_TYPE_EMPTY
;
963 data
[i
].data
.length
= iov
[i
].buffer
.length
;
964 data
[i
].data
.data
= iov
[i
].buffer
.value
;
967 data
[i
].flags
= KRB5_CRYPTO_TYPE_DATA
;
968 data
[i
].data
.data
= header
->buffer
.value
;
969 data
[i
].data
.length
= sizeof(*token
);
972 data
[i
].flags
= KRB5_CRYPTO_TYPE_CHECKSUM
;
974 data
[i
].data
.data
= trailer
->buffer
.value
;
976 data
[i
].data
.data
= (uint8_t *)header
->buffer
.value
+
979 data
[i
].data
.length
= ec
;
982 token
= (gss_cfx_wrap_token
)header
->buffer
.value
;
988 ret
= krb5_verify_checksum_iov(context
, ctx
->crypto
, usage
, data
, i
, NULL
);
991 major_status
= GSS_S_FAILURE
;
996 if (qop_state
!= NULL
) {
997 *qop_state
= GSS_C_QOP_DEFAULT
;
1003 return GSS_S_COMPLETE
;
1009 gss_release_iov_buffer(&junk
, iov
, iov_count
);
1011 return major_status
;
1015 _gssapi_wrap_iov_length_cfx(OM_uint32
*minor_status
,
1017 krb5_context context
,
1021 gss_iov_buffer_desc
*iov
,
1024 OM_uint32 major_status
;
1027 gss_iov_buffer_desc
*header
= NULL
;
1028 gss_iov_buffer_desc
*padding
= NULL
;
1029 gss_iov_buffer_desc
*trailer
= NULL
;
1030 size_t gsshsize
= 0;
1031 size_t gsstsize
= 0;
1035 GSSAPI_KRB5_INIT (&context
);
1038 for (size
= 0, i
= 0; i
< iov_count
; i
++) {
1039 switch(GSS_IOV_BUFFER_TYPE(iov
[i
].type
)) {
1040 case GSS_IOV_BUFFER_TYPE_EMPTY
:
1042 case GSS_IOV_BUFFER_TYPE_DATA
:
1043 size
+= iov
[i
].buffer
.length
;
1045 case GSS_IOV_BUFFER_TYPE_HEADER
:
1046 if (header
!= NULL
) {
1048 return GSS_S_FAILURE
;
1052 case GSS_IOV_BUFFER_TYPE_TRAILER
:
1053 if (trailer
!= NULL
) {
1055 return GSS_S_FAILURE
;
1059 case GSS_IOV_BUFFER_TYPE_PADDING
:
1060 if (padding
!= NULL
) {
1062 return GSS_S_FAILURE
;
1066 case GSS_IOV_BUFFER_TYPE_SIGN_ONLY
:
1069 *minor_status
= EINVAL
;
1070 return GSS_S_FAILURE
;
1074 major_status
= _gk_verify_buffers(minor_status
, ctx
, header
, padding
, trailer
);
1075 if (major_status
!= GSS_S_COMPLETE
) {
1076 return major_status
;
1079 if (conf_req_flag
) {
1085 size
+= sizeof(gss_cfx_wrap_token_desc
);
1087 *minor_status
= krb5_crypto_length(context
, ctx
->crypto
,
1088 KRB5_CRYPTO_TYPE_HEADER
,
1091 return GSS_S_FAILURE
;
1093 *minor_status
= krb5_crypto_length(context
, ctx
->crypto
,
1094 KRB5_CRYPTO_TYPE_TRAILER
,
1097 return GSS_S_FAILURE
;
1099 *minor_status
= krb5_crypto_length(context
, ctx
->crypto
,
1100 KRB5_CRYPTO_TYPE_PADDING
,
1103 return GSS_S_FAILURE
;
1106 k5psize
= k5pbase
- (size
% k5pbase
);
1111 if (k5psize
== 0 && IS_DCE_STYLE(ctx
)) {
1112 *minor_status
= krb5_crypto_getblocksize(context
, ctx
->crypto
,
1115 return GSS_S_FAILURE
;
1122 gsshsize
= sizeof(gss_cfx_wrap_token_desc
) + k5hsize
;
1123 gsstsize
= sizeof(gss_cfx_wrap_token_desc
) + ec
+ k5tsize
;
1125 *minor_status
= krb5_crypto_length(context
, ctx
->crypto
,
1126 KRB5_CRYPTO_TYPE_CHECKSUM
,
1129 return GSS_S_FAILURE
;
1131 gsshsize
= sizeof(gss_cfx_wrap_token_desc
);
1135 if (trailer
!= NULL
) {
1136 trailer
->buffer
.length
= gsstsize
;
1138 gsshsize
+= gsstsize
;
1141 header
->buffer
.length
= gsshsize
;
1144 /* padding is done via EC and is contained in the header or trailer */
1145 padding
->buffer
.length
= 0;
1149 *conf_state
= conf_req_flag
;
1152 return GSS_S_COMPLETE
;
1158 OM_uint32
_gssapi_wrap_cfx(OM_uint32
*minor_status
,
1159 const gsskrb5_ctx ctx
,
1160 krb5_context context
,
1162 const gss_buffer_t input_message_buffer
,
1164 gss_buffer_t output_message_buffer
)
1166 gss_cfx_wrap_token token
;
1167 krb5_error_code ret
;
1170 size_t wrapped_len
, cksumsize
;
1171 uint16_t padlength
, rrc
= 0;
1175 ret
= _gsskrb5cfx_wrap_length_cfx(context
,
1176 ctx
->crypto
, conf_req_flag
,
1178 input_message_buffer
->length
,
1179 &wrapped_len
, &cksumsize
, &padlength
);
1181 *minor_status
= ret
;
1182 return GSS_S_FAILURE
;
1185 /* Always rotate encrypted token (if any) and checksum to header */
1186 rrc
= (conf_req_flag
? sizeof(*token
) : 0) + (uint16_t)cksumsize
;
1188 output_message_buffer
->length
= wrapped_len
;
1189 output_message_buffer
->value
= malloc(output_message_buffer
->length
);
1190 if (output_message_buffer
->value
== NULL
) {
1191 *minor_status
= ENOMEM
;
1192 return GSS_S_FAILURE
;
1195 p
= output_message_buffer
->value
;
1196 token
= (gss_cfx_wrap_token
)p
;
1197 token
->TOK_ID
[0] = 0x05;
1198 token
->TOK_ID
[1] = 0x04;
1200 token
->Filler
= 0xFF;
1201 if ((ctx
->more_flags
& LOCAL
) == 0)
1202 token
->Flags
|= CFXSentByAcceptor
;
1203 if (ctx
->more_flags
& ACCEPTOR_SUBKEY
)
1204 token
->Flags
|= CFXAcceptorSubkey
;
1205 if (conf_req_flag
) {
1207 * In Wrap tokens with confidentiality, the EC field is
1208 * used to encode the size (in bytes) of the random filler.
1210 token
->Flags
|= CFXSealed
;
1211 token
->EC
[0] = (padlength
>> 8) & 0xFF;
1212 token
->EC
[1] = (padlength
>> 0) & 0xFF;
1215 * In Wrap tokens without confidentiality, the EC field is
1216 * used to encode the size (in bytes) of the trailing
1219 * This is not used in the checksum calcuation itself,
1220 * because the checksum length could potentially vary
1221 * depending on the data length.
1228 * In Wrap tokens that provide for confidentiality, the RRC
1229 * field in the header contains the hex value 00 00 before
1232 * In Wrap tokens that do not provide for confidentiality,
1233 * both the EC and RRC fields in the appended checksum
1234 * contain the hex value 00 00 for the purpose of calculating
1240 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
1241 krb5_auth_con_getlocalseqnumber(context
,
1244 _gsskrb5_encode_be_om_uint32(0, &token
->SND_SEQ
[0]);
1245 _gsskrb5_encode_be_om_uint32(seq_number
, &token
->SND_SEQ
[4]);
1246 krb5_auth_con_setlocalseqnumber(context
,
1249 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
1252 * If confidentiality is requested, the token header is
1253 * appended to the plaintext before encryption; the resulting
1254 * token is {"header" | encrypt(plaintext | pad | "header")}.
1256 * If no confidentiality is requested, the checksum is
1257 * calculated over the plaintext concatenated with the
1260 if (ctx
->more_flags
& LOCAL
) {
1261 usage
= KRB5_KU_USAGE_INITIATOR_SEAL
;
1263 usage
= KRB5_KU_USAGE_ACCEPTOR_SEAL
;
1266 if (conf_req_flag
) {
1268 * Any necessary padding is added here to ensure that the
1269 * encrypted token header is always at the end of the
1272 * The specification does not require that the padding
1273 * bytes are initialized.
1275 p
+= sizeof(*token
);
1276 memcpy(p
, input_message_buffer
->value
, input_message_buffer
->length
);
1277 memset(p
+ input_message_buffer
->length
, 0xFF, padlength
);
1278 memcpy(p
+ input_message_buffer
->length
+ padlength
,
1279 token
, sizeof(*token
));
1281 ret
= krb5_encrypt(context
, ctx
->crypto
,
1283 input_message_buffer
->length
+ padlength
+
1287 *minor_status
= ret
;
1288 _gsskrb5_release_buffer(minor_status
, output_message_buffer
);
1289 return GSS_S_FAILURE
;
1291 assert(sizeof(*token
) + cipher
.length
== wrapped_len
);
1292 token
->RRC
[0] = (rrc
>> 8) & 0xFF;
1293 token
->RRC
[1] = (rrc
>> 0) & 0xFF;
1296 * this is really ugly, but needed against windows
1297 * for DCERPC, as windows rotates by EC+RRC.
1299 if (IS_DCE_STYLE(ctx
)) {
1300 ret
= rrc_rotate(cipher
.data
, cipher
.length
, rrc
+padlength
, FALSE
);
1302 ret
= rrc_rotate(cipher
.data
, cipher
.length
, rrc
, FALSE
);
1305 *minor_status
= ret
;
1306 _gsskrb5_release_buffer(minor_status
, output_message_buffer
);
1307 return GSS_S_FAILURE
;
1309 memcpy(p
, cipher
.data
, cipher
.length
);
1310 krb5_data_free(&cipher
);
1315 buf
= malloc(input_message_buffer
->length
+ sizeof(*token
));
1317 *minor_status
= ENOMEM
;
1318 _gsskrb5_release_buffer(minor_status
, output_message_buffer
);
1319 return GSS_S_FAILURE
;
1321 memcpy(buf
, input_message_buffer
->value
, input_message_buffer
->length
);
1322 memcpy(buf
+ input_message_buffer
->length
, token
, sizeof(*token
));
1324 ret
= krb5_create_checksum(context
, ctx
->crypto
,
1326 input_message_buffer
->length
+
1330 *minor_status
= ret
;
1331 _gsskrb5_release_buffer(minor_status
, output_message_buffer
);
1333 return GSS_S_FAILURE
;
1338 assert(cksum
.checksum
.length
== cksumsize
);
1339 token
->EC
[0] = (cksum
.checksum
.length
>> 8) & 0xFF;
1340 token
->EC
[1] = (cksum
.checksum
.length
>> 0) & 0xFF;
1341 token
->RRC
[0] = (rrc
>> 8) & 0xFF;
1342 token
->RRC
[1] = (rrc
>> 0) & 0xFF;
1344 p
+= sizeof(*token
);
1345 memcpy(p
, input_message_buffer
->value
, input_message_buffer
->length
);
1346 memcpy(p
+ input_message_buffer
->length
,
1347 cksum
.checksum
.data
, cksum
.checksum
.length
);
1350 input_message_buffer
->length
+ cksum
.checksum
.length
, rrc
, FALSE
);
1352 *minor_status
= ret
;
1353 _gsskrb5_release_buffer(minor_status
, output_message_buffer
);
1354 free_Checksum(&cksum
);
1355 return GSS_S_FAILURE
;
1357 free_Checksum(&cksum
);
1360 if (conf_state
!= NULL
) {
1361 *conf_state
= conf_req_flag
;
1365 return GSS_S_COMPLETE
;
1368 OM_uint32
_gssapi_unwrap_cfx(OM_uint32
*minor_status
,
1369 const gsskrb5_ctx ctx
,
1370 krb5_context context
,
1371 const gss_buffer_t input_message_buffer
,
1372 gss_buffer_t output_message_buffer
,
1374 gss_qop_t
*qop_state
)
1376 gss_cfx_wrap_token token
;
1378 krb5_error_code ret
;
1382 OM_uint32 seq_number_lo
, seq_number_hi
;
1388 if (input_message_buffer
->length
< sizeof(*token
)) {
1389 return GSS_S_DEFECTIVE_TOKEN
;
1392 p
= input_message_buffer
->value
;
1394 token
= (gss_cfx_wrap_token
)p
;
1396 if (token
->TOK_ID
[0] != 0x05 || token
->TOK_ID
[1] != 0x04) {
1397 return GSS_S_DEFECTIVE_TOKEN
;
1400 /* Ignore unknown flags */
1401 token_flags
= token
->Flags
&
1402 (CFXSentByAcceptor
| CFXSealed
| CFXAcceptorSubkey
);
1404 if (token_flags
& CFXSentByAcceptor
) {
1405 if ((ctx
->more_flags
& LOCAL
) == 0)
1406 return GSS_S_DEFECTIVE_TOKEN
;
1409 if (ctx
->more_flags
& ACCEPTOR_SUBKEY
) {
1410 if ((token_flags
& CFXAcceptorSubkey
) == 0)
1411 return GSS_S_DEFECTIVE_TOKEN
;
1413 if (token_flags
& CFXAcceptorSubkey
)
1414 return GSS_S_DEFECTIVE_TOKEN
;
1417 if (token
->Filler
!= 0xFF) {
1418 return GSS_S_DEFECTIVE_TOKEN
;
1421 if (conf_state
!= NULL
) {
1422 *conf_state
= (token_flags
& CFXSealed
) ? 1 : 0;
1425 ec
= (token
->EC
[0] << 8) | token
->EC
[1];
1426 rrc
= (token
->RRC
[0] << 8) | token
->RRC
[1];
1429 * Check sequence number
1431 _gsskrb5_decode_be_om_uint32(&token
->SND_SEQ
[0], &seq_number_hi
);
1432 _gsskrb5_decode_be_om_uint32(&token
->SND_SEQ
[4], &seq_number_lo
);
1433 if (seq_number_hi
) {
1434 /* no support for 64-bit sequence numbers */
1435 *minor_status
= ERANGE
;
1436 return GSS_S_UNSEQ_TOKEN
;
1439 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
1440 ret
= _gssapi_msg_order_check(ctx
->order
, seq_number_lo
);
1443 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
1444 _gsskrb5_release_buffer(minor_status
, output_message_buffer
);
1447 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
1450 * Decrypt and/or verify checksum
1453 if (ctx
->more_flags
& LOCAL
) {
1454 usage
= KRB5_KU_USAGE_ACCEPTOR_SEAL
;
1456 usage
= KRB5_KU_USAGE_INITIATOR_SEAL
;
1459 p
+= sizeof(*token
);
1460 len
= input_message_buffer
->length
;
1461 len
-= (p
- (u_char
*)input_message_buffer
->value
);
1463 if (token_flags
& CFXSealed
) {
1465 * this is really ugly, but needed against windows
1466 * for DCERPC, as windows rotates by EC+RRC.
1468 if (IS_DCE_STYLE(ctx
)) {
1469 *minor_status
= rrc_rotate(p
, len
, rrc
+ec
, TRUE
);
1471 *minor_status
= rrc_rotate(p
, len
, rrc
, TRUE
);
1473 if (*minor_status
!= 0) {
1474 return GSS_S_FAILURE
;
1477 ret
= krb5_decrypt(context
, ctx
->crypto
, usage
,
1480 *minor_status
= ret
;
1481 return GSS_S_BAD_MIC
;
1484 /* Check that there is room for the pad and token header */
1485 if (data
.length
< ec
+ sizeof(*token
)) {
1486 krb5_data_free(&data
);
1487 return GSS_S_DEFECTIVE_TOKEN
;
1490 p
+= data
.length
- sizeof(*token
);
1492 /* RRC is unprotected; don't modify input buffer */
1493 ((gss_cfx_wrap_token
)p
)->RRC
[0] = token
->RRC
[0];
1494 ((gss_cfx_wrap_token
)p
)->RRC
[1] = token
->RRC
[1];
1496 /* Check the integrity of the header */
1497 if (ct_memcmp(p
, token
, sizeof(*token
)) != 0) {
1498 krb5_data_free(&data
);
1499 return GSS_S_BAD_MIC
;
1502 output_message_buffer
->value
= data
.data
;
1503 output_message_buffer
->length
= data
.length
- ec
- sizeof(*token
);
1507 /* Rotate by RRC; bogus to do this in-place XXX */
1508 *minor_status
= rrc_rotate(p
, len
, rrc
, TRUE
);
1509 if (*minor_status
!= 0) {
1510 return GSS_S_FAILURE
;
1513 /* Determine checksum type */
1514 ret
= krb5_crypto_get_checksum_type(context
,
1518 *minor_status
= ret
;
1519 return GSS_S_FAILURE
;
1522 cksum
.checksum
.length
= ec
;
1524 /* Check we have at least as much data as the checksum */
1525 if (len
< cksum
.checksum
.length
) {
1526 *minor_status
= ERANGE
;
1527 return GSS_S_BAD_MIC
;
1530 /* Length now is of the plaintext only, no checksum */
1531 len
-= cksum
.checksum
.length
;
1532 cksum
.checksum
.data
= p
+ len
;
1534 output_message_buffer
->length
= len
; /* for later */
1535 output_message_buffer
->value
= malloc(len
+ sizeof(*token
));
1536 if (output_message_buffer
->value
== NULL
) {
1537 *minor_status
= ENOMEM
;
1538 return GSS_S_FAILURE
;
1541 /* Checksum is over (plaintext-data | "header") */
1542 memcpy(output_message_buffer
->value
, p
, len
);
1543 memcpy((u_char
*)output_message_buffer
->value
+ len
,
1544 token
, sizeof(*token
));
1546 /* EC is not included in checksum calculation */
1547 token
= (gss_cfx_wrap_token
)((u_char
*)output_message_buffer
->value
+
1554 ret
= krb5_verify_checksum(context
, ctx
->crypto
,
1556 output_message_buffer
->value
,
1557 len
+ sizeof(*token
),
1560 *minor_status
= ret
;
1561 _gsskrb5_release_buffer(minor_status
, output_message_buffer
);
1562 return GSS_S_BAD_MIC
;
1566 if (qop_state
!= NULL
) {
1567 *qop_state
= GSS_C_QOP_DEFAULT
;
1571 return GSS_S_COMPLETE
;
1574 OM_uint32
_gssapi_mic_cfx(OM_uint32
*minor_status
,
1575 const gsskrb5_ctx ctx
,
1576 krb5_context context
,
1578 const gss_buffer_t message_buffer
,
1579 gss_buffer_t message_token
)
1581 gss_cfx_mic_token token
;
1582 krb5_error_code ret
;
1589 len
= message_buffer
->length
+ sizeof(*token
);
1592 *minor_status
= ENOMEM
;
1593 return GSS_S_FAILURE
;
1596 memcpy(buf
, message_buffer
->value
, message_buffer
->length
);
1598 token
= (gss_cfx_mic_token
)(buf
+ message_buffer
->length
);
1599 token
->TOK_ID
[0] = 0x04;
1600 token
->TOK_ID
[1] = 0x04;
1602 if ((ctx
->more_flags
& LOCAL
) == 0)
1603 token
->Flags
|= CFXSentByAcceptor
;
1604 if (ctx
->more_flags
& ACCEPTOR_SUBKEY
)
1605 token
->Flags
|= CFXAcceptorSubkey
;
1606 memset(token
->Filler
, 0xFF, 5);
1608 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
1609 krb5_auth_con_getlocalseqnumber(context
,
1612 _gsskrb5_encode_be_om_uint32(0, &token
->SND_SEQ
[0]);
1613 _gsskrb5_encode_be_om_uint32(seq_number
, &token
->SND_SEQ
[4]);
1614 krb5_auth_con_setlocalseqnumber(context
,
1617 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
1619 if (ctx
->more_flags
& LOCAL
) {
1620 usage
= KRB5_KU_USAGE_INITIATOR_SIGN
;
1622 usage
= KRB5_KU_USAGE_ACCEPTOR_SIGN
;
1625 ret
= krb5_create_checksum(context
, ctx
->crypto
,
1626 usage
, 0, buf
, len
, &cksum
);
1628 *minor_status
= ret
;
1630 return GSS_S_FAILURE
;
1633 /* Determine MIC length */
1634 message_token
->length
= sizeof(*token
) + cksum
.checksum
.length
;
1635 message_token
->value
= malloc(message_token
->length
);
1636 if (message_token
->value
== NULL
) {
1637 *minor_status
= ENOMEM
;
1638 free_Checksum(&cksum
);
1640 return GSS_S_FAILURE
;
1643 /* Token is { "header" | get_mic("header" | plaintext-data) } */
1644 memcpy(message_token
->value
, token
, sizeof(*token
));
1645 memcpy((u_char
*)message_token
->value
+ sizeof(*token
),
1646 cksum
.checksum
.data
, cksum
.checksum
.length
);
1648 free_Checksum(&cksum
);
1652 return GSS_S_COMPLETE
;
1655 OM_uint32
_gssapi_verify_mic_cfx(OM_uint32
*minor_status
,
1656 const gsskrb5_ctx ctx
,
1657 krb5_context context
,
1658 const gss_buffer_t message_buffer
,
1659 const gss_buffer_t token_buffer
,
1660 gss_qop_t
*qop_state
)
1662 gss_cfx_mic_token token
;
1664 krb5_error_code ret
;
1666 OM_uint32 seq_number_lo
, seq_number_hi
;
1672 if (token_buffer
->length
< sizeof(*token
)) {
1673 return GSS_S_DEFECTIVE_TOKEN
;
1676 p
= token_buffer
->value
;
1678 token
= (gss_cfx_mic_token
)p
;
1680 if (token
->TOK_ID
[0] != 0x04 || token
->TOK_ID
[1] != 0x04) {
1681 return GSS_S_DEFECTIVE_TOKEN
;
1684 /* Ignore unknown flags */
1685 token_flags
= token
->Flags
& (CFXSentByAcceptor
| CFXAcceptorSubkey
);
1687 if (token_flags
& CFXSentByAcceptor
) {
1688 if ((ctx
->more_flags
& LOCAL
) == 0)
1689 return GSS_S_DEFECTIVE_TOKEN
;
1691 if (ctx
->more_flags
& ACCEPTOR_SUBKEY
) {
1692 if ((token_flags
& CFXAcceptorSubkey
) == 0)
1693 return GSS_S_DEFECTIVE_TOKEN
;
1695 if (token_flags
& CFXAcceptorSubkey
)
1696 return GSS_S_DEFECTIVE_TOKEN
;
1699 if (ct_memcmp(token
->Filler
, "\xff\xff\xff\xff\xff", 5) != 0) {
1700 return GSS_S_DEFECTIVE_TOKEN
;
1704 * Check sequence number
1706 _gsskrb5_decode_be_om_uint32(&token
->SND_SEQ
[0], &seq_number_hi
);
1707 _gsskrb5_decode_be_om_uint32(&token
->SND_SEQ
[4], &seq_number_lo
);
1708 if (seq_number_hi
) {
1709 *minor_status
= ERANGE
;
1710 return GSS_S_UNSEQ_TOKEN
;
1713 HEIMDAL_MUTEX_lock(&ctx
->ctx_id_mutex
);
1714 ret
= _gssapi_msg_order_check(ctx
->order
, seq_number_lo
);
1717 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
1720 HEIMDAL_MUTEX_unlock(&ctx
->ctx_id_mutex
);
1725 ret
= krb5_crypto_get_checksum_type(context
, ctx
->crypto
,
1728 *minor_status
= ret
;
1729 return GSS_S_FAILURE
;
1732 cksum
.checksum
.data
= p
+ sizeof(*token
);
1733 cksum
.checksum
.length
= token_buffer
->length
- sizeof(*token
);
1735 if (ctx
->more_flags
& LOCAL
) {
1736 usage
= KRB5_KU_USAGE_ACCEPTOR_SIGN
;
1738 usage
= KRB5_KU_USAGE_INITIATOR_SIGN
;
1741 buf
= malloc(message_buffer
->length
+ sizeof(*token
));
1743 *minor_status
= ENOMEM
;
1744 return GSS_S_FAILURE
;
1746 memcpy(buf
, message_buffer
->value
, message_buffer
->length
);
1747 memcpy(buf
+ message_buffer
->length
, token
, sizeof(*token
));
1749 ret
= krb5_verify_checksum(context
, ctx
->crypto
,
1752 sizeof(*token
) + message_buffer
->length
,
1755 *minor_status
= ret
;
1757 return GSS_S_BAD_MIC
;
1762 if (qop_state
!= NULL
) {
1763 *qop_state
= GSS_C_QOP_DEFAULT
;
1766 return GSS_S_COMPLETE
;