From 4f979233c32b6d7a937e4b139c131935695d2d3e Mon Sep 17 00:00:00 2001 From: Sam Hartman Date: Fri, 26 Oct 2001 05:50:25 +0000 Subject: [PATCH] * Expose some rc4 crypto routines through the accessor mechanism; cleaner than raw enctype * Deal with GSSAPI key usage in microsoft translation * Add rc4 gssapi mechanism; works with itself, not tested against * Windows yet * Refactor large chunks of k5seal.c to make code more readable for debugging git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@13859 dc483132-0cff-0310-8789-dd5450dbe970 --- src/include/ChangeLog | 8 + src/include/k5-int.h | 18 +- src/lib/crypto/arcfour/ChangeLog | 4 + src/lib/crypto/arcfour/arcfour.c | 2 + src/lib/gssapi/krb5/ChangeLog | 40 +++ src/lib/gssapi/krb5/accept_sec_context.c | 14 + src/lib/gssapi/krb5/gssapiP_krb5.h | 9 +- src/lib/gssapi/krb5/init_sec_context.c | 15 ++ src/lib/gssapi/krb5/k5seal.c | 326 +++++++++++------------ src/lib/gssapi/krb5/k5unseal.c | 73 +++-- src/lib/gssapi/krb5/util_crypt.c | 67 ++++- src/lib/gssapi/krb5/util_seqnum.c | 40 ++- src/lib/krb5/os/ChangeLog | 4 + src/lib/krb5/os/accessor.c | 3 + 14 files changed, 425 insertions(+), 198 deletions(-) diff --git a/src/include/ChangeLog b/src/include/ChangeLog index 8d18c2c41..958dc2ab5 100644 --- a/src/include/ChangeLog +++ b/src/include/ChangeLog @@ -1,3 +1,11 @@ +2001-10-24 Sam Hartman + + * k5-int.h: Add declaration for arcfour enc_provider and md5 + hash_provider so we can get to these indirectly from libgssapi. + Ick. This is an evil hack but somewhat less evil than having raw + enctypes. + Add above to krb5int_access along with krb5_hmac function + 2001-10-24 Ezra Peisach * configure.in: Use of AC_DEFINE modified to include third diff --git a/src/include/k5-int.h b/src/include/k5-int.h index 9f7a78eba..34fe73795 100644 --- a/src/include/k5-int.h +++ b/src/include/k5-int.h @@ -623,6 +623,14 @@ krb5_error_code krb5_hmac krb5_const krb5_keyblock *key, unsigned int icount, krb5_const krb5_data *input, krb5_data *output); +/* + * These declarations are here, so both krb5 and k5crypto + * can get to them. + * krb5 needs to get to them so it can make them available to libgssapi. + */ +extern const struct krb5_enc_provider krb5int_enc_arcfour; +extern const struct krb5_hash_provider krb5int_hash_md5; + #ifdef KRB5_OLD_CRYPTO /* old provider api */ @@ -1512,7 +1520,7 @@ void krb5int_set_prompt_types /* To keep happy libraries which are (for now) accessing internal stuff */ /* Make sure to increment by one when changing the struct */ -#define KRB5INT_ACCESS_STRUCT_VERSION 3 +#define KRB5INT_ACCESS_STRUCT_VERSION 4 typedef struct _krb5int_access { krb5_error_code (*krb5_locate_kdc) (krb5_context, const krb5_data *, @@ -1526,7 +1534,13 @@ typedef struct _krb5int_access { unsigned int krb5_skdc_timeout_shift; unsigned int krb5_skdc_timeout_1; unsigned int krb5_max_dgram_size; -} krb5int_access; + const struct krb5_hash_provider *md5_hash_provider; + const struct krb5_enc_provider *arcfour_enc_provider; + krb5_error_code (* krb5_hmac) + (krb5_const struct krb5_hash_provider *hash, + krb5_const krb5_keyblock *key, unsigned int icount, + krb5_const krb5_data *input, krb5_data *output); + } krb5int_access; #define KRB5INT_ACCESS_VERSION \ (((krb5_int32)((sizeof(krb5int_access) & 0xFFFF) | \ diff --git a/src/lib/crypto/arcfour/ChangeLog b/src/lib/crypto/arcfour/ChangeLog index 335304a93..9f9cbc76a 100644 --- a/src/lib/crypto/arcfour/ChangeLog +++ b/src/lib/crypto/arcfour/ChangeLog @@ -1,3 +1,7 @@ +2001-10-25 Sam Hartman + + * arcfour.c: GSSAPI usage translations + 2001-10-24 Ezra Peisach * arcfour.h: Declare krb5int_enc_arcfour extern so that multiple diff --git a/src/lib/crypto/arcfour/arcfour.c b/src/lib/crypto/arcfour/arcfour.c index cc1857770..66c0bd335 100644 --- a/src/lib/crypto/arcfour/arcfour.c +++ b/src/lib/crypto/arcfour/arcfour.c @@ -55,6 +55,8 @@ case 7: /* tgs-req authenticator */ return 11; case 12: /* app-rep encrypted part */ return 12; + case 23: /* sign wrap token*/ + return 13; default: return usage; } diff --git a/src/lib/gssapi/krb5/ChangeLog b/src/lib/gssapi/krb5/ChangeLog index e40b3fc1f..d5aa402f7 100644 --- a/src/lib/gssapi/krb5/ChangeLog +++ b/src/lib/gssapi/krb5/ChangeLog @@ -1,3 +1,39 @@ +2001-10-25 Sam Hartman + + * k5unseal.c (kg_unseal_v1): same here. + + * k5seal.c (make_seal_token_v1): Factor out usage type we claim + for signatures so we can do something different for hmac-md5. + Microsoft uses a different usage number for mic tokens and wrap tokens. + + * k5unseal.c (kg_unseal_v1): Add arcfour checksum and decrypt support + + * util_seqnum.c (kg_get_seq_num): support arcfour_hmac + + * k5unseal.c (kg_unseal_v1): Get the sequence number before + decrypting the token so we can use it to decrypt arcfour + + * gssapiP_krb5.h util_crypt.c: New function kg_arcfour_docrypt + + * util_seqnum.c (kg_make_seq_num): Add rc4 support + + * k5seal.c (make_seal_token_v1): Simplify logic significantly. + Don't worry so much about only allocating memory we use; allocate + a full token all the time and only decide not to copy in data at + the last moment. This significantly simplifies the control flow, + giving better testing coverage and allowing better reasoning about + the code. Add arcfour-hmac support + + * util_crypt.c (kg_confounder_size): Special case arcfour to return 8 + +2001-10-24 Sam Hartman + + * accept_sec_context.c (krb5_gss_accept_sec_context): Support rc4 enctype + + * init_sec_context.c (krb5_gss_init_sec_context): Support rc4 enctype + + * gssapiP_krb5.h: Remove claim we don't support Microsoft sign alg + 2001-10-09 Ken Raeburn * gssapiP_krb5.h, gssapi_krb5.h, k5mech.c: Make prototypes @@ -1487,3 +1523,7 @@ Wed Aug 17 15:47:26 1994 Theodore Y. Ts'o (tytso at tsx-11) * gssapi_krb5.c: Fixed OID for the krb5 mechanism. (Transcription error.) + + + + diff --git a/src/lib/gssapi/krb5/accept_sec_context.c b/src/lib/gssapi/krb5/accept_sec_context.c index a3d4a7337..3cc291d80 100644 --- a/src/lib/gssapi/krb5/accept_sec_context.c +++ b/src/lib/gssapi/krb5/accept_sec_context.c @@ -628,6 +628,20 @@ krb5_gss_accept_sec_context(minor_status, context_handle, } break; + case ENCTYPE_ARCFOUR_HMAC: + ctx->signalg = SGN_ALG_HMAC_MD5 ; + ctx->cksum_size = 8; + ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ; + + code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc); + if (code) + goto fail; + code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq); + if (code) { + krb5_free_keyblock (context, ctx->enc); + goto fail; + } + break; default: code = KRB5_BAD_ENCTYPE; diff --git a/src/lib/gssapi/krb5/gssapiP_krb5.h b/src/lib/gssapi/krb5/gssapiP_krb5.h index 634b9e6b8..238ce2507 100644 --- a/src/lib/gssapi/krb5/gssapiP_krb5.h +++ b/src/lib/gssapi/krb5/gssapiP_krb5.h @@ -108,14 +108,14 @@ enum sgn_alg { SGN_ALG_MD2_5 = 0x0001, SGN_ALG_DES_MAC = 0x0002, SGN_ALG_3 = 0x0003, /* not published */ - SGN_ALG_HMAC_MD5 = 0x0011, /* microsoft w2k; no support */ + SGN_ALG_HMAC_MD5 = 0x0011, /* microsoft w2k; */ SGN_ALG_HMAC_SHA1_DES3_KD = 0x0004 }; enum seal_alg { SEAL_ALG_NONE = 0xffff, SEAL_ALG_DES = 0x0000, SEAL_ALG_1 = 0x0001, /* not published */ - SEAL_ALG_MICROSOFT_RC4 = 0x0010, /* microsoft w2k; no support */ + SEAL_ALG_MICROSOFT_RC4 = 0x0010, /* microsoft w2k; */ SEAL_ALG_DES3KD = 0x0002 }; @@ -248,6 +248,11 @@ krb5_error_code kg_encrypt (krb5_context context, krb5_pointer in, krb5_pointer out, int length); +krb5_error_code +kg_arcfour_docrypt (const krb5_keyblock *longterm_key , int ms_usage, + const unsigned char *kd_data, size_t kd_data_len, + const unsigned char *input_buf, size_t input_len, + unsigned char *output_buf); krb5_error_code kg_decrypt (krb5_context context, krb5_keyblock *key, int usage, diff --git a/src/lib/gssapi/krb5/init_sec_context.c b/src/lib/gssapi/krb5/init_sec_context.c index a39372ff0..6a88a4ebc 100644 --- a/src/lib/gssapi/krb5/init_sec_context.c +++ b/src/lib/gssapi/krb5/init_sec_context.c @@ -353,6 +353,7 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, #if 1 ENCTYPE_DES3_CBC_SHA1, #endif + ENCTYPE_ARCFOUR_HMAC, ENCTYPE_DES_CBC_CRC, ENCTYPE_DES_CBC_MD5, ENCTYPE_DES_CBC_MD4, 0 @@ -565,6 +566,20 @@ krb5_gss_init_sec_context(minor_status, claimant_cred_handle, goto fail; } break; + case ENCTYPE_ARCFOUR_HMAC: + ctx->signalg = SGN_ALG_HMAC_MD5 ; + ctx->cksum_size = 8; + ctx->sealalg = SEAL_ALG_MICROSOFT_RC4 ; + + code = krb5_copy_keyblock (context, ctx->subkey, &ctx->enc); + if (code) + goto fail; + code = krb5_copy_keyblock (context, ctx->subkey, &ctx->seq); + if (code) { + krb5_free_keyblock (context, ctx->enc); + goto fail; + } + break; #if 0 case ENCTYPE_DES3_CBC_MD5: enctype = ENCTYPE_DES3_CBC_RAW; diff --git a/src/lib/gssapi/krb5/k5seal.c b/src/lib/gssapi/krb5/k5seal.c index 9c718f073..a8b10f6a5 100644 --- a/src/lib/gssapi/krb5/k5seal.c +++ b/src/lib/gssapi/krb5/k5seal.c @@ -48,6 +48,8 @@ #include "gssapiP_krb5.h" +#include + static krb5_error_code make_seal_token_v1 (krb5_context context, krb5_keyblock *enc, @@ -70,82 +72,67 @@ make_seal_token_v1 (krb5_context context, krb5_data plaind; krb5_checksum md5cksum; krb5_checksum cksum; - int conflen=0, tmsglen, tlen; + /* msglen contains the message length + * we are signing/encrypting. tmsglen + * contains the length of the message + * we plan to write out to the token. + * tlen is the length of the token + * including header. */ + unsigned conflen=0, tmsglen, tlen, msglen; unsigned char *t, *ptr; + unsigned char *plain; + unsigned char pad; + krb5_keyusage sign_usage = KG_USAGE_SIGN; - int encblksize, sumblksize; - - switch (signalg) { - case SGN_ALG_DES_MAC_MD5: - case SGN_ALG_MD2_5: - case SGN_ALG_HMAC_MD5: - sumblksize = 1; - break; - case SGN_ALG_DES_MAC: - sumblksize = 8; - break; - case SGN_ALG_HMAC_SHA1_DES3_KD: - sumblksize = 1; - break; - default: - abort (); - return 123; /* find error code */ - } - - switch (sealalg) { - case SEAL_ALG_NONE: - case SEAL_ALG_DES: - case SEAL_ALG_DES3KD: - encblksize = 8; - break; - default: - abort (); - return 12345654; - } + assert((!encrypt) || (toktype == KG_TOK_SEAL_MSG)); /* create the token buffer */ - + /* Do we need confounder? */ + if (encrypt || (!bigend && (toktype == KG_TOK_SEAL_MSG))) + conflen = kg_confounder_size(context, enc); + else conflen = 0; if (toktype == KG_TOK_SEAL_MSG) { - if (bigend && !encrypt) { - tmsglen = text->length; - } else { - conflen = kg_confounder_size(context, enc); - /* XXX knows that des block size is 8 */ - tmsglen = (conflen+text->length+8)&(~7); - } + switch (sealalg) { + case SEAL_ALG_MICROSOFT_RC4: + msglen = conflen + text->length+1; + pad = 1; + break; + default: + /* XXX knows that des block size is 8 */ + msglen = (conflen+text->length+8)&(~7); + pad = 8-(text->length%8); + } + tmsglen = msglen; } else { - tmsglen = 0; + tmsglen = 0; + msglen = text->length; + pad = 0; } - tlen = g_token_size((gss_OID) oid, 14+cksum_size+tmsglen); if ((t = (unsigned char *) xmalloc(tlen)) == NULL) - return(ENOMEM); + return(ENOMEM); /*** fill in the token */ ptr = t; - g_make_token_header((gss_OID) oid, 14+cksum_size+tmsglen, &ptr, toktype); /* 0..1 SIGN_ALG */ - ptr[0] = signalg & 0xff; ptr[1] = (signalg >> 8) & 0xff; /* 2..3 SEAL_ALG or Filler */ - if ((toktype == KG_TOK_SEAL_MSG) && encrypt) { - ptr[2] = sealalg & 0xff; - ptr[3] = (sealalg >> 8) & 0xff; + ptr[2] = sealalg & 0xff; + ptr[3] = (sealalg >> 8) & 0xff; } else { - /* No seal */ - ptr[2] = 0xff; - ptr[3] = 0xff; + /* No seal */ + ptr[2] = 0xff; + ptr[3] = 0xff; } /* 4..5 Filler */ - ptr[4] = 0xff; ptr[5] = 0xff; @@ -155,145 +142,100 @@ make_seal_token_v1 (krb5_context context, switch (signalg) { case SGN_ALG_DES_MAC_MD5: case SGN_ALG_MD2_5: - case SGN_ALG_HMAC_MD5: - md5cksum.checksum_type = CKSUMTYPE_RSA_MD5; - break; + md5cksum.checksum_type = CKSUMTYPE_RSA_MD5; + break; case SGN_ALG_HMAC_SHA1_DES3_KD: - md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3; - break; + md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3; + break; + case SGN_ALG_HMAC_MD5: + md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR; + if (!encrypt) + sign_usage = 15; + break; default: case SGN_ALG_DES_MAC: - abort (); + abort (); } code = krb5_c_checksum_length(context, md5cksum.checksum_type, &sumlen); if (code) - return(code); + return(code); md5cksum.length = sumlen; - if (toktype == KG_TOK_SEAL_MSG) { - unsigned char *plain; - unsigned char pad; - - if (!bigend || encrypt) { - if ((plain = (unsigned char *) xmalloc(tmsglen)) == NULL) { - xfree(t); - return(ENOMEM); - } - - if ((code = kg_make_confounder(context, enc, plain))) { - xfree(plain); - xfree(t); - return(code); - } - - memcpy(plain+conflen, text->value, text->length); - /* XXX 8 is DES cblock size */ - pad = 8-(text->length%8); - - memset(plain+conflen+text->length, pad, pad); - } else { - /* plain is never used in the bigend && !encrypt case */ - plain = NULL; - } - - if (encrypt) { - if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL, - (krb5_pointer) plain, - (krb5_pointer) (ptr+cksum_size+14), - tmsglen))) { - if (plain) - xfree(plain); - xfree(t); - return(code); - } - } else { - if (bigend) - memcpy(ptr+14+cksum_size, text->value, text->length); - else - memcpy(ptr+14+cksum_size, plain, tmsglen); - } + if ((plain = (unsigned char *) xmalloc(msglen)) == NULL) { + xfree(t); + return(ENOMEM); + } - /* compute the checksum */ + if (conflen) { + if ((code = kg_make_confounder(context, enc, plain))) { + xfree(plain); + xfree(t); + return(code); + } + } - /* 8 = head of token body as specified by mech spec */ - if (! (data_ptr = - (char *) xmalloc(8 + (bigend ? text->length : tmsglen)))) { - if (plain) - xfree(plain); - xfree(t); - return(ENOMEM); - } - (void) memcpy(data_ptr, ptr-2, 8); - if (bigend) - (void) memcpy(data_ptr+8, text->value, text->length); - else - (void) memcpy(data_ptr+8, plain, tmsglen); - plaind.length = 8 + (bigend ? text->length : tmsglen); - plaind.data = data_ptr; - code = krb5_c_make_checksum(context, md5cksum.checksum_type, seq, - KG_USAGE_SIGN, &plaind, &md5cksum); - xfree(data_ptr); - - if (code) { - if (plain) - xfree(plain); - xfree(t); - return(code); - } + memcpy(plain+conflen, text->value, text->length); + memset(plain+conflen+text->length, pad, pad); - if (plain) - xfree(plain); - } else { - /* Sign only. */ /* compute the checksum */ - if (! (data_ptr = (char *) xmalloc(8 + text->length))) { - xfree(t); - return(ENOMEM); - } - (void) memcpy(data_ptr, ptr-2, 8); - (void) memcpy(data_ptr+8, text->value, text->length); - plaind.length = 8 + text->length; - plaind.data = data_ptr; - code = krb5_c_make_checksum(context, md5cksum.checksum_type, seq, - KG_USAGE_SIGN, &plaind, &md5cksum); - xfree(data_ptr); - if (code) { - xfree(t); - return(code); - } + /* 8 = head of token body as specified by mech spec */ + if (! (data_ptr = + (char *) xmalloc(8 + (bigend ? text->length : tmsglen)))) { + xfree(plain); + xfree(t); + return(ENOMEM); } + (void) memcpy(data_ptr, ptr-2, 8); + if (bigend) + (void) memcpy(data_ptr+8, text->value, text->length); + else + (void) memcpy(data_ptr+8, plain, msglen); + plaind.length = 8 + (bigend ? text->length : msglen); + plaind.data = data_ptr; + code = krb5_c_make_checksum(context, md5cksum.checksum_type, seq, + sign_usage, &plaind, &md5cksum); + xfree(data_ptr); + if (code) { + xfree(plain); + xfree(t); + return(code); + } switch(signalg) { case SGN_ALG_DES_MAC_MD5: case 3: - if ((code = kg_encrypt(context, seq, KG_USAGE_SEAL, - (g_OID_equal(oid, gss_mech_krb5_old) ? - seq->contents : NULL), - md5cksum.contents, md5cksum.contents, 16))) { - krb5_free_checksum_contents(context, &md5cksum); - xfree(t); - return code; - } + if ((code = kg_encrypt(context, seq, KG_USAGE_SEAL, + (g_OID_equal(oid, gss_mech_krb5_old) ? + seq->contents : NULL), + md5cksum.contents, md5cksum.contents, 16))) { + krb5_free_checksum_contents(context, &md5cksum); + xfree (plain); + xfree(t); + return code; + } - cksum.length = cksum_size; - cksum.contents = md5cksum.contents + 16 - cksum.length; + cksum.length = cksum_size; + cksum.contents = md5cksum.contents + 16 - cksum.length; - memcpy(ptr+14, cksum.contents, cksum.length); - break; + memcpy(ptr+14, cksum.contents, cksum.length); + break; case SGN_ALG_HMAC_SHA1_DES3_KD: - /* - * Using key derivation, the call to krb5_c_make_checksum - * already dealt with encrypting. - */ - if (md5cksum.length != cksum_size) - abort (); - memcpy (ptr+14, md5cksum.contents, md5cksum.length); - break; + /* + * Using key derivation, the call to krb5_c_make_checksum + * already dealt with encrypting. + */ + if (md5cksum.length != cksum_size) + abort (); + memcpy (ptr+14, md5cksum.contents, md5cksum.length); + break; + case SGN_ALG_HMAC_MD5: + memcpy (ptr+14, md5cksum.contents, cksum_size); + break; } krb5_free_checksum_contents(context, &md5cksum); @@ -302,9 +244,61 @@ make_seal_token_v1 (krb5_context context, if ((code = kg_make_seq_num(context, seq, direction?0:0xff, *seqnum, ptr+14, ptr+6))) { - xfree(t); - return(code); + xfree (plain); + xfree(t); + return(code); + } + + if (encrypt) { + switch(sealalg) { + case SEAL_ALG_MICROSOFT_RC4: + { + unsigned char bigend_seqnum[4]; + krb5_keyblock *enc_key; + int i; + bigend_seqnum[0] = (*seqnum>>24) & 0xff; + bigend_seqnum[1] = (*seqnum>>16) & 0xff; + bigend_seqnum[2] = (*seqnum>>8) & 0xff; + bigend_seqnum[3] = *seqnum & 0xff; + code = krb5_copy_keyblock (context, enc, &enc_key); + if (code) + { + xfree(plain); + xfree(t); + return(code); + } + assert (enc_key->length == 16); + for (i = 0; i <= 15; i++) + ((char *) enc_key->contents)[i] ^=0xf0; + code = kg_arcfour_docrypt (enc_key, 0, + bigend_seqnum, 4, + plain, tmsglen, + ptr+14+cksum_size); + krb5_free_keyblock (context, enc_key); + if (code) + { + xfree(plain); + xfree(t); + return(code); + } + } + break; + default: + if ((code = kg_encrypt(context, enc, KG_USAGE_SEAL, NULL, + (krb5_pointer) plain, + (krb5_pointer) (ptr+cksum_size+14), + tmsglen))) { + xfree(plain); + xfree(t); + return(code); + } + } + }else { + if (tmsglen) + memcpy(ptr+14+cksum_size, plain, tmsglen); } + xfree(plain); + /* that's it. return the token */ diff --git a/src/lib/gssapi/krb5/k5unseal.c b/src/lib/gssapi/krb5/k5unseal.c index 8d77c4024..998068884 100644 --- a/src/lib/gssapi/krb5/k5unseal.c +++ b/src/lib/gssapi/krb5/k5unseal.c @@ -1,4 +1,5 @@ /* + * Copyright2001 by the Massachusetts Institute of Technology. * Copyright 1993 by OpenVision Technologies, Inc. * * Permission to use, copy, modify, distribute, and sell this software @@ -50,6 +51,7 @@ #ifdef HAVE_MEMORY_H #include #endif +#include /* message_buffer is an input if SIGN, output if SEAL, and ignored if DEL_CTX conf_state is only valid if SEAL. */ @@ -85,6 +87,7 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, krb5_int32 seqnum; OM_uint32 retval; size_t sumlen; + krb5_keyusage sign_usage = KG_USAGE_SIGN; if (toktype == KG_TOK_SEAL_MSG) { message_buffer->length = 0; @@ -125,7 +128,9 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, if ((ctx->sealalg == SEAL_ALG_NONE && signalg > 1) || (ctx->sealalg == SEAL_ALG_1 && signalg != SGN_ALG_3) || (ctx->sealalg == SEAL_ALG_DES3KD && - signalg != SGN_ALG_HMAC_SHA1_DES3_KD)) { + signalg != SGN_ALG_HMAC_SHA1_DES3_KD)|| + (ctx->sealalg == SEAL_ALG_MICROSOFT_RC4 && + signalg != SGN_ALG_HMAC_MD5)) { *minor_status = 0; return GSS_S_DEFECTIVE_TOKEN; } @@ -133,8 +138,11 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, switch (signalg) { case SGN_ALG_DES_MAC_MD5: case SGN_ALG_MD2_5: + case SGN_ALG_HMAC_MD5: cksum_len = 8; - break; + if (toktype != KG_TOK_SEAL_MSG) + sign_usage = 15; + break; case SGN_ALG_3: cksum_len = 16; break; @@ -151,6 +159,12 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, /* get the token parameters */ + if ((code = kg_get_seq_num(context, ctx->seq, ptr+14, ptr+6, &direction, + &seqnum))) { + *minor_status = code; + return(GSS_S_BAD_SIG); + } + /* decode the message, if SEAL */ if (toktype == KG_TOK_SEAL_MSG) { @@ -159,10 +173,36 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, *minor_status = ENOMEM; return(GSS_S_FAILURE); } - - if ((code = kg_decrypt(context, ctx->enc, KG_USAGE_SEAL, NULL, - ptr+14+cksum_len, plain, tmsglen))) { - xfree(plain); + if (ctx->enc->enctype == ENCTYPE_ARCFOUR_HMAC) { + unsigned char bigend_seqnum[4]; + krb5_keyblock *enc_key; + int i; + bigend_seqnum[0] = (seqnum>>24) & 0xff; + bigend_seqnum[1] = (seqnum>>16) & 0xff; + bigend_seqnum[2] = (seqnum>>8) & 0xff; + bigend_seqnum[3] = seqnum & 0xff; + code = krb5_copy_keyblock (context, ctx->enc, &enc_key); + if (code) + { + xfree(plain); + *minor_status = code; + return(GSS_S_FAILURE); + } + + assert (enc_key->length == 16); + for (i = 0; i <= 15; i++) + ((char *) enc_key->contents)[i] ^=0xf0; + code = kg_arcfour_docrypt (enc_key, 0, + &bigend_seqnum[0], 4, + ptr+14+cksum_len, tmsglen, + plain); + krb5_free_keyblock (context, enc_key); + } else { + code = kg_decrypt(context, ctx->enc, KG_USAGE_SEAL, NULL, + ptr+14+cksum_len, plain, tmsglen); + } + if (code) { + xfree(plain); *minor_status = code; return(GSS_S_FAILURE); } @@ -205,11 +245,13 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, switch (signalg) { case SGN_ALG_DES_MAC_MD5: case SGN_ALG_MD2_5: - case SGN_ALG_HMAC_MD5: case SGN_ALG_DES_MAC: case SGN_ALG_3: md5cksum.checksum_type = CKSUMTYPE_RSA_MD5; break; + case SGN_ALG_HMAC_MD5: + md5cksum.checksum_type = CKSUMTYPE_HMAC_MD5_ARCFOUR; + break; case SGN_ALG_HMAC_SHA1_DES3_KD: md5cksum.checksum_type = CKSUMTYPE_HMAC_SHA1_DES3; break; @@ -249,7 +291,7 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, plaind.length = 8 + (ctx->big_endian ? token.length : plainlen); plaind.data = data_ptr; code = krb5_c_make_checksum(context, md5cksum.checksum_type, - ctx->seq, KG_USAGE_SIGN, + ctx->seq, sign_usage, &plaind, &md5cksum); xfree(data_ptr); @@ -316,7 +358,7 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, plaind.data = data_ptr; krb5_free_checksum_contents(context, &md5cksum); code = krb5_c_make_checksum(context, md5cksum.checksum_type, - ctx->seq, KG_USAGE_SIGN, + ctx->seq, sign_usage, &plaind, &md5cksum); xfree(data_ptr); @@ -337,6 +379,7 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, return(GSS_S_DEFECTIVE_TOKEN); case SGN_ALG_HMAC_SHA1_DES3_KD: + case SGN_ALG_HMAC_MD5: /* compute the checksum of the message */ /* 8 = bytes of token body to be checksummed according to spec */ @@ -361,7 +404,7 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, plaind.length = 8 + (ctx->big_endian ? token.length : plainlen); plaind.data = data_ptr; code = krb5_c_make_checksum(context, md5cksum.checksum_type, - ctx->seq, KG_USAGE_SIGN, + ctx->seq, sign_usage, &plaind, &md5cksum); xfree(data_ptr); @@ -372,7 +415,7 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, return(GSS_S_FAILURE); } - code = memcmp(md5cksum.contents, ptr+14, md5cksum.length); + code = memcmp(md5cksum.contents, ptr+14, cksum_len); break; } @@ -413,14 +456,6 @@ kg_unseal_v1(context, minor_status, ctx, ptr, bodysize, message_buffer, /* do sequencing checks */ - if ((code = kg_get_seq_num(context, ctx->seq, ptr+14, ptr+6, &direction, - &seqnum))) { - if (toktype == KG_TOK_SEAL_MSG) - xfree(token.value); - *minor_status = code; - return(GSS_S_BAD_SIG); - } - if ((ctx->initiate && direction != 0xff) || (!ctx->initiate && direction != 0)) { if (toktype == KG_TOK_SEAL_MSG) diff --git a/src/lib/gssapi/krb5/util_crypt.c b/src/lib/gssapi/krb5/util_crypt.c index a08b91982..424da90b3 100644 --- a/src/lib/gssapi/krb5/util_crypt.c +++ b/src/lib/gssapi/krb5/util_crypt.c @@ -1,4 +1,5 @@ /* + * Copyright2001 by the Massachusetts Institute of Technology. * Copyright 1993 by OpenVision Technologies, Inc. * * Permission to use, copy, modify, distribute, and sell this software @@ -59,7 +60,9 @@ kg_confounder_size(context, key) { krb5_error_code code; size_t blocksize; - + /* We special case rc4*/ + if (key->enctype == ENCTYPE_ARCFOUR_HMAC) + return 8; code = krb5_c_block_size(context, key->enctype, &blocksize); if (code) return(-1); /* XXX */ @@ -189,3 +192,65 @@ kg_decrypt(context, key, usage, iv, in, out, length) free(pivd->data); return code; } + +krb5_error_code +kg_arcfour_docrypt (const krb5_keyblock *longterm_key , int ms_usage, + const unsigned char *kd_data, size_t kd_data_len, + const unsigned char *input_buf, size_t input_len, + unsigned char *output_buf) +{ + krb5_error_code code; + krb5_data input, output; + krb5int_access kaccess; + krb5_keyblock seq_enc_key, usage_key; + unsigned char t[4]; + + usage_key.length = longterm_key->length; + usage_key.contents = malloc(usage_key.length); + if (usage_key.contents == NULL) + return (ENOMEM); + seq_enc_key.length = longterm_key->length; + seq_enc_key.contents = malloc(seq_enc_key.length); + if (seq_enc_key.contents == NULL) { + free ((void *) usage_key.contents); + return (ENOMEM); + } + code = krb5int_accessor (&kaccess, KRB5INT_ACCESS_VERSION); + if (code) + goto cleanup_arcfour; + + t[0] = ms_usage &0xff; + t[1] = (ms_usage>>8) & 0xff; + t[2] = (ms_usage>>16) & 0xff; + t[3] = (ms_usage>>24) & 0xff; + input.data = (void *) &t; + input.length = 4; + output.data = (void *) usage_key.contents; + output.length = usage_key.length; + code = (*kaccess.krb5_hmac) (kaccess.md5_hash_provider, + longterm_key, 1, &input, &output); + if (code) + goto cleanup_arcfour; + + input.data = ( void *) kd_data; + input.length = kd_data_len; + output.data = (void *) seq_enc_key.contents; + code = (*kaccess.krb5_hmac) (kaccess.md5_hash_provider, + &usage_key, 1, &input, &output); + if (code) + goto cleanup_arcfour; + input.data = ( void * ) input_buf; + input.length = input_len; + output.data = (void * ) output_buf; + output.length = input_len; + code = ((*kaccess.arcfour_enc_provider->encrypt)( + &seq_enc_key, 0, + &input, &output)); + cleanup_arcfour: + memset ((void *) seq_enc_key.contents, 0, seq_enc_key.length); + memset ((void *) usage_key.contents, 0, usage_key.length); + free ((void *) usage_key.contents); + free ((void *) seq_enc_key.contents); + return (code); +} + diff --git a/src/lib/gssapi/krb5/util_seqnum.c b/src/lib/gssapi/krb5/util_seqnum.c index 7c52c7fa7..4b44b8e5c 100644 --- a/src/lib/gssapi/krb5/util_seqnum.c +++ b/src/lib/gssapi/krb5/util_seqnum.c @@ -1,4 +1,5 @@ /* + * Copyright2001 by the Massachusetts Institute of Technology. * Copyright 1993 by OpenVision Technologies, Inc. * * Permission to use, copy, modify, distribute, and sell this software @@ -21,6 +22,7 @@ */ #include "gssapiP_krb5.h" +#include "k5-int.h" /* * $Id$ @@ -37,15 +39,27 @@ kg_make_seq_num(context, key, direction, seqnum, cksum, buf) { unsigned char plain[8]; - plain[0] = (unsigned char) (seqnum&0xff); - plain[1] = (unsigned char) ((seqnum>>8)&0xff); - plain[2] = (unsigned char) ((seqnum>>16)&0xff); - plain[3] = (unsigned char) ((seqnum>>24)&0xff); - plain[4] = direction; plain[5] = direction; plain[6] = direction; plain[7] = direction; + if (key->enctype == ENCTYPE_ARCFOUR_HMAC ) { + /* Yes, Microsoft used big-endian sequence number.*/ + plain[0] = (seqnum>>24) & 0xff; + plain[1] = (seqnum>>16) & 0xff; + plain[2] = (seqnum>>8) & 0xff; + plain[3] = seqnum & 0xff; + return kg_arcfour_docrypt (key, 0, + cksum, 8, + &plain[0], 8, + buf); + + } + + plain[0] = (unsigned char) (seqnum&0xff); + plain[1] = (unsigned char) ((seqnum>>8)&0xff); + plain[2] = (unsigned char) ((seqnum>>16)&0xff); + plain[3] = (unsigned char) ((seqnum>>24)&0xff); return(kg_encrypt(context, key, KG_USAGE_SEQ, cksum, plain, buf, 8)); } @@ -61,7 +75,14 @@ krb5_error_code kg_get_seq_num(context, key, cksum, buf, direction, seqnum) krb5_error_code code; unsigned char plain[8]; - code = kg_decrypt(context, key, KG_USAGE_SEQ, cksum, buf, plain, 8); + if (key->enctype == ENCTYPE_ARCFOUR_HMAC) { + code = kg_arcfour_docrypt (key, 0, + cksum, 8, + buf, 8, + plain); + } else { + code = kg_decrypt(context, key, KG_USAGE_SEQ, cksum, buf, plain, 8); + } if (code) return(code); @@ -71,11 +92,14 @@ krb5_error_code kg_get_seq_num(context, key, cksum, buf, direction, seqnum) return((krb5_error_code) KG_BAD_SEQ); *direction = plain[4]; - - *seqnum = ((plain[0]) | + if (key->enctype == ENCTYPE_ARCFOUR_HMAC) { + *seqnum = (plain[3]|(plain[2]<<8) | (plain[1]<<16)| (plain[0]<<24)); + } else { + *seqnum = ((plain[0]) | (plain[1]<<8) | (plain[2]<<16) | (plain[3]<<24)); + } return(0); } diff --git a/src/lib/krb5/os/ChangeLog b/src/lib/krb5/os/ChangeLog index fdb247c6e..2926e6994 100644 --- a/src/lib/krb5/os/ChangeLog +++ b/src/lib/krb5/os/ChangeLog @@ -1,3 +1,7 @@ +2001-10-24 Sam Hartman + + * accessor.c (krb5int_accessor): Add fields for struct version 4 + 2001-10-17 Ken Raeburn * locate_kdc.c (add_host_to_list): If sa_len field exists and is diff --git a/src/lib/krb5/os/accessor.c b/src/lib/krb5/os/accessor.c index 64fd5089c..5e77051a6 100644 --- a/src/lib/krb5/os/accessor.c +++ b/src/lib/krb5/os/accessor.c @@ -44,6 +44,9 @@ krb5int_accessor(internals, version) internals_temp.krb5_skdc_timeout_shift = krb5_skdc_timeout_shift; internals_temp.krb5_skdc_timeout_1 = krb5_skdc_timeout_1; internals_temp.krb5_max_dgram_size = krb5_max_dgram_size; + internals_temp.krb5_hmac = krb5_hmac; + internals_temp.md5_hash_provider = &krb5int_hash_md5; + internals_temp.arcfour_enc_provider = &krb5int_enc_arcfour; *internals = internals_temp; return 0; } -- 2.26.2