diff options
author | Sam Hartman <hartmans@mit.edu> | 2011-09-21 18:40:16 +0000 |
---|---|---|
committer | Sam Hartman <hartmans@mit.edu> | 2011-09-21 18:40:16 +0000 |
commit | af2ddab839944028ef51d9ef393496063f454bea (patch) | |
tree | fcfae71ea2f257595d3572610ec3cc5592aad998 /src | |
parent | 013643be34ccfacd0be794ff55a89f609d576796 (diff) | |
download | krb5-af2ddab839944028ef51d9ef393496063f454bea.tar.gz krb5-af2ddab839944028ef51d9ef393496063f454bea.tar.xz krb5-af2ddab839944028ef51d9ef393496063f454bea.zip |
If the client offers the alg agility KDF, use it
Signed-off-by: Margaret Wasserman <mrw@painless-security.com>
pkinit: changes to call alg-agility KDF
git-svn-id: svn://anonsvn.mit.edu/krb5/trunk@25218 dc483132-0cff-0310-8789-dd5450dbe970
Diffstat (limited to 'src')
-rw-r--r-- | src/kdc/kdc_preauth.c | 2 | ||||
-rw-r--r-- | src/lib/krb5/error_tables/krb5_err.et | 2 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_clnt.c | 34 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_crypto.h | 9 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 5 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_kdf_constants.c | 21 | ||||
-rw-r--r-- | src/plugins/preauth/pkinit/pkinit_srv.c | 98 |
7 files changed, 155 insertions, 16 deletions
diff --git a/src/kdc/kdc_preauth.c b/src/kdc/kdc_preauth.c index 72c1752e9..69b1e2cf5 100644 --- a/src/kdc/kdc_preauth.c +++ b/src/kdc/kdc_preauth.c @@ -1104,6 +1104,8 @@ check_padata (krb5_context context, krb5_db_entry *client, krb5_data *req_pkt, /* This value is shared with KRB5KDC_ERR_DH_KEY_PARAMETERS_NOT_ACCEPTED. */ /* case KRB5KDC_ERR_KEY_TOO_WEAK: */ case KRB5KDC_ERR_DISCARD: + /* pkinit alg-agility */ + case KRB5KDC_ERR_NO_ACCEPTABLE_KDF: return retval; default: return KRB5KDC_ERR_PREAUTH_FAILED; diff --git a/src/lib/krb5/error_tables/krb5_err.et b/src/lib/krb5/error_tables/krb5_err.et index 4e34efd45..eda7dc307 100644 --- a/src/lib/krb5/error_tables/krb5_err.et +++ b/src/lib/krb5/error_tables/krb5_err.et @@ -123,7 +123,7 @@ error_code KRB5KDC_ERR_DIGEST_IN_CERT_NOT_ACCEPTED, "Digest in certificate not a error_code KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED, "Checksum must be included" error_code KRB5KDC_ERR_DIGEST_IN_SIGNED_DATA_NOT_ACCEPTED, "Digest in signed-data not accepted" error_code KRB5KDC_ERR_PUBLIC_KEY_ENCRYPTION_NOT_SUPPORTED, "Public key encryption not supported" -error_code KRB5PLACEHOLD_82, "KRB5 error code 82" +error_code KRB5KDC_ERR_NO_ACCEPTABLE_KDF, "No acceptable KDF offered" error_code KRB5PLACEHOLD_83, "KRB5 error code 83" error_code KRB5PLACEHOLD_84, "KRB5 error code 84" error_code KRB5KRB_AP_ERR_IAKERB_KDC_NOT_FOUND, "The IAKERB proxy could not find a KDC" diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c index 3d3dcebb5..4860e0712 100644 --- a/src/plugins/preauth/pkinit/pkinit_clnt.c +++ b/src/plugins/preauth/pkinit/pkinit_clnt.c @@ -684,6 +684,7 @@ pkinit_as_rep_parse(krb5_context context, unsigned int client_key_len = 0; krb5_checksum cksum = {0, 0, 0, NULL}; krb5_data k5data; + krb5_octet_data secret; int valid_san = 0; int valid_eku = 0; int need_eku_checking = 1; @@ -794,12 +795,35 @@ pkinit_as_rep_parse(krb5_context context, goto cleanup; } - retval = pkinit_octetstring2key(context, etype, client_key, + /* If we have a KDF algorithm ID, call the algorithm agility KDF... */ + if (kdc_reply->u.dh_Info.kdfID) { + secret.length = client_key_len; + secret.data = client_key; + + retval = pkinit_alg_agility_kdf(context, &secret, + kdc_reply->u.dh_Info.kdfID, + request->client, + request->server, etype, + (krb5_octet_data *)encoded_request, + (krb5_octet_data *)as_rep, + key_block); + + if (retval) { + pkiDebug("failed to create key pkinit_alg_agility_kdf %s\n", + error_message(retval)); + goto cleanup; + } + + /* ...otherwise, use the older octetstring2key function. */ + } else { + + retval = pkinit_octetstring2key(context, etype, client_key, client_key_len, key_block); - if (retval) { - pkiDebug("failed to create key pkinit_octetstring2key %s\n", - error_message(retval)); - goto cleanup; + if (retval) { + pkiDebug("failed to create key pkinit_octetstring2key %s\n", + error_message(retval)); + goto cleanup; + } } break; diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h index 528caecfb..31e01f9dc 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto.h +++ b/src/plugins/preauth/pkinit/pkinit_crypto.h @@ -648,5 +648,14 @@ extern const krb5_octet krb5_pkinit_sha256_oid[]; extern const size_t krb5_pkinit_sha256_oid_len; extern const krb5_octet krb5_pkinit_sha512_oid[]; extern const size_t krb5_pkinit_sha512_oid_len; +/** + * An ordered set of OIDs, stored as krb5_octet_data of KDF algorithms + * supported by this implementation. The order of this array controls + * the order in which the server will pick. + */ +extern const krb5_octet_data const *supported_kdf_alg_ids[] ; +extern const krb5_octet_data const sha1_id; +extern const krb5_octet_data const sha256_id; +extern const krb5_octet_data const sha512_id; #endif /* _PKINIT_CRYPTO_H */ diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c index 08ca8df4d..013f8cbe0 100644 --- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c +++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c @@ -2263,6 +2263,11 @@ pkinit_alg_agility_kdf(krb5_context context, } memset (key_block->contents, 0, key_block->length); + /* If this is anonymous pkinit, use the anonymous principle for party_u_info */ + if (party_u_info && krb5_principal_compare_any_realm(context, party_u_info, + krb5_anonymous_principal())) + party_u_info = krb5_anonymous_principal(); + if (0 != (retval = pkinit_alg_values(context, alg_oid, &hash_len, &EVP_func))) goto cleanup; diff --git a/src/plugins/preauth/pkinit/pkinit_kdf_constants.c b/src/plugins/preauth/pkinit/pkinit_kdf_constants.c index f29764a1b..c29d5e2b2 100644 --- a/src/plugins/preauth/pkinit/pkinit_kdf_constants.c +++ b/src/plugins/preauth/pkinit/pkinit_kdf_constants.c @@ -46,12 +46,27 @@ #include "pkinit_crypto.h" /* statically declare OID constants for all three algorithms */ -const krb5_octet krb5_pkinit_sha1_oid[10] = +const krb5_octet krb5_pkinit_sha1_oid[8] = {0x2B,0x06,0x01,0x05,0x02,0x03,0x06,0x01}; const size_t krb5_pkinit_sha1_oid_len = 8; -const krb5_octet krb5_pkinit_sha256_oid[10] = +const krb5_octet krb5_pkinit_sha256_oid[8] = {0x2B,0x06,0x01,0x05,0x02,0x03,0x06,0x02}; const size_t krb5_pkinit_sha256_oid_len = 8; -const krb5_octet krb5_pkinit_sha512_oid [10] = +const krb5_octet krb5_pkinit_sha512_oid [8] = {0x2B,0x06,0x01,0x05,0x02,0x03,0x06,0x03}; const size_t krb5_pkinit_sha512_oid_len = 8; + +#define oid_as_data(var, oid_base) \ + const krb5_octet_data var = \ + {0, sizeof oid_base, (krb5_octet *) oid_base} +oid_as_data(sha1_id, krb5_pkinit_sha1_oid); +oid_as_data(sha256_id, krb5_pkinit_sha256_oid); +oid_as_data(sha512_id, krb5_pkinit_sha512_oid); +#undef oid_as_data + +const krb5_octet_data const *supported_kdf_alg_ids[] = { + &sha256_id, + &sha1_id, + &sha512_id, + NULL +}; diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c index 46bcc2ca7..a74268ce8 100644 --- a/src/plugins/preauth/pkinit/pkinit_srv.c +++ b/src/plugins/preauth/pkinit/pkinit_srv.c @@ -34,6 +34,7 @@ #include <errno.h> #include <string.h> +#include <k5-int.h> #include "pkinit.h" /* Remove when FAST PKINIT is settled. */ @@ -659,6 +660,46 @@ cleanup: } static krb5_error_code +pkinit_pick_kdf_alg(krb5_context context, + krb5_octet_data **kdf_list, + krb5_octet_data **alg_oid) +{ + krb5_error_code retval = 0; + krb5_octet_data *req_oid = NULL; + const krb5_octet_data *supp_oid = NULL; + krb5_octet_data *tmp_oid = NULL; + int i, j = 0; + + *alg_oid = NULL; + + /* for each of the OIDs in the client's request... */ + for (i = 0; NULL != (req_oid = kdf_list[i]); i++) { + /* if the requested OID is supported, use it. */ + for (j = 0; NULL != (supp_oid = supported_kdf_alg_ids[j]); j++) { + if ((req_oid->length == supp_oid->length) && + (0 == memcmp(req_oid->data, supp_oid->data, req_oid->length))) { + tmp_oid = k5alloc(sizeof(krb5_octet_data), &retval); + if (retval) + goto cleanup; + tmp_oid->data = k5alloc(supp_oid->length, &retval); + if (retval) + goto cleanup; + tmp_oid->length = supp_oid->length; + memcpy(tmp_oid->data, supp_oid->data, supp_oid->length); + *alg_oid = tmp_oid; + tmp_oid = NULL; + goto cleanup; + } + } + retval = KRB5KDC_ERR_NO_ACCEPTABLE_KDF; + } +cleanup: + if (tmp_oid) + krb5_free_octet_data(context, tmp_oid); + return retval; +} + +static krb5_error_code pkinit_server_return_padata(krb5_context context, krb5_pa_data * padata, struct _krb5_db_entry_new * client, @@ -688,6 +729,7 @@ pkinit_server_return_padata(krb5_context context, krb5_pa_pk_as_rep *rep = NULL; krb5_pa_pk_as_rep_draft9 *rep9 = NULL; krb5_data *out_data = NULL; + krb5_octet_data secret; krb5_enctype enctype = -1; @@ -975,6 +1017,25 @@ pkinit_server_return_padata(krb5_context context, #endif } + if ((rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo) && + ((reqctx->rcv_auth_pack != NULL && + reqctx->rcv_auth_pack->supportedKDFs != NULL))) { + + /* If using the alg-agility KDF, put the algorithm in the reply + * before encoding it. + */ + if (reqctx->rcv_auth_pack != NULL && + reqctx->rcv_auth_pack->supportedKDFs != NULL) { + retval = pkinit_pick_kdf_alg(context, reqctx->rcv_auth_pack->supportedKDFs, + &(rep->u.dh_Info.kdfID)); + if (retval) { + pkiDebug("pkinit_pick_kdf_alg failed: %s\n", + error_message(retval)); + goto cleanup; + } + } + } + switch ((int)padata->pa_type) { case KRB5_PADATA_PK_AS_REQ: retval = k5int_encode_krb5_pa_pk_as_rep(rep, &out_data); @@ -998,12 +1059,36 @@ pkinit_server_return_padata(krb5_context context, if ((rep9 != NULL && rep9->choice == choice_pa_pk_as_rep_draft9_dhSignedData) || (rep != NULL && rep->choice == choice_pa_pk_as_rep_dhInfo)) { - retval = pkinit_octetstring2key(context, enctype, server_key, - server_key_len, encrypting_key); - if (retval) { - pkiDebug("pkinit_octetstring2key failed: %s\n", - error_message(retval)); - goto cleanup; + + /* If supported KDFs are specified, use the alg agility KDF */ + if ((reqctx->rcv_auth_pack != NULL && + reqctx->rcv_auth_pack->supportedKDFs != NULL)) { + + secret.data = server_key; + secret.length = server_key_len; + + retval = pkinit_alg_agility_kdf(context, &secret, + rep->u.dh_Info.kdfID, + request->client, request->server, + enctype, + (krb5_octet_data *)req_pkt, + (krb5_octet_data *)out_data, + encrypting_key); + if (retval) { + pkiDebug("pkinit_alg_agility_kdf failed: %s\n", + error_message(retval)); + goto cleanup; + } + + /* Otherwise, use the older octetstring2key() function */ + } else { + retval = pkinit_octetstring2key(context, enctype, server_key, + server_key_len, encrypting_key); + if (retval) { + pkiDebug("pkinit_octetstring2key failed: %s\n", + error_message(retval)); + goto cleanup; + } } } @@ -1028,7 +1113,6 @@ pkinit_server_return_padata(krb5_context context, (*send_pa)->length = out_data->length; (*send_pa)->contents = (krb5_octet *) out_data->data; - cleanup: pkinit_fini_kdc_req_context(context, reqctx); free(scratch.data); |