From 93807462c9d786c06a59df0a36dcc7ec60411ef7 Mon Sep 17 00:00:00 2001 From: Nalin Dahyabhai Date: Mon, 19 Sep 2011 14:07:02 -0400 Subject: [PATCH 142/150] - define KRB5KDC_ERR_NO_ACCEPTABLE_KDF if it isn't defined yet (temporary) - use external definitions of pkinit_kdf_sha{1,256,512}, drop ours - provide a slot for the additional data in HKDF - factor out the bits that compute the KDF OtherInfo structure - replace the KDF guess with one that matches the new openssl implementation --- src/plugins/preauth/pkinit/pkinit_crypto_nss.c | 187 +++++++++++++++--------- 1 files changed, 121 insertions(+), 66 deletions(-) diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c index f4e8d45..a689c9b 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_nss.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_nss.c @@ -86,6 +86,12 @@ * include a friendly name. */ #define PKCS12_PREFIX "pkinit-pkcs12" +#ifndef KRB5KDC_ERR_NO_ACCEPTABLE_KDF +#ifdef KRB5PLACEHOLD_82 +#define KRB5KDC_ERR_NO_ACCEPTABLE_KDF KRB5PLACEHOLD_82 +#endif +#endif + /* Forward declaration. */ static krb5_error_code cert_retrieve_cert_sans(krb5_context context, CERTCertificate *cert, @@ -419,27 +425,6 @@ 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) @@ -3618,15 +3603,16 @@ pkinit_identity_set_prompter(pkinit_identity_crypto_context id_cryptoctx, return 0; } -/* 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. */ +/* Convert a DH secret and optional data 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, + char *other_data, unsigned int other_data_len, krb5_keyblock *krb5key) { PK11Context *ctx; @@ -3681,6 +3667,15 @@ pkinit_octetstring_hkdf(krb5_context context, free(rnd_buf); return ENOMEM; } + if ((other_data_len > 0) && + (PK11_DigestOp(ctx, (const unsigned char *) other_data, + other_data_len) != SECSuccess)) { + PK11_DestroyContext(ctx, PR_TRUE); + krb5int_zap(buf, sizeof(buf)); + krb5int_zap(rnd_buf, dh_key_len); + free(rnd_buf); + return ENOMEM; + } if (PK11_DigestFinal(ctx, buf, &length, sizeof(buf)) != SECSuccess) { PK11_DestroyContext(ctx, PR_TRUE); krb5int_zap(buf, sizeof(buf)); @@ -3731,58 +3726,118 @@ pkinit_octetstring2key(krb5_context context, { return pkinit_octetstring_hkdf(context, SEC_OID_SHA1, 0, 1, etype, - dh_key, dh_key_len, + dh_key, dh_key_len, NULL, 0, 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) +octet_data_and_data_and_length_equal(const krb5_octet_data *octets, + const void *data, size_t len) { - if (id->algorithm.length != item->len) { - return FALSE; - } - return (memcmp(id->algorithm.data, item->data, item->len) == 0); + return (octets->length == len) && (memcmp(octets->data, data, 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. */ +/* Encode the other info used by the agility KDF. Taken almost verbatim from + * parts of the agility KDF in pkinit_crypto_openssl.c */ 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) +encode_agility_kdf_other_info(krb5_context context, + krb5_octet_data *alg_oid, + krb5_principal party_u_info, + krb5_principal party_v_info, + krb5_enctype enctype, + krb5_octet_data *as_req, + krb5_octet_data *pk_as_rep, + krb5_data **other_info) { - 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; + krb5_error_code retval = 0; + krb5_sp80056a_other_info other_info_fields; + krb5_pkinit_supp_pub_info supp_pub_info_fields; + krb5_data *supp_pub_info = NULL; + krb5_algorithm_identifier alg_id; + + /* Encode the ASN.1 octet string for "SuppPubInfo" */ + supp_pub_info_fields.enctype = enctype; + supp_pub_info_fields.as_req = *as_req; + supp_pub_info_fields.pk_as_rep = *pk_as_rep; + retval = encode_krb5_pkinit_supp_pub_info(&supp_pub_info_fields, + &supp_pub_info); + if (retval != 0) + goto cleanup; + + /* Now encode the ASN.1 octet string for "OtherInfo" */ + memset(&alg_id, 0, sizeof alg_id); + alg_id.algorithm = *alg_oid; /*alias, don't have to free it*/ + + other_info_fields.algorithm_identifier = alg_id; + other_info_fields.party_u_info = party_u_info; + other_info_fields.party_v_info = party_v_info; + other_info_fields.supp_pub_info = *supp_pub_info; + retval = encode_krb5_sp80056a_other_info(&other_info_fields, other_info); + if (retval != 0) + goto cleanup; + +cleanup: + krb5_free_data(context, supp_pub_info); + + return retval; +} + +/* Convert a DH secret to a keyblock using the key derivation function + * identified by the passed-in algorithm identifier. Return ENOSYS if it's not + * one that we support. */ +krb5_error_code +pkinit_alg_agility_kdf(krb5_context context, + krb5_octet_data *secret, + krb5_octet_data *alg_oid, + krb5_principal party_u_info, + krb5_principal party_v_info, + krb5_enctype enctype, + krb5_octet_data *as_req, + krb5_octet_data *pk_as_rep, + krb5_keyblock *key_block) +{ + krb5_data *other_info = NULL; + krb5_error_code retval = ENOSYS; + + retval = encode_agility_kdf_other_info(context, + alg_oid, party_u_info, party_v_info, + enctype, as_req, pk_as_rep, + &other_info); + if (retval != 0) + return retval; + + if (octet_data_and_data_and_length_equal(alg_oid, + krb5_pkinit_sha512_oid, + krb5_pkinit_sha512_oid_len)) + retval = pkinit_octetstring_hkdf(context, + SEC_OID_SHA512, 1, 4, enctype, + secret->data, secret->length, + other_info->data, other_info->length, + key_block); + else if (octet_data_and_data_and_length_equal(alg_oid, + krb5_pkinit_sha256_oid, + krb5_pkinit_sha256_oid_len)) + retval = pkinit_octetstring_hkdf(context, + SEC_OID_SHA256, 1, 4, enctype, + secret->data, secret->length, + other_info->data, other_info->length, + key_block); + else if (octet_data_and_data_and_length_equal(alg_oid, + krb5_pkinit_sha1_oid, + krb5_pkinit_sha1_oid_len)) + retval = pkinit_octetstring_hkdf(context, + SEC_OID_SHA1, 1, 4, enctype, + secret->data, secret->length, + other_info->data, other_info->length, + key_block); + else + retval = KRB5KDC_ERR_NO_ACCEPTABLE_KDF; + + krb5_free_data(context, other_info); + + return retval; } static int -- 1.7.6.4