From 708f7a7303a2d35da5e1250a0ec9da5ac170a95f Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Mon, 12 Sep 2011 15:44:07 -0400 Subject: [PATCH 138/150] - take a stab at the algorithm agility KDF, refactoring the 4556 version to use it --- src/plugins/preauth/pkinit/pkinit_crypto_nss.c | 124 +++++++++++++++++++++--- 1 files changed, 109 insertions(+), 15 deletions(-) diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c index 0132759..0c12545 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c @@ -419,6 +419,27 @@ static SECItem pkinit_nt_upn = { oid_pkinit_name_type_upn_bytes, 10, }; +static unsigned char oid_pkinit_kdf_sha1_bytes[] = + { 0x2b, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x01 }; +static SECItem pkinit_kdf_sha1 = { + siDEROID, + oid_pkinit_kdf_sha1_bytes, + 8, +}; +static unsigned char oid_pkinit_kdf_sha256_bytes[] = + { 0x2b, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x02 }; +static SECItem pkinit_kdf_sha256 = { + siDEROID, + oid_pkinit_kdf_sha256_bytes, + 8, +}; +static unsigned char oid_pkinit_kdf_sha512_bytes[] = + { 0x2b, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x03 }; +static SECItem pkinit_kdf_sha512 = { + siDEROID, + oid_pkinit_kdf_sha512_bytes, + 8, +}; static SECOidTag get_pkinit_data_auth_data_tag(void) @@ -3596,32 +3617,38 @@ pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx, return 0; } -/* Convert a DH secret to a keyblock. */ -krb5_error_code -pkinit_octetstring2key(krb5_context context, - krb5_enctype etype, - unsigned char *dh_key, - unsigned int dh_key_len, krb5_keyblock *krb5key) +/* Convert a DH secret to a keyblock using the specified digest and a + * big-endian counter of the specified length that starts at the specified + * value. */ +static krb5_error_code +pkinit_octetstring_hkdf(krb5_context context, + SECOidTag hash_alg, + int counter_start, size_t counter_length, + krb5_enctype etype, + unsigned char *dh_key, unsigned int dh_key_len, + krb5_keyblock *krb5key) { PK11Context *ctx; unsigned int left, length, rnd_len; - unsigned char c, buf[512]; /* the longest digest we support */ + unsigned char counter[8], buf[512]; /* the longest digest we support */ + int i; char *rnd_buf; size_t kbyte, klength; krb5_data rnd_data; krb5_error_code result; - SECOidTag hash_alg = SEC_OID_SHA1; + if (counter_length > sizeof(counter)) + return EINVAL; result = krb5_c_keylengths(context, etype, &kbyte, &klength); - if (result != 0) { + if (result != 0) return result; - } rnd_buf = malloc(dh_key_len); - if (rnd_buf == NULL) { + if (rnd_buf == NULL) return ENOMEM; - } - c = 0; + memset(counter, 0, sizeof(counter)); + for (i = sizeof(counter) - 1; i >= 0; i--) + counter[i] = (counter_start >> (8 * (counter_length - 1 - i))) & 0xff; rnd_len = kbyte; left = rnd_len; while (left > 0) { @@ -3639,7 +3666,7 @@ pkinit_octetstring2key(krb5_context context, free(rnd_buf); return ENOMEM; } - if (PK11_DigestOp(ctx, &c, 1) != SECSuccess) { + if (PK11_DigestOp(ctx, counter, counter_length) != SECSuccess) { PK11_DestroyContext(ctx, PR_TRUE); memset(buf, 0, sizeof(buf)); memset(rnd_buf, 0, dh_key_len); @@ -3666,7 +3693,11 @@ pkinit_octetstring2key(krb5_context context, } memcpy(rnd_buf + rnd_len - left, buf, length); left -= length; - c++; + for (i = counter_length - 1; i >= 0; i--) { + counter[i] = ((counter[i] + 1) & 0xff); + if (counter[i] != 0) + break; + } } krb5_free_keyblock_contents(context, krb5key); @@ -3690,6 +3721,69 @@ pkinit_octetstring2key(krb5_context context, return result; } +/* Convert a DH secret to a keyblock, RFC4556-style. */ +krb5_error_code +pkinit_octetstring2key(krb5_context context, + krb5_enctype etype, + unsigned char *dh_key, + unsigned int dh_key_len, krb5_keyblock *krb5key) +{ + return pkinit_octetstring_hkdf(context, + SEC_OID_SHA1, 0, 1, etype, + dh_key, dh_key_len, + krb5key); +} + +/* Return TRUE if the item and the "algorithm" part of the algorithm identifier + * are the same. */ +static PRBool +algorithm_id_and_item_equal(const krb5_algorithm_identifier *id, + const SECItem *item) +{ + if (id->algorithm.length != item->len) { + return FALSE; + } + return (memcmp(id->algorithm.data, item->data, item->len) == 0); +} + +/* Convert a DH secret to a keyblock using one of the key derivation functions + * in the list of passed-in algorithm identifiers. Set "kdf" to the index of + * the one which is actually used. Return ENOSYS if none are recognized. */ +static krb5_error_code +pkinit_octetstring_kdf(krb5_context context, + krb5_algorithm_identifier **ids, int n_ids, + int counter_start, size_t counter_length, + krb5_enctype etype, + unsigned char *dh_key, unsigned int dh_key_len, + int *kdf, krb5_keyblock *krb5key) +{ + int i; + for (i = 0; i < n_ids; i++) { + if (algorithm_id_and_item_equal(ids[i], &pkinit_kdf_sha512)) { + *kdf = i; + return pkinit_octetstring_hkdf(context, + SEC_OID_SHA512, 1, 4, etype, + dh_key, dh_key_len, + krb5key); + } + if (algorithm_id_and_item_equal(ids[i], &pkinit_kdf_sha256)) { + *kdf = i; + return pkinit_octetstring_hkdf(context, + SEC_OID_SHA256, 1, 4, etype, + dh_key, dh_key_len, + krb5key); + } + if (algorithm_id_and_item_equal(ids[i], &pkinit_kdf_sha1)) { + *kdf = i; + return pkinit_octetstring_hkdf(context, + SEC_OID_SHA1, 1, 4, etype, + dh_key, dh_key_len, + krb5key); + } + } + return ENOSYS; +} + static int cert_add_string(unsigned char ***list, int *count, int len, const unsigned char *value) -- 1.7.6.4