summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorSam Hartman <hartmans@mit.edu>2011-09-21 18:40:16 +0000
committerSam Hartman <hartmans@mit.edu>2011-09-21 18:40:16 +0000
commitaf2ddab839944028ef51d9ef393496063f454bea (patch)
treefcfae71ea2f257595d3572610ec3cc5592aad998 /src
parent013643be34ccfacd0be794ff55a89f609d576796 (diff)
downloadkrb5-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.c2
-rw-r--r--src/lib/krb5/error_tables/krb5_err.et2
-rw-r--r--src/plugins/preauth/pkinit/pkinit_clnt.c34
-rw-r--r--src/plugins/preauth/pkinit/pkinit_crypto.h9
-rw-r--r--src/plugins/preauth/pkinit/pkinit_crypto_openssl.c5
-rw-r--r--src/plugins/preauth/pkinit/pkinit_kdf_constants.c21
-rw-r--r--src/plugins/preauth/pkinit/pkinit_srv.c98
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);