diff options
Diffstat (limited to 'crypto/heimdal/lib/gssapi/unwrap.c')
-rw-r--r-- | crypto/heimdal/lib/gssapi/unwrap.c | 266 |
1 files changed, 241 insertions, 25 deletions
diff --git a/crypto/heimdal/lib/gssapi/unwrap.c b/crypto/heimdal/lib/gssapi/unwrap.c index 210bab1..588517e 100644 --- a/crypto/heimdal/lib/gssapi/unwrap.c +++ b/crypto/heimdal/lib/gssapi/unwrap.c @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997 - 2000 Kungliga Tekniska Högskolan + * Copyright (c) 1997 - 2001 Kungliga Tekniska Högskolan * (Royal Institute of Technology, Stockholm, Sweden). * All rights reserved. * @@ -33,11 +33,11 @@ #include "gssapi_locl.h" -RCSID("$Id: unwrap.c,v 1.11 2000/01/25 23:13:38 assar Exp $"); +RCSID("$Id: unwrap.c,v 1.15 2001/01/29 02:08:58 assar Exp $"); OM_uint32 gss_krb5_getsomekey(const gss_ctx_id_t context_handle, - des_cblock *key) + krb5_keyblock **key) { /* XXX this is ugly, and probably incorrect... */ krb5_keyblock *skey; @@ -54,18 +54,19 @@ gss_krb5_getsomekey(const gss_ctx_id_t context_handle, &skey); if(skey == NULL) return GSS_S_FAILURE; - memcpy(key, skey->keyvalue.data, sizeof(*key)); - krb5_free_keyblock(gssapi_krb5_context, skey); + *key = skey; return 0; } -OM_uint32 gss_unwrap +static OM_uint32 +unwrap_des (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 + gss_qop_t * qop_state, + krb5_keyblock *key ) { u_char *p, *pad; @@ -73,7 +74,7 @@ OM_uint32 gss_unwrap MD5_CTX md5; u_char hash[16], seq_data[8]; des_key_schedule schedule; - des_cblock key; + des_cblock deskey; des_cblock zero; int i; int32_t seq_number; @@ -109,19 +110,20 @@ OM_uint32 gss_unwrap if(cstate) { /* decrypt data */ - gss_krb5_getsomekey(context_handle, &key); - for (i = 0; i < sizeof(key); ++i) - key[i] ^= 0xf0; - des_set_key (&key, schedule); + 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 ((const void *)p, + des_cbc_encrypt ((void *)p, (void *)p, input_message_buffer->length - len, schedule, &zero, DES_DECRYPT); - memset (key, 0, sizeof(key)); + memset (deskey, 0, sizeof(deskey)); memset (schedule, 0, sizeof(schedule)); } /* check pad */ @@ -134,15 +136,15 @@ OM_uint32 gss_unwrap if (i != 0) return GSS_S_BAD_MIC; - MD5Init (&md5); - MD5Update (&md5, p - 24, 8); - MD5Update (&md5, p, input_message_buffer->length - len); - MD5Final (hash, &md5); + 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)); - gss_krb5_getsomekey(context_handle, &key); - des_set_key (&key, schedule); - des_cbc_cksum ((const void *)hash, (void *)hash, sizeof(hash), + 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; @@ -161,11 +163,11 @@ OM_uint32 gss_unwrap 4); p -= 16; - des_set_key (&key, schedule); - des_cbc_encrypt ((const void *)p, (void *)p, 8, + des_set_key (&deskey, schedule); + des_cbc_encrypt ((void *)p, (void *)p, 8, schedule, (des_cblock *)hash, DES_DECRYPT); - memset (key, 0, sizeof(key)); + memset (deskey, 0, sizeof(deskey)); memset (schedule, 0, sizeof(schedule)); if (memcmp (p, seq_data, 8) != 0) { @@ -179,7 +181,7 @@ OM_uint32 gss_unwrap /* copy out data */ output_message_buffer->length = input_message_buffer->length - - len - 8 - padlength; + - 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; @@ -188,3 +190,217 @@ OM_uint32 gss_unwrap output_message_buffer->length); return GSS_S_COMPLETE; } + +static OM_uint32 +unwrap_des3 + (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 *p, *pad; + size_t len; + u_char seq[8]; + krb5_data seq_data; + u_char cksum[20]; + int i; + int32_t seq_number; + size_t padlength; + OM_uint32 ret; + int cstate; + krb5_crypto crypto; + Checksum csum; + int cmp; + + p = input_message_buffer->value; + ret = gssapi_krb5_verify_header (&p, + input_message_buffer->length, + "\x02\x01"); + 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(gssapi_krb5_context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + ret = krb5_decrypt(gssapi_krb5_context, crypto, KRB5_KU_USAGE_SEAL, + p, input_message_buffer->length - len, &tmp); + krb5_crypto_destroy(gssapi_krb5_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 */ + + pad = (u_char *)input_message_buffer->value + input_message_buffer->length - 1; + padlength = *pad; + + for (i = padlength; i > 0 && *pad == padlength; i--, pad--) + ; + if (i != 0) + return GSS_S_BAD_MIC; + + /* verify sequence number */ + + krb5_auth_getremoteseqnumber (gssapi_krb5_context, + context_handle->auth_context, + &seq_number); + seq[0] = (seq_number >> 0) & 0xFF; + seq[1] = (seq_number >> 8) & 0xFF; + seq[2] = (seq_number >> 16) & 0xFF; + seq[3] = (seq_number >> 24) & 0xFF; + memset (seq + 4, + (context_handle->more_flags & LOCAL) ? 0xFF : 0, + 4); + + p -= 28; + + ret = krb5_crypto_init(gssapi_krb5_context, key, + ETYPE_DES3_CBC_NONE_IVEC, &crypto); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + { + des_cblock ivec; + + memcpy(&ivec, p + 8, 8); + ret = krb5_decrypt_ivec (gssapi_krb5_context, + crypto, + KRB5_KU_USAGE_SEQ, + p, 8, &seq_data, + &ivec); + } + krb5_crypto_destroy (gssapi_krb5_context, crypto); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + if (seq_data.length != 8) { + krb5_data_free (&seq_data); + return GSS_S_BAD_MIC; + } + + cmp = memcmp (seq, seq_data.data, seq_data.length); + krb5_data_free (&seq_data); + if (cmp != 0) { + return GSS_S_BAD_MIC; + } + + krb5_auth_setremoteseqnumber (gssapi_krb5_context, + context_handle->auth_context, + ++seq_number); + + /* 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(gssapi_krb5_context, key, 0, &crypto); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_verify_checksum (gssapi_krb5_context, crypto, + KRB5_KU_USAGE_SIGN, + p + 20, + input_message_buffer->length - len + 8, + &csum); + krb5_crypto_destroy (gssapi_krb5_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; +} + +OM_uint32 gss_unwrap + (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; + OM_uint32 ret; + krb5_keytype keytype; + + ret = gss_krb5_getsomekey(context_handle, &key); + if (ret) { + *minor_status = ret; + return GSS_S_FAILURE; + } + krb5_enctype_to_keytype (gssapi_krb5_context, key->keytype, &keytype); + + switch (keytype) { + case KEYTYPE_DES : + ret = unwrap_des (minor_status, context_handle, + input_message_buffer, output_message_buffer, + conf_state, qop_state, key); + break; + case KEYTYPE_DES3 : + ret = unwrap_des3 (minor_status, context_handle, + input_message_buffer, output_message_buffer, + conf_state, qop_state, key); + break; + default : + *minor_status = KRB5_PROG_ETYPE_NOSUPP; + ret = GSS_S_FAILURE; + break; + } + krb5_free_keyblock (gssapi_krb5_context, key); + return ret; +} |