From 7c691b1d90425e72bbafb22917990bcb68fc0b31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Love=20H=C3=B6rnquist=20=C3=85strand?= Date: Thu, 28 Aug 2003 00:04:59 +0000 Subject: [PATCH] implement wrap/unwarp git-svn-id: svn://svn.h5l.se/heimdal/trunk/heimdal@12670 ec53bebd-3082-4978-b11e-865c3cabbd6b --- lib/gssapi/arcfour.c | 591 ++++++++++++++++++++------------------ lib/gssapi/krb5/arcfour.c | 591 ++++++++++++++++++++------------------ 2 files changed, 628 insertions(+), 554 deletions(-) diff --git a/lib/gssapi/arcfour.c b/lib/gssapi/arcfour.c index 38ff80b27..c51bee393 100644 --- a/lib/gssapi/arcfour.c +++ b/lib/gssapi/arcfour.c @@ -33,28 +33,14 @@ #include "gssapi_locl.h" -#if 0 -static const char arcfour_sk[] = "signaturekey"; +/* + * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt + */ -static krb5_error_code -get_arcfour_sk(krb5_context context, krb5_keyblock *key, - void *sk_key_data, size_t sk_key_size) -{ - Checksum cksum_k4; - - cksum_k4.checksum.data = sk_key_data; - cksum_k4.checksum.length = sk_key_size; - return krb5_hmac(context, CKSUMTYPE_RSA_MD5, - arcfour_sk, sizeof(arcfour_sk), 13, /* XXX usage */ - key, &cksum_k4); - -} -#endif +RCSID("$Id$"); static krb5_error_code arcfour_mic_key(krb5_context context, krb5_keyblock *key, - const void *header, size_t header_size, - const void *message, size_t message_size, void *cksum_data, size_t cksum_size, void *key6_data, size_t key6_size) { @@ -68,9 +54,7 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key, char T[4]; - /* draft: T = 0; */ memset(T, 0, 4); - /* draft: HMAC (K, &T, 4, K5); */ cksum_k5.checksum.data = k5_data; cksum_k5.checksum.length = sizeof(k5_data); @@ -82,7 +66,6 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key, key5.keytype = KEYTYPE_ARCFOUR; key5.keyvalue = cksum_k5.checksum; - /* HMAC(K5, MIC_checksum, 8, K6); */ cksum_k6.checksum.data = key6_data; cksum_k6.checksum.length = key6_size; @@ -90,22 +73,31 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key, cksum_data, cksum_size, 0, &key5, &cksum_k6); } -static krb5_error_code -arcfour_mic_cksum(const char *p, size_t p_sz, - const gss_buffer_t message_buffer, - krb5_keyblock *key, - u_char *sgn_cksum, size_t sgn_cksum_sz) +static krb5_error_code +arcfour_mic_cksum(krb5_keyblock *key, + u_char *sgn_cksum, size_t sgn_cksum_sz, + const char *v1, size_t l1, + const void *v2, size_t l2, + const void *v3, size_t l3) { Checksum CKSUM; - u_char *ptr = emalloc(p_sz + message_buffer->length); + u_char *ptr; + size_t len; krb5_crypto crypto; krb5_error_code ret; assert(sgn_cksum_sz == 8); - memcpy(ptr, p, p_sz); - memcpy(ptr + p_sz, message_buffer->value, message_buffer->length); + len = l1 + l2 + l3; + + ptr = malloc(len); + if (ptr == NULL) + return ENOMEM; + + memcpy(ptr, v1, l1); + memcpy(ptr + l1, v2, l2); + memcpy(ptr + l1 + l2, v3, l3); ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto); if (ret) { @@ -114,12 +106,11 @@ arcfour_mic_cksum(const char *p, size_t p_sz, } ret = krb5_create_checksum(gssapi_krb5_context, - crypto, - KRB5_KU_USAGE_SIGN, - 0, - ptr, - p_sz + message_buffer->length, - &CKSUM); + crypto, + KRB5_KU_USAGE_SIGN, + 0, + ptr, len, + &CKSUM); free(ptr); if (ret == 0) { memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz); @@ -132,24 +123,18 @@ arcfour_mic_cksum(const char *p, size_t p_sz, OM_uint32 -_gssapi_get_mic_arcfour - (OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, - gss_qop_t qop_req, - const gss_buffer_t message_buffer, - gss_buffer_t message_token, - krb5_keyblock *key - ) +_gssapi_get_mic_arcfour(OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key) { gss_arcfour_mic_token *token; - krb5_error_code kret; - - u_char *p; - + krb5_error_code ret; int32_t seq_number; size_t len, total_len; - - char k6_data[16]; + u_char k6_data[16], *p; gssapi_krb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM); @@ -174,19 +159,21 @@ _gssapi_get_mic_arcfour token->Filler[2] = 0xff; token->Filler[3] = 0xff; - kret = arcfour_mic_cksum(p, 8, message_buffer, key, token->SGN_CKSUM, 8); - if (kret) { - *minor_status = kret; + ret = arcfour_mic_cksum(key, token->SGN_CKSUM, 8, + p, 8, + message_buffer->value, message_buffer->length, + NULL, 0); + if (ret) { gss_release_buffer(minor_status, message_token); + *minor_status = ret; return GSS_S_FAILURE; } - kret = arcfour_mic_key(gssapi_krb5_context, key, - p, 8, - message_buffer->value,message_buffer->length, - token->SGN_CKSUM, 8, - k6_data, sizeof(k6_data)); - if (kret) { - *minor_status = kret; + ret = arcfour_mic_key(gssapi_krb5_context, key, + token->SGN_CKSUM, 8, + k6_data, sizeof(k6_data)); + if (ret) { + gss_release_buffer(minor_status, message_token); + *minor_status = ret; return GSS_S_FAILURE; } p += 8; @@ -198,11 +185,8 @@ _gssapi_get_mic_arcfour krb5_auth_con_getlocalseqnumber (gssapi_krb5_context, context_handle->auth_context, &seq_number); - - p[0] = (seq_number >> 24) & 0xFF; - p[1] = (seq_number >> 16) & 0xFF; - p[2] = (seq_number >> 8) & 0xFF; - p[3] = (seq_number >> 0) & 0xFF; + + gssapi_encode_be_om_uint32(seq_number, p); krb5_auth_con_setlocalseqnumber (gssapi_krb5_context, context_handle->auth_context, @@ -221,6 +205,7 @@ _gssapi_get_mic_arcfour RC4 (&rc4_key, 8, p, p); memset(&rc4_key, 0, sizeof(rc4_key)); + memset(k6_data, 0, sizeof(k6_data)); } return GSS_S_COMPLETE; @@ -228,30 +213,28 @@ _gssapi_get_mic_arcfour OM_uint32 -_gssapi_verify_mic_arcfour - (OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, - const gss_buffer_t message_buffer, - const gss_buffer_t token_buffer, - gss_qop_t * qop_state, - char *type, - krb5_keyblock *key - ) +_gssapi_verify_mic_arcfour(OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + char *type, + krb5_keyblock *key) { - krb5_error_code kret; + krb5_error_code ret; int32_t seq_number; - OM_uint32 ret; - char cksum_data[8], k6_data[16]; + OM_uint32 omret; + char cksum_data[8], k6_data[16], SND_SEQ[8]; u_char *p; int cmp; p = token_buffer->value; - ret = gssapi_krb5_verify_header (&p, - token_buffer->length, - type, - GSS_KRB5_MECHANISM); - if (ret) - return ret; + omret = gssapi_krb5_verify_header (&p, + token_buffer->length, + type, + GSS_KRB5_MECHANISM); + if (omret) + return omret; if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ return GSS_S_BAD_SIG; @@ -260,24 +243,20 @@ _gssapi_verify_mic_arcfour return GSS_S_BAD_MIC; p += 4; - /* draft: memcpy (T_plus_hdr_plus_msg + 04, MIC_hdr, 8); */ - /* draft: memcpy (T_plus_hdr_plus_msg + 12, msg, msg_len); */ - - kret = arcfour_mic_cksum(p - 8, 8, message_buffer, key, - cksum_data, sizeof(cksum_data)); - if (kret) { - *minor_status = kret; + ret = arcfour_mic_cksum(key, cksum_data, sizeof(cksum_data), + p - 8, 8, + message_buffer->value, message_buffer->length, + NULL, 0); + if (ret) { + *minor_status = ret; return GSS_S_FAILURE; } - kret = arcfour_mic_key(gssapi_krb5_context, key, - p - 8, 8, - message_buffer->value, - message_buffer->length, - cksum_data, sizeof(cksum_data), - k6_data, sizeof(k6_data)); - if (kret) { - *minor_status = kret; + ret = arcfour_mic_key(gssapi_krb5_context, key, + cksum_data, sizeof(cksum_data), + k6_data, sizeof(k6_data)); + if (ret) { + *minor_status = ret; return GSS_S_FAILURE; } @@ -287,77 +266,56 @@ _gssapi_verify_mic_arcfour return GSS_S_BAD_MIC; } - /* XXX don't modify p */ { RC4_KEY rc4_key; RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); - RC4 (&rc4_key, 8, p, p); + RC4 (&rc4_key, 8, p, SND_SEQ); memset(&rc4_key, 0, sizeof(rc4_key)); + memset(k6_data, 0, sizeof(k6_data)); } - gssapi_decode_om_uint32(p, &seq_number); + gssapi_decode_be_om_uint32(SND_SEQ, &seq_number); if (context_handle->more_flags & LOCAL) - cmp = memcmp(&p[4], "\x00\x00\x00\x00", 4); + cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); else - cmp = memcmp(&p[4], "\xff\xff\xff\xff", 4); - + cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); + + memset(SND_SEQ, 0, sizeof(SND_SEQ)); if (cmp != 0) { *minor_status = 0; return GSS_S_BAD_MIC; } HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - ret = gssapi_msg_order_check(context_handle->order, seq_number); + omret = gssapi_msg_order_check(context_handle->order, seq_number); HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - if (ret) - return ret; + if (omret) + return omret; - return 0; + return GSS_S_COMPLETE; } OM_uint32 -_gssapi_wrap_arcfour - (OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, - int conf_req_flag, - gss_qop_t qop_req, - const gss_buffer_t input_message_buffer, - int * conf_state, - gss_buffer_t output_message_buffer, - krb5_keyblock *key - ) +_gssapi_wrap_arcfour(OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int * conf_state, + gss_buffer_t output_message_buffer, + krb5_keyblock *key) { -#if 0 - u_char *p; - OM_uint32 ret; - int32_t seq_number; + u_char Klocaldata[16], k6_data[16], *p; size_t len, total_len, datalen; gss_arcfour_wrap_token *token; + krb5_keyblock Klocal; + krb5_error_code ret; + int32_t seq_number; - krb5_keyblock key7; - char k7_data[16]; - - Checksum cksum_k8; - krb5_keyblock key8; - char k8_data[16]; - - Checksum cksum_k9; - krb5_keyblock key9; - char k9_data[16]; - - krb5_keyblock key10; - char k10_data[16]; - - Checksum cksum_k11; - char k11_data[16]; - - Checksum CKSUM; - char cksum_data[16]; - - datalen = input_message_buffer->length; + datalen = input_message_buffer->length + 1 /* padding */; len = datalen + 30; gssapi_krb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); @@ -368,12 +326,13 @@ _gssapi_wrap_arcfour return GSS_S_FAILURE; } - p = gssapi_krb5_make_header(output_message_buffer->value, - len, - "\x02\x01", /* TOK_ID */ - GSS_KRB5_MECHANISM); + p = _gssapi_make_mech_header(output_message_buffer->value, + len, + GSS_KRB5_MECHANISM); token = (gss_arcfour_wrap_token *)p; + token->TOK_ID[0] = 0x02; + token->TOK_ID[1] = 0x01; token->SGN_ALG[0] = 0x11; token->SGN_ALG[1] = 0x00; if (conf_req_flag) { @@ -386,160 +345,94 @@ _gssapi_wrap_arcfour token->Filler[0] = 0xff; token->Filler[1] = 0xff; - memset(p + 8, 0, 16); /* XXX SND_SEQ, SGN_CKSUM */ - /* Confounder */ - krb5_generate_random_block(p + 16, 8); - - ret = get_arcfour_sk(gssapi_krb5_context, key, k7_data, sizeof(k7_data)); - if (ret) { - gss_release_buffer(minor_status, output_message_buffer); - return ret; - } - - key7.keytype = KEYTYPE_ARCFOUR; - key7.keyvalue.length = sizeof(k7_data); - key7.keyvalue.data = k7_data; - - { - u_char T[4]; - MD5_CTX md5; - u_char hash[16]; - - T[0] = 13; - T[1] = 0; - T[2] = 0; - T[3] = 0; - - MD5_Init(&md5); - MD5_Update(&md5, T, 4); /* T */ - MD5_Update(&md5, p - 8, 8); /* Token.Header */ - MD5_Update(&md5, p + 16, 8); /* Confounder */ - MD5_Update(&md5, - input_message_buffer->value, input_message_buffer->length); - MD5_Final(hash, &md5); - - CKSUM.checksum.data = cksum_data; - CKSUM.checksum.length = sizeof(cksum_data); - - /* draft: HMAC (K7, MD5_of_T_hdr_msg, CHKSUM); */ - ret = krb5_hmac(gssapi_krb5_context, CKSUMTYPE_RSA_MD5, - hash, sizeof(hash), - 0 /* XXX */, &key7, &CKSUM); - if (ret) { - gss_release_buffer(minor_status, output_message_buffer); - return ret; - } - } - - { - u_char T[4]; - - memset(T, 0, sizeof(T)); - cksum_k8.checksum.data = k8_data; - cksum_k8.checksum.length = sizeof(k8_data); - - ret = krb5_hmac(gssapi_krb5_context, CKSUMTYPE_RSA_MD5, - T, sizeof(T), 4 /* XXX */, key, &cksum_k8); - if (ret) { - gss_release_buffer(minor_status, output_message_buffer); - return ret; - } - } - - cksum_k9.checksum.data = k9_data; - cksum_k9.checksum.length = sizeof(k9_data); - - key8.keytype = KEYTYPE_ARCFOUR; - key8.keyvalue.length = sizeof(k8_data); - key8.keyvalue.data = k8_data; - - ret = krb5_hmac(gssapi_krb5_context, CKSUMTYPE_RSA_MD5, - cksum_data, sizeof(cksum_data), - 8 /* XXX */, &key8, &cksum_k9); - if (ret) { - gss_release_buffer(minor_status, output_message_buffer); - return ret; - } - - key9.keytype = KEYTYPE_ARCFOUR; - key9.keyvalue.length = sizeof(k9_data); - key9.keyvalue.data = k9_data; + /* skip to SND_SEQ */ + p += 8; HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); krb5_auth_con_getlocalseqnumber (gssapi_krb5_context, context_handle->auth_context, &seq_number); - p[0] = (seq_number >> 0) & 0xFF; - p[1] = (seq_number >> 8) & 0xFF; - p[2] = (seq_number >> 16) & 0xFF; - p[3] = (seq_number >> 24) & 0xFF; - + gssapi_encode_be_om_uint32(seq_number, p); + krb5_auth_con_setlocalseqnumber (gssapi_krb5_context, context_handle->auth_context, ++seq_number); HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); - memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xFF, 4); + memset (p + 4, + (context_handle->more_flags & LOCAL) ? 0xFF : 0, + 4); - { - RC4_KEY rc4_key; - - RC4_set_key (&rc4_key, sizeof(k9_data), k9_data); - RC4 (&rc4_key, 8, p, p); - - memset(&rc4_key, 0, sizeof(rc4_key)); + /* Confounder */ + krb5_generate_random_block(token->Confounder, sizeof(token->Confounder)); + + ret = arcfour_mic_cksum(key, token->SGN_CKSUM, 8, + p - 8, 8, + token->Confounder, sizeof(token->Confounder), + input_message_buffer->value, + input_message_buffer->length); + if (ret) { + *minor_status = ret; + gss_release_buffer(minor_status, input_message_buffer); + return GSS_S_FAILURE; } - p += 8; - memcpy(p, cksum_data, 8); - - key10.keytype = KEYTYPE_ARCFOUR; - key10.keyvalue.length = sizeof(k10_data); - key10.keyvalue.data = k10_data; - - assert(key->keyvalue.length == 16); { int i; - memcpy(k10_data, key->keyvalue.data, sizeof(k10_data)); - for (i = 0; i < sizeof(k10_data); i++) - k10_data[i] ^= 0xF0; + + Klocal.keytype = KEYTYPE_ARCFOUR; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + ret = arcfour_mic_key(gssapi_krb5_context, &Klocal, + p, 4, + k6_data, sizeof(k6_data)); + memset(Klocaldata, 0, sizeof(Klocaldata)); + if (ret) { + gss_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + return GSS_S_FAILURE; + } + + p += 24; /* skip SND_SEQ, SGN_CKSUM, and Confounder */ + + memcpy(p, input_message_buffer->value, input_message_buffer->length); + p[input_message_buffer->length] = 0; /* PADDING */ + + if(conf_req_flag) { + RC4_KEY rc4_key; + + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + /* XXX ? */ + RC4 (&rc4_key, 8 + datalen, token->Confounder, token->Confounder); + memset(&rc4_key, 0, sizeof(rc4_key)); + } + memset(k6_data, 0, sizeof(k6_data)); + + ret = arcfour_mic_key(gssapi_krb5_context, key, + token->SGN_CKSUM, 8, + k6_data, sizeof(k6_data)); + if (ret) { + gss_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + return GSS_S_FAILURE; } { - u_char T[4]; - - memset(T, 0, sizeof(T)); - cksum_k11.checksum.data = k11_data; - cksum_k11.checksum.length = sizeof(k11_data); - - ret = krb5_hmac(gssapi_krb5_context, CKSUMTYPE_RSA_MD5, - T, sizeof(T), 4 /* XXX */, &key10, &cksum_k11); - if (ret) { - gss_release_buffer(minor_status, output_message_buffer); - return ret; - } - } - - memcpy(p + 8, input_message_buffer->value, - input_message_buffer->length); - p[8 + input_message_buffer->length] = 1; - - if (conf_req_flag) { RC4_KEY rc4_key; - RC4_set_key (&rc4_key, sizeof(k11_data), k11_data); - - RC4 (&rc4_key, 8 + input_message_buffer->length, p, p); + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + RC4 (&rc4_key, 8, token->SND_SEQ, token->SND_SEQ); memset(&rc4_key, 0, sizeof(rc4_key)); + memset(k6_data, 0, sizeof(k6_data)); } - + *minor_status = 0; return GSS_S_COMPLETE; -#else - *minor_status = (OM_uint32)KRB5_PROG_ETYPE_NOSUPP; - return GSS_S_FAILURE; -#endif } OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, @@ -550,6 +443,150 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, gss_qop_t *qop_state, krb5_keyblock *key) { - *minor_status = (OM_uint32)KRB5_PROG_ETYPE_NOSUPP; - return GSS_S_FAILURE; + u_char Klocaldata[16]; + krb5_keyblock Klocal; + krb5_error_code ret; + int32_t seq_number; + size_t datalen; + OM_uint32 omret; + char k6_data[16], SND_SEQ[8], Confounder[8]; + char cksum_data[8]; + gss_arcfour_wrap_token *token; + u_char *p; + int cmp; + int conf_flag; + + if (conf_state) + *conf_state = 0; + if (qop_state) + *qop_state = 0; + + p = input_message_buffer->value; + omret = _gssapi_verify_mech_header(&p, + input_message_buffer->length, + GSS_KRB5_MECHANISM); + if (omret) + return omret; + token = (gss_arcfour_wrap_token *)p; + + datalen = input_message_buffer->length - + (p - ((u_char *)input_message_buffer->value)) - + sizeof(*token); + + if (memcmp(p, "\x02\x01", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ + return GSS_S_BAD_SIG; + p += 2; + + if (memcmp (p, "\x00\x00", 2) == 0) + conf_flag = 1; + else if (memcmp (p, "\xff\xff", 2) == 0) + conf_flag = 0; + else + return GSS_S_BAD_SIG; + + p += 2; + if (memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_BAD_MIC; + p += 2; + + ret = arcfour_mic_key(gssapi_krb5_context, key, + token->SGN_CKSUM, 8, + k6_data, sizeof(k6_data)); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + { + RC4_KEY rc4_key; + + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + RC4 (&rc4_key, 8, token->SND_SEQ, SND_SEQ); + memset(&rc4_key, 0, sizeof(rc4_key)); + memset(k6_data, 0, sizeof(k6_data)); + } + + gssapi_decode_be_om_uint32(SND_SEQ, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); + else + cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); + + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + { + int i; + + Klocal.keytype = KEYTYPE_ARCFOUR; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + ret = arcfour_mic_key(gssapi_krb5_context, &Klocal, + SND_SEQ, 4, + k6_data, sizeof(k6_data)); + memset(Klocaldata, 0, sizeof(Klocaldata)); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + output_message_buffer->value = malloc(datalen + 8); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + output_message_buffer->length = datalen - 1; + + if(conf_flag) { + RC4_KEY rc4_key; + + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + RC4 (&rc4_key, 8, token->Confounder, Confounder); + RC4 (&rc4_key, datalen, token->Confounder + 8, + output_message_buffer->value); + memset(&rc4_key, 0, sizeof(rc4_key)); + } else { + memcpy(Confounder, token->Confounder, 8); + memcpy(output_message_buffer->value, token->Confounder + 8,datalen - 1); + } + memset(k6_data, 0, sizeof(k6_data)); + + ret = arcfour_mic_cksum(key, cksum_data, sizeof(cksum_data), + p - 8, 8, + Confounder, sizeof(Confounder), + output_message_buffer->value, + output_message_buffer->length); + if (ret) { + *minor_status = ret; + gss_release_buffer(minor_status, input_message_buffer); + return GSS_S_FAILURE; + } + + cmp = memcmp(cksum_data, token->SGN_CKSUM, 8); + if (cmp) { + gss_release_buffer(minor_status, input_message_buffer); + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + omret = gssapi_msg_order_check(context_handle->order, seq_number); + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + if (omret) + return omret; + + if (conf_state) + *conf_state = conf_flag; + + return GSS_S_COMPLETE; } diff --git a/lib/gssapi/krb5/arcfour.c b/lib/gssapi/krb5/arcfour.c index 38ff80b27..c51bee393 100644 --- a/lib/gssapi/krb5/arcfour.c +++ b/lib/gssapi/krb5/arcfour.c @@ -33,28 +33,14 @@ #include "gssapi_locl.h" -#if 0 -static const char arcfour_sk[] = "signaturekey"; +/* + * Implements draft-brezak-win2k-krb-rc4-hmac-04.txt + */ -static krb5_error_code -get_arcfour_sk(krb5_context context, krb5_keyblock *key, - void *sk_key_data, size_t sk_key_size) -{ - Checksum cksum_k4; - - cksum_k4.checksum.data = sk_key_data; - cksum_k4.checksum.length = sk_key_size; - return krb5_hmac(context, CKSUMTYPE_RSA_MD5, - arcfour_sk, sizeof(arcfour_sk), 13, /* XXX usage */ - key, &cksum_k4); - -} -#endif +RCSID("$Id$"); static krb5_error_code arcfour_mic_key(krb5_context context, krb5_keyblock *key, - const void *header, size_t header_size, - const void *message, size_t message_size, void *cksum_data, size_t cksum_size, void *key6_data, size_t key6_size) { @@ -68,9 +54,7 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key, char T[4]; - /* draft: T = 0; */ memset(T, 0, 4); - /* draft: HMAC (K, &T, 4, K5); */ cksum_k5.checksum.data = k5_data; cksum_k5.checksum.length = sizeof(k5_data); @@ -82,7 +66,6 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key, key5.keytype = KEYTYPE_ARCFOUR; key5.keyvalue = cksum_k5.checksum; - /* HMAC(K5, MIC_checksum, 8, K6); */ cksum_k6.checksum.data = key6_data; cksum_k6.checksum.length = key6_size; @@ -90,22 +73,31 @@ arcfour_mic_key(krb5_context context, krb5_keyblock *key, cksum_data, cksum_size, 0, &key5, &cksum_k6); } -static krb5_error_code -arcfour_mic_cksum(const char *p, size_t p_sz, - const gss_buffer_t message_buffer, - krb5_keyblock *key, - u_char *sgn_cksum, size_t sgn_cksum_sz) +static krb5_error_code +arcfour_mic_cksum(krb5_keyblock *key, + u_char *sgn_cksum, size_t sgn_cksum_sz, + const char *v1, size_t l1, + const void *v2, size_t l2, + const void *v3, size_t l3) { Checksum CKSUM; - u_char *ptr = emalloc(p_sz + message_buffer->length); + u_char *ptr; + size_t len; krb5_crypto crypto; krb5_error_code ret; assert(sgn_cksum_sz == 8); - memcpy(ptr, p, p_sz); - memcpy(ptr + p_sz, message_buffer->value, message_buffer->length); + len = l1 + l2 + l3; + + ptr = malloc(len); + if (ptr == NULL) + return ENOMEM; + + memcpy(ptr, v1, l1); + memcpy(ptr + l1, v2, l2); + memcpy(ptr + l1 + l2, v3, l3); ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto); if (ret) { @@ -114,12 +106,11 @@ arcfour_mic_cksum(const char *p, size_t p_sz, } ret = krb5_create_checksum(gssapi_krb5_context, - crypto, - KRB5_KU_USAGE_SIGN, - 0, - ptr, - p_sz + message_buffer->length, - &CKSUM); + crypto, + KRB5_KU_USAGE_SIGN, + 0, + ptr, len, + &CKSUM); free(ptr); if (ret == 0) { memcpy(sgn_cksum, CKSUM.checksum.data, sgn_cksum_sz); @@ -132,24 +123,18 @@ arcfour_mic_cksum(const char *p, size_t p_sz, OM_uint32 -_gssapi_get_mic_arcfour - (OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, - gss_qop_t qop_req, - const gss_buffer_t message_buffer, - gss_buffer_t message_token, - krb5_keyblock *key - ) +_gssapi_get_mic_arcfour(OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + gss_qop_t qop_req, + const gss_buffer_t message_buffer, + gss_buffer_t message_token, + krb5_keyblock *key) { gss_arcfour_mic_token *token; - krb5_error_code kret; - - u_char *p; - + krb5_error_code ret; int32_t seq_number; size_t len, total_len; - - char k6_data[16]; + u_char k6_data[16], *p; gssapi_krb5_encap_length (22, &len, &total_len, GSS_KRB5_MECHANISM); @@ -174,19 +159,21 @@ _gssapi_get_mic_arcfour token->Filler[2] = 0xff; token->Filler[3] = 0xff; - kret = arcfour_mic_cksum(p, 8, message_buffer, key, token->SGN_CKSUM, 8); - if (kret) { - *minor_status = kret; + ret = arcfour_mic_cksum(key, token->SGN_CKSUM, 8, + p, 8, + message_buffer->value, message_buffer->length, + NULL, 0); + if (ret) { gss_release_buffer(minor_status, message_token); + *minor_status = ret; return GSS_S_FAILURE; } - kret = arcfour_mic_key(gssapi_krb5_context, key, - p, 8, - message_buffer->value,message_buffer->length, - token->SGN_CKSUM, 8, - k6_data, sizeof(k6_data)); - if (kret) { - *minor_status = kret; + ret = arcfour_mic_key(gssapi_krb5_context, key, + token->SGN_CKSUM, 8, + k6_data, sizeof(k6_data)); + if (ret) { + gss_release_buffer(minor_status, message_token); + *minor_status = ret; return GSS_S_FAILURE; } p += 8; @@ -198,11 +185,8 @@ _gssapi_get_mic_arcfour krb5_auth_con_getlocalseqnumber (gssapi_krb5_context, context_handle->auth_context, &seq_number); - - p[0] = (seq_number >> 24) & 0xFF; - p[1] = (seq_number >> 16) & 0xFF; - p[2] = (seq_number >> 8) & 0xFF; - p[3] = (seq_number >> 0) & 0xFF; + + gssapi_encode_be_om_uint32(seq_number, p); krb5_auth_con_setlocalseqnumber (gssapi_krb5_context, context_handle->auth_context, @@ -221,6 +205,7 @@ _gssapi_get_mic_arcfour RC4 (&rc4_key, 8, p, p); memset(&rc4_key, 0, sizeof(rc4_key)); + memset(k6_data, 0, sizeof(k6_data)); } return GSS_S_COMPLETE; @@ -228,30 +213,28 @@ _gssapi_get_mic_arcfour OM_uint32 -_gssapi_verify_mic_arcfour - (OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, - const gss_buffer_t message_buffer, - const gss_buffer_t token_buffer, - gss_qop_t * qop_state, - char *type, - krb5_keyblock *key - ) +_gssapi_verify_mic_arcfour(OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + const gss_buffer_t message_buffer, + const gss_buffer_t token_buffer, + gss_qop_t * qop_state, + char *type, + krb5_keyblock *key) { - krb5_error_code kret; + krb5_error_code ret; int32_t seq_number; - OM_uint32 ret; - char cksum_data[8], k6_data[16]; + OM_uint32 omret; + char cksum_data[8], k6_data[16], SND_SEQ[8]; u_char *p; int cmp; p = token_buffer->value; - ret = gssapi_krb5_verify_header (&p, - token_buffer->length, - type, - GSS_KRB5_MECHANISM); - if (ret) - return ret; + omret = gssapi_krb5_verify_header (&p, + token_buffer->length, + type, + GSS_KRB5_MECHANISM); + if (omret) + return omret; if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ return GSS_S_BAD_SIG; @@ -260,24 +243,20 @@ _gssapi_verify_mic_arcfour return GSS_S_BAD_MIC; p += 4; - /* draft: memcpy (T_plus_hdr_plus_msg + 04, MIC_hdr, 8); */ - /* draft: memcpy (T_plus_hdr_plus_msg + 12, msg, msg_len); */ - - kret = arcfour_mic_cksum(p - 8, 8, message_buffer, key, - cksum_data, sizeof(cksum_data)); - if (kret) { - *minor_status = kret; + ret = arcfour_mic_cksum(key, cksum_data, sizeof(cksum_data), + p - 8, 8, + message_buffer->value, message_buffer->length, + NULL, 0); + if (ret) { + *minor_status = ret; return GSS_S_FAILURE; } - kret = arcfour_mic_key(gssapi_krb5_context, key, - p - 8, 8, - message_buffer->value, - message_buffer->length, - cksum_data, sizeof(cksum_data), - k6_data, sizeof(k6_data)); - if (kret) { - *minor_status = kret; + ret = arcfour_mic_key(gssapi_krb5_context, key, + cksum_data, sizeof(cksum_data), + k6_data, sizeof(k6_data)); + if (ret) { + *minor_status = ret; return GSS_S_FAILURE; } @@ -287,77 +266,56 @@ _gssapi_verify_mic_arcfour return GSS_S_BAD_MIC; } - /* XXX don't modify p */ { RC4_KEY rc4_key; RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); - RC4 (&rc4_key, 8, p, p); + RC4 (&rc4_key, 8, p, SND_SEQ); memset(&rc4_key, 0, sizeof(rc4_key)); + memset(k6_data, 0, sizeof(k6_data)); } - gssapi_decode_om_uint32(p, &seq_number); + gssapi_decode_be_om_uint32(SND_SEQ, &seq_number); if (context_handle->more_flags & LOCAL) - cmp = memcmp(&p[4], "\x00\x00\x00\x00", 4); + cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); else - cmp = memcmp(&p[4], "\xff\xff\xff\xff", 4); - + cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); + + memset(SND_SEQ, 0, sizeof(SND_SEQ)); if (cmp != 0) { *minor_status = 0; return GSS_S_BAD_MIC; } HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - ret = gssapi_msg_order_check(context_handle->order, seq_number); + omret = gssapi_msg_order_check(context_handle->order, seq_number); HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); - if (ret) - return ret; + if (omret) + return omret; - return 0; + return GSS_S_COMPLETE; } OM_uint32 -_gssapi_wrap_arcfour - (OM_uint32 * minor_status, - const gss_ctx_id_t context_handle, - int conf_req_flag, - gss_qop_t qop_req, - const gss_buffer_t input_message_buffer, - int * conf_state, - gss_buffer_t output_message_buffer, - krb5_keyblock *key - ) +_gssapi_wrap_arcfour(OM_uint32 * minor_status, + const gss_ctx_id_t context_handle, + int conf_req_flag, + gss_qop_t qop_req, + const gss_buffer_t input_message_buffer, + int * conf_state, + gss_buffer_t output_message_buffer, + krb5_keyblock *key) { -#if 0 - u_char *p; - OM_uint32 ret; - int32_t seq_number; + u_char Klocaldata[16], k6_data[16], *p; size_t len, total_len, datalen; gss_arcfour_wrap_token *token; + krb5_keyblock Klocal; + krb5_error_code ret; + int32_t seq_number; - krb5_keyblock key7; - char k7_data[16]; - - Checksum cksum_k8; - krb5_keyblock key8; - char k8_data[16]; - - Checksum cksum_k9; - krb5_keyblock key9; - char k9_data[16]; - - krb5_keyblock key10; - char k10_data[16]; - - Checksum cksum_k11; - char k11_data[16]; - - Checksum CKSUM; - char cksum_data[16]; - - datalen = input_message_buffer->length; + datalen = input_message_buffer->length + 1 /* padding */; len = datalen + 30; gssapi_krb5_encap_length (len, &len, &total_len, GSS_KRB5_MECHANISM); @@ -368,12 +326,13 @@ _gssapi_wrap_arcfour return GSS_S_FAILURE; } - p = gssapi_krb5_make_header(output_message_buffer->value, - len, - "\x02\x01", /* TOK_ID */ - GSS_KRB5_MECHANISM); + p = _gssapi_make_mech_header(output_message_buffer->value, + len, + GSS_KRB5_MECHANISM); token = (gss_arcfour_wrap_token *)p; + token->TOK_ID[0] = 0x02; + token->TOK_ID[1] = 0x01; token->SGN_ALG[0] = 0x11; token->SGN_ALG[1] = 0x00; if (conf_req_flag) { @@ -386,160 +345,94 @@ _gssapi_wrap_arcfour token->Filler[0] = 0xff; token->Filler[1] = 0xff; - memset(p + 8, 0, 16); /* XXX SND_SEQ, SGN_CKSUM */ - /* Confounder */ - krb5_generate_random_block(p + 16, 8); - - ret = get_arcfour_sk(gssapi_krb5_context, key, k7_data, sizeof(k7_data)); - if (ret) { - gss_release_buffer(minor_status, output_message_buffer); - return ret; - } - - key7.keytype = KEYTYPE_ARCFOUR; - key7.keyvalue.length = sizeof(k7_data); - key7.keyvalue.data = k7_data; - - { - u_char T[4]; - MD5_CTX md5; - u_char hash[16]; - - T[0] = 13; - T[1] = 0; - T[2] = 0; - T[3] = 0; - - MD5_Init(&md5); - MD5_Update(&md5, T, 4); /* T */ - MD5_Update(&md5, p - 8, 8); /* Token.Header */ - MD5_Update(&md5, p + 16, 8); /* Confounder */ - MD5_Update(&md5, - input_message_buffer->value, input_message_buffer->length); - MD5_Final(hash, &md5); - - CKSUM.checksum.data = cksum_data; - CKSUM.checksum.length = sizeof(cksum_data); - - /* draft: HMAC (K7, MD5_of_T_hdr_msg, CHKSUM); */ - ret = krb5_hmac(gssapi_krb5_context, CKSUMTYPE_RSA_MD5, - hash, sizeof(hash), - 0 /* XXX */, &key7, &CKSUM); - if (ret) { - gss_release_buffer(minor_status, output_message_buffer); - return ret; - } - } - - { - u_char T[4]; - - memset(T, 0, sizeof(T)); - cksum_k8.checksum.data = k8_data; - cksum_k8.checksum.length = sizeof(k8_data); - - ret = krb5_hmac(gssapi_krb5_context, CKSUMTYPE_RSA_MD5, - T, sizeof(T), 4 /* XXX */, key, &cksum_k8); - if (ret) { - gss_release_buffer(minor_status, output_message_buffer); - return ret; - } - } - - cksum_k9.checksum.data = k9_data; - cksum_k9.checksum.length = sizeof(k9_data); - - key8.keytype = KEYTYPE_ARCFOUR; - key8.keyvalue.length = sizeof(k8_data); - key8.keyvalue.data = k8_data; - - ret = krb5_hmac(gssapi_krb5_context, CKSUMTYPE_RSA_MD5, - cksum_data, sizeof(cksum_data), - 8 /* XXX */, &key8, &cksum_k9); - if (ret) { - gss_release_buffer(minor_status, output_message_buffer); - return ret; - } - - key9.keytype = KEYTYPE_ARCFOUR; - key9.keyvalue.length = sizeof(k9_data); - key9.keyvalue.data = k9_data; + /* skip to SND_SEQ */ + p += 8; HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); krb5_auth_con_getlocalseqnumber (gssapi_krb5_context, context_handle->auth_context, &seq_number); - p[0] = (seq_number >> 0) & 0xFF; - p[1] = (seq_number >> 8) & 0xFF; - p[2] = (seq_number >> 16) & 0xFF; - p[3] = (seq_number >> 24) & 0xFF; - + gssapi_encode_be_om_uint32(seq_number, p); + krb5_auth_con_setlocalseqnumber (gssapi_krb5_context, context_handle->auth_context, ++seq_number); HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); - memset (p + 4, (context_handle->more_flags & LOCAL) ? 0 : 0xFF, 4); + memset (p + 4, + (context_handle->more_flags & LOCAL) ? 0xFF : 0, + 4); - { - RC4_KEY rc4_key; - - RC4_set_key (&rc4_key, sizeof(k9_data), k9_data); - RC4 (&rc4_key, 8, p, p); - - memset(&rc4_key, 0, sizeof(rc4_key)); + /* Confounder */ + krb5_generate_random_block(token->Confounder, sizeof(token->Confounder)); + + ret = arcfour_mic_cksum(key, token->SGN_CKSUM, 8, + p - 8, 8, + token->Confounder, sizeof(token->Confounder), + input_message_buffer->value, + input_message_buffer->length); + if (ret) { + *minor_status = ret; + gss_release_buffer(minor_status, input_message_buffer); + return GSS_S_FAILURE; } - p += 8; - memcpy(p, cksum_data, 8); - - key10.keytype = KEYTYPE_ARCFOUR; - key10.keyvalue.length = sizeof(k10_data); - key10.keyvalue.data = k10_data; - - assert(key->keyvalue.length == 16); { int i; - memcpy(k10_data, key->keyvalue.data, sizeof(k10_data)); - for (i = 0; i < sizeof(k10_data); i++) - k10_data[i] ^= 0xF0; + + Klocal.keytype = KEYTYPE_ARCFOUR; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + ret = arcfour_mic_key(gssapi_krb5_context, &Klocal, + p, 4, + k6_data, sizeof(k6_data)); + memset(Klocaldata, 0, sizeof(Klocaldata)); + if (ret) { + gss_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + return GSS_S_FAILURE; + } + + p += 24; /* skip SND_SEQ, SGN_CKSUM, and Confounder */ + + memcpy(p, input_message_buffer->value, input_message_buffer->length); + p[input_message_buffer->length] = 0; /* PADDING */ + + if(conf_req_flag) { + RC4_KEY rc4_key; + + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + /* XXX ? */ + RC4 (&rc4_key, 8 + datalen, token->Confounder, token->Confounder); + memset(&rc4_key, 0, sizeof(rc4_key)); + } + memset(k6_data, 0, sizeof(k6_data)); + + ret = arcfour_mic_key(gssapi_krb5_context, key, + token->SGN_CKSUM, 8, + k6_data, sizeof(k6_data)); + if (ret) { + gss_release_buffer(minor_status, output_message_buffer); + *minor_status = ret; + return GSS_S_FAILURE; } { - u_char T[4]; - - memset(T, 0, sizeof(T)); - cksum_k11.checksum.data = k11_data; - cksum_k11.checksum.length = sizeof(k11_data); - - ret = krb5_hmac(gssapi_krb5_context, CKSUMTYPE_RSA_MD5, - T, sizeof(T), 4 /* XXX */, &key10, &cksum_k11); - if (ret) { - gss_release_buffer(minor_status, output_message_buffer); - return ret; - } - } - - memcpy(p + 8, input_message_buffer->value, - input_message_buffer->length); - p[8 + input_message_buffer->length] = 1; - - if (conf_req_flag) { RC4_KEY rc4_key; - RC4_set_key (&rc4_key, sizeof(k11_data), k11_data); - - RC4 (&rc4_key, 8 + input_message_buffer->length, p, p); + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + RC4 (&rc4_key, 8, token->SND_SEQ, token->SND_SEQ); memset(&rc4_key, 0, sizeof(rc4_key)); + memset(k6_data, 0, sizeof(k6_data)); } - + *minor_status = 0; return GSS_S_COMPLETE; -#else - *minor_status = (OM_uint32)KRB5_PROG_ETYPE_NOSUPP; - return GSS_S_FAILURE; -#endif } OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, @@ -550,6 +443,150 @@ OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, gss_qop_t *qop_state, krb5_keyblock *key) { - *minor_status = (OM_uint32)KRB5_PROG_ETYPE_NOSUPP; - return GSS_S_FAILURE; + u_char Klocaldata[16]; + krb5_keyblock Klocal; + krb5_error_code ret; + int32_t seq_number; + size_t datalen; + OM_uint32 omret; + char k6_data[16], SND_SEQ[8], Confounder[8]; + char cksum_data[8]; + gss_arcfour_wrap_token *token; + u_char *p; + int cmp; + int conf_flag; + + if (conf_state) + *conf_state = 0; + if (qop_state) + *qop_state = 0; + + p = input_message_buffer->value; + omret = _gssapi_verify_mech_header(&p, + input_message_buffer->length, + GSS_KRB5_MECHANISM); + if (omret) + return omret; + token = (gss_arcfour_wrap_token *)p; + + datalen = input_message_buffer->length - + (p - ((u_char *)input_message_buffer->value)) - + sizeof(*token); + + if (memcmp(p, "\x02\x01", 2) != 0) + return GSS_S_BAD_SIG; + p += 2; + if (memcmp(p, "\x11\x00", 2) != 0) /* SGN_ALG = HMAC MD5 ARCFOUR */ + return GSS_S_BAD_SIG; + p += 2; + + if (memcmp (p, "\x00\x00", 2) == 0) + conf_flag = 1; + else if (memcmp (p, "\xff\xff", 2) == 0) + conf_flag = 0; + else + return GSS_S_BAD_SIG; + + p += 2; + if (memcmp (p, "\xff\xff", 2) != 0) + return GSS_S_BAD_MIC; + p += 2; + + ret = arcfour_mic_key(gssapi_krb5_context, key, + token->SGN_CKSUM, 8, + k6_data, sizeof(k6_data)); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + { + RC4_KEY rc4_key; + + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + RC4 (&rc4_key, 8, token->SND_SEQ, SND_SEQ); + memset(&rc4_key, 0, sizeof(rc4_key)); + memset(k6_data, 0, sizeof(k6_data)); + } + + gssapi_decode_be_om_uint32(SND_SEQ, &seq_number); + + if (context_handle->more_flags & LOCAL) + cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); + else + cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); + + if (cmp != 0) { + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + { + int i; + + Klocal.keytype = KEYTYPE_ARCFOUR; + Klocal.keyvalue.data = Klocaldata; + Klocal.keyvalue.length = sizeof(Klocaldata); + + for (i = 0; i < 16; i++) + Klocaldata[i] = ((u_char *)key->keyvalue.data)[i] ^ 0xF0; + } + ret = arcfour_mic_key(gssapi_krb5_context, &Klocal, + SND_SEQ, 4, + k6_data, sizeof(k6_data)); + memset(Klocaldata, 0, sizeof(Klocaldata)); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + output_message_buffer->value = malloc(datalen + 8); + if (output_message_buffer->value == NULL) { + *minor_status = ENOMEM; + return GSS_S_FAILURE; + } + output_message_buffer->length = datalen - 1; + + if(conf_flag) { + RC4_KEY rc4_key; + + RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); + RC4 (&rc4_key, 8, token->Confounder, Confounder); + RC4 (&rc4_key, datalen, token->Confounder + 8, + output_message_buffer->value); + memset(&rc4_key, 0, sizeof(rc4_key)); + } else { + memcpy(Confounder, token->Confounder, 8); + memcpy(output_message_buffer->value, token->Confounder + 8,datalen - 1); + } + memset(k6_data, 0, sizeof(k6_data)); + + ret = arcfour_mic_cksum(key, cksum_data, sizeof(cksum_data), + p - 8, 8, + Confounder, sizeof(Confounder), + output_message_buffer->value, + output_message_buffer->length); + if (ret) { + *minor_status = ret; + gss_release_buffer(minor_status, input_message_buffer); + return GSS_S_FAILURE; + } + + cmp = memcmp(cksum_data, token->SGN_CKSUM, 8); + if (cmp) { + gss_release_buffer(minor_status, input_message_buffer); + *minor_status = 0; + return GSS_S_BAD_MIC; + } + + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + omret = gssapi_msg_order_check(context_handle->order, seq_number); + HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); + if (omret) + return omret; + + if (conf_state) + *conf_state = conf_flag; + + return GSS_S_COMPLETE; }