OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, const gsskrb5_ctx context_handle, krb5_context context, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int *conf_state, gss_qop_t *qop_state, krb5_keyblock *key) { u_char Klocaldata[16]; krb5_keyblock Klocal; krb5_error_code ret; uint32_t seq_number; size_t datalen; OM_uint32 omret; u_char k6_data[16], SND_SEQ[8], Confounder[8]; u_char cksum_data[8]; u_char *p, *p0; int cmp; int conf_flag; size_t padlen = 0, len; if (conf_state) *conf_state = 0; if (qop_state) *qop_state = 0; p0 = input_message_buffer->value; if (IS_DCE_STYLE(context_handle)) { len = GSS_ARCFOUR_WRAP_TOKEN_SIZE + GSS_ARCFOUR_WRAP_TOKEN_DCE_DER_HEADER_SIZE; if (input_message_buffer->length < len) return GSS_S_BAD_MECH; } else { len = input_message_buffer->length; } omret = _gssapi_verify_mech_header(&p0, len, GSS_KRB5_MECHANISM); if (omret) return omret; /* length of mech header */ len = (p0 - (u_char *)input_message_buffer->value) + GSS_ARCFOUR_WRAP_TOKEN_SIZE; if (len > input_message_buffer->length) return GSS_S_BAD_MECH; /* length of data */ datalen = input_message_buffer->length - len; p = p0; 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, "\x10\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 = NULL; ret = arcfour_mic_key(context, key, p0 + 16, 8, /* SGN_CKSUM */ k6_data, sizeof(k6_data)); if (ret) { *minor_status = ret; return GSS_S_FAILURE; } { EVP_CIPHER_CTX rc4_key; EVP_CIPHER_CTX_init(&rc4_key); EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); EVP_Cipher(&rc4_key, SND_SEQ, p0 + 8, 8); EVP_CIPHER_CTX_cleanup(&rc4_key); memset(k6_data, 0, sizeof(k6_data)); } _gss_mg_decode_be_uint32(SND_SEQ, &seq_number); if (context_handle->more_flags & LOCAL) cmp = memcmp(&SND_SEQ[4], "\xff\xff\xff\xff", 4); else cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); if (cmp != 0) { *minor_status = 0; return GSS_S_BAD_MIC; } { int i; Klocal.keytype = key->keytype; 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(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); if (output_message_buffer->value == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } output_message_buffer->length = datalen; if(conf_flag) { EVP_CIPHER_CTX rc4_key; EVP_CIPHER_CTX_init(&rc4_key); EVP_CipherInit_ex(&rc4_key, EVP_rc4(), NULL, k6_data, NULL, 1); EVP_Cipher(&rc4_key, Confounder, p0 + 24, 8); EVP_Cipher(&rc4_key, output_message_buffer->value, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, datalen); EVP_CIPHER_CTX_cleanup(&rc4_key); } else { memcpy(Confounder, p0 + 24, 8); /* Confounder */ memcpy(output_message_buffer->value, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, datalen); } memset(k6_data, 0, sizeof(k6_data)); if (!IS_DCE_STYLE(context_handle)) { ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen); if (ret) { _gsskrb5_release_buffer(minor_status, output_message_buffer); *minor_status = 0; return ret; } output_message_buffer->length -= padlen; } ret = arcfour_mic_cksum(context, key, KRB5_KU_USAGE_SEAL, cksum_data, sizeof(cksum_data), p0, 8, Confounder, sizeof(Confounder), output_message_buffer->value, output_message_buffer->length + padlen); if (ret) { _gsskrb5_release_buffer(minor_status, output_message_buffer); *minor_status = ret; return GSS_S_FAILURE; } cmp = ct_memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */ if (cmp) { _gsskrb5_release_buffer(minor_status, output_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->gk5c.order, seq_number); HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); if (omret) return omret; if (conf_state) *conf_state = conf_flag; *minor_status = 0; return GSS_S_COMPLETE; }
static OM_uint32 unwrap_des (OM_uint32 * minor_status, const gsskrb5_ctx context_handle, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int * conf_state, gss_qop_t * qop_state, krb5_keyblock *key ) { u_char *p, *seq; size_t len; MD5_CTX md5; u_char hash[16]; DES_key_schedule schedule; DES_cblock deskey; DES_cblock zero; int i; uint32_t seq_number; size_t padlength; OM_uint32 ret; int cstate; int cmp; p = input_message_buffer->value; ret = _gsskrb5_verify_header (&p, input_message_buffer->length, "\x02\x01", GSS_KRB5_MECHANISM); if (ret) return ret; if (memcmp (p, "\x00\x00", 2) != 0) return GSS_S_BAD_SIG; p += 2; if (memcmp (p, "\x00\x00", 2) == 0) { cstate = 1; } else if (memcmp (p, "\xFF\xFF", 2) == 0) { cstate = 0; } else return GSS_S_BAD_MIC; p += 2; if(conf_state != NULL) *conf_state = cstate; if (memcmp (p, "\xff\xff", 2) != 0) return GSS_S_DEFECTIVE_TOKEN; p += 2; p += 16; len = p - (u_char *)input_message_buffer->value; if(cstate) { /* decrypt data */ memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); for (i = 0; i < sizeof(deskey); ++i) deskey[i] ^= 0xf0; DES_set_key (&deskey, &schedule); memset (&zero, 0, sizeof(zero)); DES_cbc_encrypt ((void *)p, (void *)p, input_message_buffer->length - len, &schedule, &zero, DES_DECRYPT); memset (deskey, 0, sizeof(deskey)); memset (&schedule, 0, sizeof(schedule)); } /* check pad */ ret = _gssapi_verify_pad(input_message_buffer, input_message_buffer->length - len, &padlength); if (ret) return ret; MD5_Init (&md5); MD5_Update (&md5, p - 24, 8); MD5_Update (&md5, p, input_message_buffer->length - len); MD5_Final (hash, &md5); memset (&zero, 0, sizeof(zero)); memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); DES_set_key (&deskey, &schedule); DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), &schedule, &zero); if (memcmp (p - 8, hash, 8) != 0) return GSS_S_BAD_MIC; /* verify sequence number */ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); p -= 16; DES_set_key (&deskey, &schedule); DES_cbc_encrypt ((void *)p, (void *)p, 8, &schedule, (DES_cblock *)hash, DES_DECRYPT); memset (deskey, 0, sizeof(deskey)); memset (&schedule, 0, sizeof(schedule)); seq = p; _gsskrb5_decode_om_uint32(seq, &seq_number); if (context_handle->more_flags & LOCAL) cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4); else cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4); if (cmp != 0) { HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return GSS_S_BAD_MIC; } ret = _gssapi_msg_order_check(context_handle->order, seq_number); if (ret) { HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return ret; } HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); /* copy out data */ output_message_buffer->length = input_message_buffer->length - len - padlength - 8; output_message_buffer->value = malloc(output_message_buffer->length); if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) return GSS_S_FAILURE; memcpy (output_message_buffer->value, p + 24, output_message_buffer->length); return GSS_S_COMPLETE; }
OM_uint32 _gssapi_unwrap_arcfour(OM_uint32 *minor_status, const gss_ctx_id_t context_handle, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int *conf_state, gss_qop_t *qop_state, krb5_keyblock *key) { 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]; u_char *p, *p0; int cmp; int conf_flag; size_t padlen; if (conf_state) *conf_state = 0; if (qop_state) *qop_state = 0; p0 = input_message_buffer->value; omret = _gssapi_verify_mech_header(&p0, input_message_buffer->length, GSS_KRB5_MECHANISM); if (omret) return omret; p = p0; datalen = input_message_buffer->length - (p - ((u_char *)input_message_buffer->value)) - GSS_ARCFOUR_WRAP_TOKEN_SIZE; 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, "\x10\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 = NULL; ret = arcfour_mic_key(gssapi_krb5_context, key, p0 + 16, 8, /* SGN_CKSUM */ 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, p0 + 8, 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], "\xff\xff\xff\xff", 4); else cmp = memcmp(&SND_SEQ[4], "\x00\x00\x00\x00", 4); if (cmp != 0) { *minor_status = 0; return GSS_S_BAD_MIC; } { int i; Klocal.keytype = key->keytype; 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); if (output_message_buffer->value == NULL) { *minor_status = ENOMEM; return GSS_S_FAILURE; } output_message_buffer->length = datalen; if(conf_flag) { RC4_KEY rc4_key; RC4_set_key (&rc4_key, sizeof(k6_data), k6_data); RC4 (&rc4_key, 8, p0 + 24, Confounder); /* Confounder */ RC4 (&rc4_key, datalen, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, output_message_buffer->value); memset(&rc4_key, 0, sizeof(rc4_key)); } else { memcpy(Confounder, p0 + 24, 8); /* Confounder */ memcpy(output_message_buffer->value, p0 + GSS_ARCFOUR_WRAP_TOKEN_SIZE, datalen); } memset(k6_data, 0, sizeof(k6_data)); ret = _gssapi_verify_pad(output_message_buffer, datalen, &padlen); if (ret) { gss_release_buffer(minor_status, output_message_buffer); *minor_status = 0; return ret; } output_message_buffer->length -= padlen; ret = arcfour_mic_cksum(key, KRB5_KU_USAGE_SEAL, cksum_data, sizeof(cksum_data), p0, 8, Confounder, sizeof(Confounder), output_message_buffer->value, output_message_buffer->length + padlen); if (ret) { gss_release_buffer(minor_status, output_message_buffer); *minor_status = ret; return GSS_S_FAILURE; } cmp = memcmp(cksum_data, p0 + 16, 8); /* SGN_CKSUM */ if (cmp) { gss_release_buffer(minor_status, output_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_unlock(&context_handle->ctx_id_mutex); if (omret) return omret; if (conf_state) *conf_state = conf_flag; *minor_status = 0; return GSS_S_COMPLETE; }
static OM_uint32 unwrap_des3 (OM_uint32 * minor_status, const gsskrb5_ctx context_handle, krb5_context context, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int * conf_state, gss_qop_t * qop_state, krb5_keyblock *key ) { u_char *p; size_t len; u_char *seq; krb5_data seq_data; u_char cksum[20]; uint32_t seq_number; size_t padlength; OM_uint32 ret; int cstate; krb5_crypto crypto; Checksum csum; int cmp; p = input_message_buffer->value; ret = _gsskrb5_verify_header (&p, input_message_buffer->length, "\x02\x01", GSS_KRB5_MECHANISM); if (ret) return ret; if (memcmp (p, "\x04\x00", 2) != 0) /* HMAC SHA1 DES3_KD */ return GSS_S_BAD_SIG; p += 2; if (memcmp (p, "\x02\x00", 2) == 0) { cstate = 1; } else if (memcmp (p, "\xff\xff", 2) == 0) { cstate = 0; } else return GSS_S_BAD_MIC; p += 2; if(conf_state != NULL) *conf_state = cstate; if (memcmp (p, "\xff\xff", 2) != 0) return GSS_S_DEFECTIVE_TOKEN; p += 2; p += 28; len = p - (u_char *)input_message_buffer->value; if(cstate) { /* decrypt data */ krb5_data tmp; ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, &crypto); if (ret) { *minor_status = ret; return GSS_S_FAILURE; } ret = krb5_decrypt(context, crypto, KRB5_KU_USAGE_SEAL, p, input_message_buffer->length - len, &tmp); krb5_crypto_destroy(context, crypto); if (ret) { *minor_status = ret; return GSS_S_FAILURE; } assert (tmp.length == input_message_buffer->length - len); memcpy (p, tmp.data, tmp.length); krb5_data_free(&tmp); } /* check pad */ ret = _gssapi_verify_pad(input_message_buffer, input_message_buffer->length - len, &padlength); if (ret) return ret; /* verify sequence number */ HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); p -= 28; ret = krb5_crypto_init(context, key, ETYPE_DES3_CBC_NONE, &crypto); if (ret) { *minor_status = ret; HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return GSS_S_FAILURE; } { DES_cblock ivec; memcpy(&ivec, p + 8, 8); ret = krb5_decrypt_ivec (context, crypto, KRB5_KU_USAGE_SEQ, p, 8, &seq_data, &ivec); } krb5_crypto_destroy (context, crypto); if (ret) { *minor_status = ret; HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return GSS_S_FAILURE; } if (seq_data.length != 8) { krb5_data_free (&seq_data); *minor_status = 0; HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return GSS_S_BAD_MIC; } seq = seq_data.data; _gsskrb5_decode_om_uint32(seq, &seq_number); if (context_handle->more_flags & LOCAL) cmp = memcmp(&seq[4], "\xff\xff\xff\xff", 4); else cmp = memcmp(&seq[4], "\x00\x00\x00\x00", 4); krb5_data_free (&seq_data); if (cmp != 0) { *minor_status = 0; HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return GSS_S_BAD_MIC; } ret = _gssapi_msg_order_check(context_handle->order, seq_number); if (ret) { *minor_status = 0; HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return ret; } HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); /* verify checksum */ memcpy (cksum, p + 8, 20); memcpy (p + 20, p - 8, 8); csum.cksumtype = CKSUMTYPE_HMAC_SHA1_DES3; csum.checksum.length = 20; csum.checksum.data = cksum; ret = krb5_crypto_init(context, key, 0, &crypto); if (ret) { *minor_status = ret; return GSS_S_FAILURE; } ret = krb5_verify_checksum (context, crypto, KRB5_KU_USAGE_SIGN, p + 20, input_message_buffer->length - len + 8, &csum); krb5_crypto_destroy (context, crypto); if (ret) { *minor_status = ret; return GSS_S_FAILURE; } /* copy out data */ output_message_buffer->length = input_message_buffer->length - len - padlength - 8; output_message_buffer->value = malloc(output_message_buffer->length); if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) return GSS_S_FAILURE; memcpy (output_message_buffer->value, p + 36, output_message_buffer->length); return GSS_S_COMPLETE; }
static OM_uint32 unwrap_des (OM_uint32 * minor_status, const gsskrb5_ctx context_handle, const gss_buffer_t input_message_buffer, gss_buffer_t output_message_buffer, int * conf_state, gss_qop_t * qop_state, krb5_keyblock *key ) { u_char *p, *seq; size_t len; EVP_MD_CTX *md5; u_char hash[16]; EVP_CIPHER_CTX *des_ctx; DES_key_schedule schedule; DES_cblock deskey; DES_cblock zero; size_t i; uint32_t seq_number; size_t padlength; OM_uint32 ret; int cstate; int cmp; int token_len; if (IS_DCE_STYLE(context_handle)) { token_len = 22 + 8 + 15; /* 45 */ } else { token_len = input_message_buffer->length; } p = input_message_buffer->value; ret = _gsskrb5_verify_header (&p, token_len, "\x02\x01", GSS_KRB5_MECHANISM); if (ret) return ret; if (memcmp (p, "\x00\x00", 2) != 0) return GSS_S_BAD_SIG; p += 2; if (memcmp (p, "\x00\x00", 2) == 0) { cstate = 1; } else if (memcmp (p, "\xFF\xFF", 2) == 0) { cstate = 0; } else return GSS_S_BAD_MIC; p += 2; if(conf_state != NULL) *conf_state = cstate; if (memcmp (p, "\xff\xff", 2) != 0) return GSS_S_DEFECTIVE_TOKEN; p += 2; p += 16; len = p - (u_char *)input_message_buffer->value; if(cstate) { /* decrypt data */ memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); memset (&zero, 0, sizeof(zero)); for (i = 0; i < sizeof(deskey); ++i) deskey[i] ^= 0xf0; des_ctx = EVP_CIPHER_CTX_new(); if (des_ctx == NULL) { memset (deskey, 0, sizeof(deskey)); *minor_status = ENOMEM; return GSS_S_FAILURE; } EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, deskey, zero, 0); EVP_Cipher(des_ctx, p, p, input_message_buffer->length - len); EVP_CIPHER_CTX_free(des_ctx); memset (deskey, 0, sizeof(deskey)); } if (IS_DCE_STYLE(context_handle)) { padlength = 0; } else { /* check pad */ ret = _gssapi_verify_pad(input_message_buffer, input_message_buffer->length - len, &padlength); if (ret) return ret; } md5 = EVP_MD_CTX_create(); EVP_DigestInit_ex(md5, EVP_md5(), NULL); EVP_DigestUpdate(md5, p - 24, 8); EVP_DigestUpdate(md5, p, input_message_buffer->length - len); EVP_DigestFinal_ex(md5, hash, NULL); EVP_MD_CTX_destroy(md5); memset (&zero, 0, sizeof(zero)); memcpy (&deskey, key->keyvalue.data, sizeof(deskey)); DES_set_key_unchecked (&deskey, &schedule); DES_cbc_cksum ((void *)hash, (void *)hash, sizeof(hash), &schedule, &zero); if (ct_memcmp (p - 8, hash, 8) != 0) { memset (deskey, 0, sizeof(deskey)); memset (&schedule, 0, sizeof(schedule)); return GSS_S_BAD_MIC; } /* verify sequence number */ des_ctx = EVP_CIPHER_CTX_new(); if (des_ctx == NULL) { memset (deskey, 0, sizeof(deskey)); memset (&schedule, 0, sizeof(schedule)); *minor_status = ENOMEM; return GSS_S_FAILURE; } HEIMDAL_MUTEX_lock(&context_handle->ctx_id_mutex); p -= 16; EVP_CipherInit_ex(des_ctx, EVP_des_cbc(), NULL, key->keyvalue.data, hash, 0); EVP_Cipher(des_ctx, p, p, 8); EVP_CIPHER_CTX_free(des_ctx); memset (deskey, 0, sizeof(deskey)); memset (&schedule, 0, sizeof(schedule)); seq = p; _gsskrb5_decode_om_uint32(seq, &seq_number); if (context_handle->more_flags & LOCAL) cmp = ct_memcmp(&seq[4], "\xff\xff\xff\xff", 4); else cmp = ct_memcmp(&seq[4], "\x00\x00\x00\x00", 4); if (cmp != 0) { HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return GSS_S_BAD_MIC; } ret = _gssapi_msg_order_check(context_handle->order, seq_number); if (ret) { HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); return ret; } HEIMDAL_MUTEX_unlock(&context_handle->ctx_id_mutex); /* copy out data */ output_message_buffer->length = input_message_buffer->length - len - padlength - 8; output_message_buffer->value = malloc(output_message_buffer->length); if(output_message_buffer->length != 0 && output_message_buffer->value == NULL) return GSS_S_FAILURE; memcpy (output_message_buffer->value, p + 24, output_message_buffer->length); return GSS_S_COMPLETE; }