diff options
Diffstat (limited to 'crypto/heimdal/lib/gssapi/wrap.c')
-rw-r--r-- | crypto/heimdal/lib/gssapi/wrap.c | 305 |
1 files changed, 273 insertions, 32 deletions
diff --git a/crypto/heimdal/lib/gssapi/wrap.c b/crypto/heimdal/lib/gssapi/wrap.c index c71f2b1..1d9f51d 100644 --- a/crypto/heimdal/lib/gssapi/wrap.c +++ b/crypto/heimdal/lib/gssapi/wrap.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,9 +33,26 @@ #include "gssapi_locl.h" -RCSID("$Id: wrap.c,v 1.11 2000/01/25 23:15:44 assar Exp $"); +RCSID("$Id: wrap.c,v 1.15 2001/01/29 02:08:59 assar Exp $"); -OM_uint32 gss_wrap_size_limit ( +static OM_uint32 +sub_wrap_size ( + OM_uint32 req_output_size, + OM_uint32 * max_input_size, + int blocksize, + int extrasize + ) +{ + size_t len, total_len, padlength; + padlength = blocksize - (req_output_size % blocksize); + len = req_output_size + 8 + padlength + extrasize; + gssapi_krb5_encap_length(len, &len, &total_len); + *max_input_size = (OM_uint32)total_len; + return GSS_S_COMPLETE; +} + +OM_uint32 +gss_wrap_size_limit ( OM_uint32 * minor_status, const gss_ctx_id_t context_handle, int conf_req_flag, @@ -44,36 +61,58 @@ OM_uint32 gss_wrap_size_limit ( OM_uint32 * max_input_size ) { - size_t len, total_len, padlength; - padlength = 8 - (req_output_size % 8); - len = req_output_size + 8 + padlength + 22; - gssapi_krb5_encap_length(len, &len, &total_len); - *max_input_size = (OM_uint32)total_len; - return GSS_S_COMPLETE; + 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 = sub_wrap_size(req_output_size, max_input_size, 8, 22); + break; + case KEYTYPE_DES3 : + ret = sub_wrap_size(req_output_size, max_input_size, 8, 34); + break; + default : + *minor_status = KRB5_PROG_ETYPE_NOSUPP; + ret = GSS_S_FAILURE; + break; + } + krb5_free_keyblock (gssapi_krb5_context, key); + return ret; } -OM_uint32 gss_wrap +static OM_uint32 +wrap_des (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 + gss_buffer_t output_message_buffer, + krb5_keyblock *key ) { u_char *p; MD5_CTX md5; u_char hash[16]; des_key_schedule schedule; - des_cblock key; + des_cblock deskey; des_cblock zero; int i; int32_t seq_number; - size_t len, total_len, padlength; + size_t len, total_len, padlength, datalen; padlength = 8 - (input_message_buffer->length % 8); - len = input_message_buffer->length + 8 + padlength + 22; + datalen = input_message_buffer->length + padlength + 8; + len = datalen + 22; gssapi_krb5_encap_length (len, &len, &total_len); output_message_buffer->length = total_len; @@ -83,8 +122,7 @@ OM_uint32 gss_wrap p = gssapi_krb5_make_header(output_message_buffer->value, len, - "\x02\x01"); - + "\x02\x01"); /* TOK_ID */ /* SGN_ALG */ memcpy (p, "\x00\x00", 2); @@ -110,15 +148,15 @@ OM_uint32 gss_wrap memset (p + 8 + input_message_buffer->length, padlength, padlength); /* checksum */ - MD5Init (&md5); - MD5Update (&md5, p - 24, 8); - MD5Update (&md5, p, input_message_buffer->length + padlength + 8); - MD5Final (hash, &md5); + MD5_Init (&md5); + MD5_Update (&md5, p - 24, 8); + MD5_Update (&md5, p, datalen); + 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); memcpy (p - 8, hash, 8); @@ -136,8 +174,8 @@ OM_uint32 gss_wrap (context_handle->more_flags & LOCAL) ? 0 : 0xFF, 4); - 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 *)(p + 8), DES_ENCRYPT); krb5_auth_setlocalseqnumber (gssapi_krb5_context, @@ -148,22 +186,225 @@ OM_uint32 gss_wrap p += 16; if(conf_req_flag) { - 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, - 8 + input_message_buffer->length + padlength, + datalen, schedule, &zero, DES_ENCRYPT); - memset (key, 0, sizeof(key)); + memset (deskey, 0, sizeof(deskey)); memset (schedule, 0, sizeof(schedule)); } if(conf_state != NULL) *conf_state = conf_req_flag; return GSS_S_COMPLETE; } + +static OM_uint32 +wrap_des3 + (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 + ) +{ + u_char *p; + u_char seq[8]; + int32_t seq_number; + size_t len, total_len, padlength, datalen; + u_int32_t ret; + krb5_crypto crypto; + Checksum cksum; + krb5_data encdata; + + padlength = 8 - (input_message_buffer->length % 8); + datalen = input_message_buffer->length + padlength + 8; + len = datalen + 34; + gssapi_krb5_encap_length (len, &len, &total_len); + + output_message_buffer->length = total_len; + output_message_buffer->value = malloc (total_len); + if (output_message_buffer->value == NULL) + return GSS_S_FAILURE; + + p = gssapi_krb5_make_header(output_message_buffer->value, + len, + "\x02\x01"); /* TOK_ID */ + + /* SGN_ALG */ + memcpy (p, "\x04\x00", 2); /* HMAC SHA1 DES3-KD */ + p += 2; + /* SEAL_ALG */ + if(conf_req_flag) + memcpy (p, "\x02\x00", 2); /* DES3-KD */ + else + memcpy (p, "\xff\xff", 2); + p += 2; + /* Filler */ + memcpy (p, "\xff\xff", 2); + p += 2; + + /* calculate checksum (the above + confounder + data + pad) */ + + memcpy (p + 20, p - 8, 8); + des_new_random_key((des_cblock*)(p + 28)); + memcpy (p + 28 + 8, input_message_buffer->value, + input_message_buffer->length); + memset (p + 28 + 8 + input_message_buffer->length, padlength, padlength); + + ret = krb5_crypto_init(gssapi_krb5_context, key, 0, &crypto); + if (ret) { + free (output_message_buffer->value); + *minor_status = ret; + return GSS_S_FAILURE; + } + + ret = krb5_create_checksum (gssapi_krb5_context, + crypto, + KRB5_KU_USAGE_SIGN, + p + 20, + datalen + 8, + &cksum); + krb5_crypto_destroy (gssapi_krb5_context, crypto); + if (ret) { + free (output_message_buffer->value); + *minor_status = ret; + return GSS_S_FAILURE; + } + + /* zero out SND_SEQ + SGN_CKSUM in case */ + memset (p, 0, 28); + + memcpy (p + 8, cksum.checksum.data, cksum.checksum.length); + free_Checksum (&cksum); + + /* sequence number */ + krb5_auth_getlocalseqnumber (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) ? 0 : 0xFF, + 4); + + + ret = krb5_crypto_init(gssapi_krb5_context, key, ETYPE_DES3_CBC_NONE_IVEC, + &crypto); + if (ret) { + free (output_message_buffer->value); + *minor_status = ret; + return GSS_S_FAILURE; + } + + { + des_cblock ivec; + + memcpy (&ivec, p + 8, 8); + ret = krb5_encrypt_ivec (gssapi_krb5_context, + crypto, + KRB5_KU_USAGE_SEQ, + seq, 8, &encdata, + &ivec); + } + krb5_crypto_destroy (gssapi_krb5_context, crypto); + if (ret) { + free (output_message_buffer->value); + *minor_status = ret; + return GSS_S_FAILURE; + } + + assert (encdata.length == 8); + + memcpy (p, encdata.data, encdata.length); + krb5_data_free (&encdata); + + krb5_auth_setlocalseqnumber (gssapi_krb5_context, + context_handle->auth_context, + ++seq_number); + + /* encrypt the data */ + p += 28; + + if(conf_req_flag) { + krb5_data tmp; + + ret = krb5_crypto_init(gssapi_krb5_context, key, + ETYPE_DES3_CBC_NONE, &crypto); + if (ret) { + free (output_message_buffer->value); + *minor_status = ret; + return GSS_S_FAILURE; + } + ret = krb5_encrypt(gssapi_krb5_context, crypto, KRB5_KU_USAGE_SEAL, + p, datalen, &tmp); + krb5_crypto_destroy(gssapi_krb5_context, crypto); + if (ret) { + free (output_message_buffer->value); + *minor_status = ret; + return GSS_S_FAILURE; + } + assert (tmp.length == datalen); + + memcpy (p, tmp.data, datalen); + krb5_data_free(&tmp); + } + if(conf_state != NULL) + *conf_state = conf_req_flag; + return GSS_S_COMPLETE; +} + +OM_uint32 gss_wrap + (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; + 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 = wrap_des (minor_status, context_handle, conf_req_flag, + qop_req, input_message_buffer, conf_state, + output_message_buffer, key); + break; + case KEYTYPE_DES3 : + ret = wrap_des3 (minor_status, context_handle, conf_req_flag, + qop_req, input_message_buffer, conf_state, + output_message_buffer, key); + break; + default : + *minor_status = KRB5_PROG_ETYPE_NOSUPP; + ret = GSS_S_FAILURE; + break; + } + krb5_free_keyblock (gssapi_krb5_context, key); + return ret; +} |