2 * Copyright (c) 2003, PADL Software Pty Ltd.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
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.
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.
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
33 #include "gssapi_locl.h"
35 RCSID("$Id: cfx.c,v 1.19 2006/05/05 10:26:43 lha Exp $");
38 * Implementation of draft-ietf-krb-wg-gssapi-cfx-06.txt
41 #define CFXSentByAcceptor (1 << 0)
42 #define CFXSealed (1 << 1)
43 #define CFXAcceptorSubkey (1 << 2)
45 static krb5_error_code
46 wrap_length_cfx(krb5_crypto crypto
,
49 size_t *output_length
,
57 /* 16-byte header is always first */
58 *output_length
= sizeof(gss_cfx_wrap_token_desc
);
61 ret
= krb5_crypto_get_checksum_type(gssapi_krb5_context
, crypto
, &type
);
66 ret
= krb5_checksumsize(gssapi_krb5_context
, type
, cksumsize
);
73 /* Header is concatenated with data before encryption */
74 input_length
+= sizeof(gss_cfx_wrap_token_desc
);
76 ret
= krb5_crypto_getpadsize(gssapi_krb5_context
, crypto
, padsize
);
82 *padlength
= *padsize
- (input_length
% *padsize
);
85 /* We add the pad ourselves (noted here for completeness only) */
86 input_length
+= *padlength
;
88 *output_length
+= krb5_get_wrapped_length(gssapi_krb5_context
,
89 crypto
, input_length
);
91 /* Checksum is concatenated with data */
92 *output_length
+= input_length
+ *cksumsize
;
96 assert(*output_length
> input_length
);
101 OM_uint32
_gssapi_wrap_size_cfx(OM_uint32
*minor_status
,
102 const gss_ctx_id_t context_handle
,
105 OM_uint32 req_input_size
,
106 OM_uint32
*output_len
,
114 size_t output_length
, cksumsize
;
116 ret
= krb5_crypto_init(gssapi_krb5_context
, key
, 0, &crypto
);
118 gssapi_krb5_set_error_string();
120 return GSS_S_FAILURE
;
123 ret
= wrap_length_cfx(crypto
, conf_req_flag
,
125 &output_length
, &cksumsize
, &pad_length
, &pad_size
);
127 gssapi_krb5_set_error_string();
129 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
130 return GSS_S_FAILURE
;
133 *output_len
= output_length
;
136 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
138 return GSS_S_COMPLETE
;
142 * Rotate "rrc" bytes to the front or back
145 static krb5_error_code
146 rrc_rotate(void *data
, size_t len
, uint16_t rrc
, krb5_boolean unrotate
)
148 u_char
*tmp
, buf
[256];
161 if (rrc
<= sizeof(buf
)) {
170 memcpy(tmp
, data
, rrc
);
171 memmove(data
, (u_char
*)data
+ rrc
, left
);
172 memcpy((u_char
*)data
+ left
, tmp
, rrc
);
174 memcpy(tmp
, (u_char
*)data
+ left
, rrc
);
175 memmove((u_char
*)data
+ rrc
, data
, left
);
176 memcpy(data
, tmp
, rrc
);
179 if (rrc
> sizeof(buf
))
185 OM_uint32
_gssapi_wrap_cfx(OM_uint32
*minor_status
,
186 const gss_ctx_id_t context_handle
,
189 const gss_buffer_t input_message_buffer
,
191 gss_buffer_t output_message_buffer
,
195 gss_cfx_wrap_token token
;
199 size_t wrapped_len
, cksumsize
;
200 uint16_t padlength
, rrc
= 0;
205 ret
= krb5_crypto_init(gssapi_krb5_context
, key
, 0, &crypto
);
207 gssapi_krb5_set_error_string();
209 return GSS_S_FAILURE
;
212 ret
= wrap_length_cfx(crypto
, conf_req_flag
,
213 input_message_buffer
->length
,
214 &wrapped_len
, &cksumsize
, &padlength
, &padsize
);
216 gssapi_krb5_set_error_string();
218 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
219 return GSS_S_FAILURE
;
222 /* Always rotate encrypted token (if any) and checksum to header */
223 rrc
= (conf_req_flag
? sizeof(*token
) : 0) + (uint16_t)cksumsize
;
225 output_message_buffer
->length
= wrapped_len
;
226 output_message_buffer
->value
= malloc(output_message_buffer
->length
);
227 if (output_message_buffer
->value
== NULL
) {
228 *minor_status
= ENOMEM
;
229 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
230 return GSS_S_FAILURE
;
233 p
= output_message_buffer
->value
;
234 token
= (gss_cfx_wrap_token
)p
;
235 token
->TOK_ID
[0] = 0x05;
236 token
->TOK_ID
[1] = 0x04;
238 token
->Filler
= 0xFF;
239 if ((context_handle
->more_flags
& LOCAL
) == 0)
240 token
->Flags
|= CFXSentByAcceptor
;
241 if (context_handle
->more_flags
& ACCEPTOR_SUBKEY
)
242 token
->Flags
|= CFXAcceptorSubkey
;
245 * In Wrap tokens with confidentiality, the EC field is
246 * used to encode the size (in bytes) of the random filler.
248 token
->Flags
|= CFXSealed
;
249 token
->EC
[0] = (padlength
>> 8) & 0xFF;
250 token
->EC
[1] = (padlength
>> 0) & 0xFF;
253 * In Wrap tokens without confidentiality, the EC field is
254 * used to encode the size (in bytes) of the trailing
257 * This is not used in the checksum calcuation itself,
258 * because the checksum length could potentially vary
259 * depending on the data length.
266 * In Wrap tokens that provide for confidentiality, the RRC
267 * field in the header contains the hex value 00 00 before
270 * In Wrap tokens that do not provide for confidentiality,
271 * both the EC and RRC fields in the appended checksum
272 * contain the hex value 00 00 for the purpose of calculating
278 HEIMDAL_MUTEX_lock(&context_handle
->ctx_id_mutex
);
279 krb5_auth_con_getlocalseqnumber(gssapi_krb5_context
,
280 context_handle
->auth_context
,
282 gssapi_encode_be_om_uint32(0, &token
->SND_SEQ
[0]);
283 gssapi_encode_be_om_uint32(seq_number
, &token
->SND_SEQ
[4]);
284 krb5_auth_con_setlocalseqnumber(gssapi_krb5_context
,
285 context_handle
->auth_context
,
287 HEIMDAL_MUTEX_unlock(&context_handle
->ctx_id_mutex
);
290 * If confidentiality is requested, the token header is
291 * appended to the plaintext before encryption; the resulting
292 * token is {"header" | encrypt(plaintext | pad | "header")}.
294 * If no confidentiality is requested, the checksum is
295 * calculated over the plaintext concatenated with the
298 if (context_handle
->more_flags
& LOCAL
) {
299 usage
= KRB5_KU_USAGE_INITIATOR_SEAL
;
301 usage
= KRB5_KU_USAGE_ACCEPTOR_SEAL
;
306 * Any necessary padding is added here to ensure that the
307 * encrypted token header is always at the end of the
310 * The specification does not require that the padding
311 * bytes are initialized.
314 memcpy(p
, input_message_buffer
->value
, input_message_buffer
->length
);
315 memset(p
+ input_message_buffer
->length
, 0xFF, padlength
);
316 memcpy(p
+ input_message_buffer
->length
+ padlength
,
317 token
, sizeof(*token
));
319 ret
= krb5_encrypt(gssapi_krb5_context
, crypto
,
321 input_message_buffer
->length
+ padlength
+
325 gssapi_krb5_set_error_string();
327 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
328 gss_release_buffer(minor_status
, output_message_buffer
);
329 return GSS_S_FAILURE
;
331 assert(sizeof(*token
) + cipher
.length
== wrapped_len
);
332 token
->RRC
[0] = (rrc
>> 8) & 0xFF;
333 token
->RRC
[1] = (rrc
>> 0) & 0xFF;
335 ret
= rrc_rotate(cipher
.data
, cipher
.length
, rrc
, FALSE
);
337 gssapi_krb5_set_error_string();
339 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
340 gss_release_buffer(minor_status
, output_message_buffer
);
341 return GSS_S_FAILURE
;
343 memcpy(p
, cipher
.data
, cipher
.length
);
344 krb5_data_free(&cipher
);
349 buf
= malloc(input_message_buffer
->length
+ sizeof(*token
));
351 *minor_status
= ENOMEM
;
352 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
353 gss_release_buffer(minor_status
, output_message_buffer
);
354 return GSS_S_FAILURE
;
356 memcpy(buf
, input_message_buffer
->value
, input_message_buffer
->length
);
357 memcpy(buf
+ input_message_buffer
->length
, token
, sizeof(*token
));
359 ret
= krb5_create_checksum(gssapi_krb5_context
, crypto
,
361 input_message_buffer
->length
+
365 gssapi_krb5_set_error_string();
367 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
368 gss_release_buffer(minor_status
, output_message_buffer
);
370 return GSS_S_FAILURE
;
375 assert(cksum
.checksum
.length
== cksumsize
);
376 token
->EC
[0] = (cksum
.checksum
.length
>> 8) & 0xFF;
377 token
->EC
[1] = (cksum
.checksum
.length
>> 0) & 0xFF;
378 token
->RRC
[0] = (rrc
>> 8) & 0xFF;
379 token
->RRC
[1] = (rrc
>> 0) & 0xFF;
382 memcpy(p
, input_message_buffer
->value
, input_message_buffer
->length
);
383 memcpy(p
+ input_message_buffer
->length
,
384 cksum
.checksum
.data
, cksum
.checksum
.length
);
387 input_message_buffer
->length
+ cksum
.checksum
.length
, rrc
, FALSE
);
389 gssapi_krb5_set_error_string();
391 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
392 gss_release_buffer(minor_status
, output_message_buffer
);
393 free_Checksum(&cksum
);
394 return GSS_S_FAILURE
;
396 free_Checksum(&cksum
);
399 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
401 if (conf_state
!= NULL
) {
402 *conf_state
= conf_req_flag
;
406 return GSS_S_COMPLETE
;
409 OM_uint32
_gssapi_unwrap_cfx(OM_uint32
*minor_status
,
410 const gss_ctx_id_t context_handle
,
411 const gss_buffer_t input_message_buffer
,
412 gss_buffer_t output_message_buffer
,
414 gss_qop_t
*qop_state
,
418 gss_cfx_wrap_token token
;
424 OM_uint32 seq_number_lo
, seq_number_hi
;
430 if (input_message_buffer
->length
< sizeof(*token
)) {
431 return GSS_S_DEFECTIVE_TOKEN
;
434 p
= input_message_buffer
->value
;
436 token
= (gss_cfx_wrap_token
)p
;
438 if (token
->TOK_ID
[0] != 0x05 || token
->TOK_ID
[1] != 0x04) {
439 return GSS_S_DEFECTIVE_TOKEN
;
442 /* Ignore unknown flags */
443 token_flags
= token
->Flags
&
444 (CFXSentByAcceptor
| CFXSealed
| CFXAcceptorSubkey
);
446 if (token_flags
& CFXSentByAcceptor
) {
447 if ((context_handle
->more_flags
& LOCAL
) == 0)
448 return GSS_S_DEFECTIVE_TOKEN
;
451 if (context_handle
->more_flags
& ACCEPTOR_SUBKEY
) {
452 if ((token_flags
& CFXAcceptorSubkey
) == 0)
453 return GSS_S_DEFECTIVE_TOKEN
;
455 if (token_flags
& CFXAcceptorSubkey
)
456 return GSS_S_DEFECTIVE_TOKEN
;
459 if (token
->Filler
!= 0xFF) {
460 return GSS_S_DEFECTIVE_TOKEN
;
463 if (conf_state
!= NULL
) {
464 *conf_state
= (token_flags
& CFXSealed
) ? 1 : 0;
467 ec
= (token
->EC
[0] << 8) | token
->EC
[1];
468 rrc
= (token
->RRC
[0] << 8) | token
->RRC
[1];
471 * Check sequence number
473 gssapi_decode_be_om_uint32(&token
->SND_SEQ
[0], &seq_number_hi
);
474 gssapi_decode_be_om_uint32(&token
->SND_SEQ
[4], &seq_number_lo
);
476 /* no support for 64-bit sequence numbers */
477 *minor_status
= ERANGE
;
478 return GSS_S_UNSEQ_TOKEN
;
481 HEIMDAL_MUTEX_lock(&context_handle
->ctx_id_mutex
);
482 ret
= _gssapi_msg_order_check(context_handle
->order
, seq_number_lo
);
485 HEIMDAL_MUTEX_unlock(&context_handle
->ctx_id_mutex
);
486 gss_release_buffer(minor_status
, output_message_buffer
);
489 HEIMDAL_MUTEX_unlock(&context_handle
->ctx_id_mutex
);
492 * Decrypt and/or verify checksum
494 ret
= krb5_crypto_init(gssapi_krb5_context
, key
, 0, &crypto
);
496 gssapi_krb5_set_error_string();
498 return GSS_S_FAILURE
;
501 if (context_handle
->more_flags
& LOCAL
) {
502 usage
= KRB5_KU_USAGE_ACCEPTOR_SEAL
;
504 usage
= KRB5_KU_USAGE_INITIATOR_SEAL
;
508 len
= input_message_buffer
->length
;
509 len
-= (p
- (u_char
*)input_message_buffer
->value
);
511 /* Rotate by RRC; bogus to do this in-place XXX */
512 *minor_status
= rrc_rotate(p
, len
, rrc
, TRUE
);
513 if (*minor_status
!= 0) {
514 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
515 return GSS_S_FAILURE
;
518 if (token_flags
& CFXSealed
) {
519 ret
= krb5_decrypt(gssapi_krb5_context
, crypto
, usage
,
522 gssapi_krb5_set_error_string();
524 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
525 return GSS_S_BAD_MIC
;
528 /* Check that there is room for the pad and token header */
529 if (data
.length
< ec
+ sizeof(*token
)) {
530 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
531 krb5_data_free(&data
);
532 return GSS_S_DEFECTIVE_TOKEN
;
535 p
+= data
.length
- sizeof(*token
);
537 /* RRC is unprotected; don't modify input buffer */
538 ((gss_cfx_wrap_token
)p
)->RRC
[0] = token
->RRC
[0];
539 ((gss_cfx_wrap_token
)p
)->RRC
[1] = token
->RRC
[1];
541 /* Check the integrity of the header */
542 if (memcmp(p
, token
, sizeof(*token
)) != 0) {
543 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
544 krb5_data_free(&data
);
545 return GSS_S_BAD_MIC
;
548 output_message_buffer
->value
= data
.data
;
549 output_message_buffer
->length
= data
.length
- ec
- sizeof(*token
);
553 /* Determine checksum type */
554 ret
= krb5_crypto_get_checksum_type(gssapi_krb5_context
,
555 crypto
, &cksum
.cksumtype
);
557 gssapi_krb5_set_error_string();
559 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
560 return GSS_S_FAILURE
;
563 cksum
.checksum
.length
= ec
;
565 /* Check we have at least as much data as the checksum */
566 if (len
< cksum
.checksum
.length
) {
567 *minor_status
= ERANGE
;
568 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
569 return GSS_S_BAD_MIC
;
572 /* Length now is of the plaintext only, no checksum */
573 len
-= cksum
.checksum
.length
;
574 cksum
.checksum
.data
= p
+ len
;
576 output_message_buffer
->length
= len
; /* for later */
577 output_message_buffer
->value
= malloc(len
+ sizeof(*token
));
578 if (output_message_buffer
->value
== NULL
) {
579 *minor_status
= ENOMEM
;
580 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
581 return GSS_S_FAILURE
;
584 /* Checksum is over (plaintext-data | "header") */
585 memcpy(output_message_buffer
->value
, p
, len
);
586 memcpy((u_char
*)output_message_buffer
->value
+ len
,
587 token
, sizeof(*token
));
589 /* EC is not included in checksum calculation */
590 token
= (gss_cfx_wrap_token
)((u_char
*)output_message_buffer
->value
+
597 ret
= krb5_verify_checksum(gssapi_krb5_context
, crypto
,
599 output_message_buffer
->value
,
600 len
+ sizeof(*token
),
603 gssapi_krb5_set_error_string();
605 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
606 gss_release_buffer(minor_status
, output_message_buffer
);
607 return GSS_S_BAD_MIC
;
611 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
613 if (qop_state
!= NULL
) {
614 *qop_state
= GSS_C_QOP_DEFAULT
;
618 return GSS_S_COMPLETE
;
621 OM_uint32
_gssapi_mic_cfx(OM_uint32
*minor_status
,
622 const gss_ctx_id_t context_handle
,
624 const gss_buffer_t message_buffer
,
625 gss_buffer_t message_token
,
629 gss_cfx_mic_token token
;
637 ret
= krb5_crypto_init(gssapi_krb5_context
, key
, 0, &crypto
);
639 gssapi_krb5_set_error_string();
641 return GSS_S_FAILURE
;
644 len
= message_buffer
->length
+ sizeof(*token
);
647 *minor_status
= ENOMEM
;
648 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
649 return GSS_S_FAILURE
;
652 memcpy(buf
, message_buffer
->value
, message_buffer
->length
);
654 token
= (gss_cfx_mic_token
)(buf
+ message_buffer
->length
);
655 token
->TOK_ID
[0] = 0x04;
656 token
->TOK_ID
[1] = 0x04;
658 if ((context_handle
->more_flags
& LOCAL
) == 0)
659 token
->Flags
|= CFXSentByAcceptor
;
660 if (context_handle
->more_flags
& ACCEPTOR_SUBKEY
)
661 token
->Flags
|= CFXAcceptorSubkey
;
662 memset(token
->Filler
, 0xFF, 5);
664 HEIMDAL_MUTEX_lock(&context_handle
->ctx_id_mutex
);
665 krb5_auth_con_getlocalseqnumber(gssapi_krb5_context
,
666 context_handle
->auth_context
,
668 gssapi_encode_be_om_uint32(0, &token
->SND_SEQ
[0]);
669 gssapi_encode_be_om_uint32(seq_number
, &token
->SND_SEQ
[4]);
670 krb5_auth_con_setlocalseqnumber(gssapi_krb5_context
,
671 context_handle
->auth_context
,
673 HEIMDAL_MUTEX_unlock(&context_handle
->ctx_id_mutex
);
675 if (context_handle
->more_flags
& LOCAL
) {
676 usage
= KRB5_KU_USAGE_INITIATOR_SIGN
;
678 usage
= KRB5_KU_USAGE_ACCEPTOR_SIGN
;
681 ret
= krb5_create_checksum(gssapi_krb5_context
, crypto
,
682 usage
, 0, buf
, len
, &cksum
);
684 gssapi_krb5_set_error_string();
686 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
688 return GSS_S_FAILURE
;
690 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
692 /* Determine MIC length */
693 message_token
->length
= sizeof(*token
) + cksum
.checksum
.length
;
694 message_token
->value
= malloc(message_token
->length
);
695 if (message_token
->value
== NULL
) {
696 *minor_status
= ENOMEM
;
697 free_Checksum(&cksum
);
699 return GSS_S_FAILURE
;
702 /* Token is { "header" | get_mic("header" | plaintext-data) } */
703 memcpy(message_token
->value
, token
, sizeof(*token
));
704 memcpy((u_char
*)message_token
->value
+ sizeof(*token
),
705 cksum
.checksum
.data
, cksum
.checksum
.length
);
707 free_Checksum(&cksum
);
711 return GSS_S_COMPLETE
;
714 OM_uint32
_gssapi_verify_mic_cfx(OM_uint32
*minor_status
,
715 const gss_ctx_id_t context_handle
,
716 const gss_buffer_t message_buffer
,
717 const gss_buffer_t token_buffer
,
718 gss_qop_t
*qop_state
,
722 gss_cfx_mic_token token
;
726 OM_uint32 seq_number_lo
, seq_number_hi
;
732 if (token_buffer
->length
< sizeof(*token
)) {
733 return GSS_S_DEFECTIVE_TOKEN
;
736 p
= token_buffer
->value
;
738 token
= (gss_cfx_mic_token
)p
;
740 if (token
->TOK_ID
[0] != 0x04 || token
->TOK_ID
[1] != 0x04) {
741 return GSS_S_DEFECTIVE_TOKEN
;
744 /* Ignore unknown flags */
745 token_flags
= token
->Flags
& (CFXSentByAcceptor
| CFXAcceptorSubkey
);
747 if (token_flags
& CFXSentByAcceptor
) {
748 if ((context_handle
->more_flags
& LOCAL
) == 0)
749 return GSS_S_DEFECTIVE_TOKEN
;
751 if (context_handle
->more_flags
& ACCEPTOR_SUBKEY
) {
752 if ((token_flags
& CFXAcceptorSubkey
) == 0)
753 return GSS_S_DEFECTIVE_TOKEN
;
755 if (token_flags
& CFXAcceptorSubkey
)
756 return GSS_S_DEFECTIVE_TOKEN
;
759 if (memcmp(token
->Filler
, "\xff\xff\xff\xff\xff", 5) != 0) {
760 return GSS_S_DEFECTIVE_TOKEN
;
764 * Check sequence number
766 gssapi_decode_be_om_uint32(&token
->SND_SEQ
[0], &seq_number_hi
);
767 gssapi_decode_be_om_uint32(&token
->SND_SEQ
[4], &seq_number_lo
);
769 *minor_status
= ERANGE
;
770 return GSS_S_UNSEQ_TOKEN
;
773 HEIMDAL_MUTEX_lock(&context_handle
->ctx_id_mutex
);
774 ret
= _gssapi_msg_order_check(context_handle
->order
, seq_number_lo
);
777 HEIMDAL_MUTEX_unlock(&context_handle
->ctx_id_mutex
);
780 HEIMDAL_MUTEX_unlock(&context_handle
->ctx_id_mutex
);
785 ret
= krb5_crypto_init(gssapi_krb5_context
, key
, 0, &crypto
);
787 gssapi_krb5_set_error_string();
789 return GSS_S_FAILURE
;
792 ret
= krb5_crypto_get_checksum_type(gssapi_krb5_context
, crypto
,
795 gssapi_krb5_set_error_string();
797 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
798 return GSS_S_FAILURE
;
801 cksum
.checksum
.data
= p
+ sizeof(*token
);
802 cksum
.checksum
.length
= token_buffer
->length
- sizeof(*token
);
804 if (context_handle
->more_flags
& LOCAL
) {
805 usage
= KRB5_KU_USAGE_ACCEPTOR_SIGN
;
807 usage
= KRB5_KU_USAGE_INITIATOR_SIGN
;
810 buf
= malloc(message_buffer
->length
+ sizeof(*token
));
812 *minor_status
= ENOMEM
;
813 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
814 return GSS_S_FAILURE
;
816 memcpy(buf
, message_buffer
->value
, message_buffer
->length
);
817 memcpy(buf
+ message_buffer
->length
, token
, sizeof(*token
));
819 ret
= krb5_verify_checksum(gssapi_krb5_context
, crypto
,
822 sizeof(*token
) + message_buffer
->length
,
825 gssapi_krb5_set_error_string();
827 krb5_crypto_destroy(gssapi_krb5_context
, crypto
);
829 return GSS_S_BAD_MIC
;
834 if (qop_state
!= NULL
) {
835 *qop_state
= GSS_C_QOP_DEFAULT
;
838 return GSS_S_COMPLETE
;