goto cleanup;
}
- /* 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 = (char *)client_key;
-
- retval = pkinit_alg_agility_kdf(context, &secret,
- kdc_reply->u.dh_Info.kdfID,
- request->client, request->server,
- etype, encoded_request,
- (krb5_data *)as_rep, key_block);
- if (retval) {
- pkiDebug("failed to create key pkinit_alg_agility_kdf %s\n",
- error_message(retval));
- goto cleanup;
- }
- TRACE_PKINIT_CLIENT_KDF_ALG(context, kdc_reply->u.dh_Info.kdfID,
- key_block);
-
- } else {
- /* Otherwise, use the older octetstring2key function. */
- 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;
- }
- TRACE_PKINIT_CLIENT_KDF_OS2K(context, key_block);
+ secret = make_data(client_key, client_key_len);
+ retval = pkinit_kdf(context, &secret, kdc_reply->u.dh_Info.kdfID,
+ request->client, request->server, etype,
+ encoded_request, as_rep, key_block);
+ if (retval) {
+ pkiDebug("pkinit_kdf failed: %s\n", error_message(retval));
+ goto cleanup;
}
retval = 0;
int *eku_valid); /* OUT
receives non-zero if an acceptable EKU was found */
-/*
- * this functions takes in generated DH secret key and converts
- * it in to a kerberos session key. it takes into the account the
- * enc type and then follows the procedure specified in the RFC p 22.
- */
-krb5_error_code pkinit_octetstring2key
- (krb5_context context, /* IN */
- krb5_enctype etype, /* IN
- specifies the enc type */
- unsigned char *key, /* IN
- contains the DH secret key */
- unsigned int key_len, /* IN
- contains length of key */
- krb5_keyblock * krb5key); /* OUT
- receives kerberos session key */
-
/*
* this function implements clients first part of the DH protocol.
* client selects its DH parameters and pub key
void *prompter_data); /* IN */
krb5_error_code
-pkinit_alg_agility_kdf(krb5_context context,
- krb5_data *secret,
- krb5_data *alg_oid,
- krb5_const_principal party_u_info,
- krb5_const_principal party_v_info,
- krb5_enctype enctype,
- krb5_data *as_req,
- krb5_data *pk_as_rep,
- krb5_keyblock *key_block);
+pkinit_kdf(krb5_context context, krb5_data *secret, const krb5_data *alg_oid,
+ krb5_const_principal party_u_info,
+ krb5_const_principal party_v_info, krb5_enctype enctype,
+ const krb5_data *as_req, const krb5_data *pk_as_rep,
+ krb5_keyblock *key_block);
extern const krb5_data sha1_id;
extern const krb5_data sha256_id;
return retval;
}
-krb5_error_code
-pkinit_octetstring2key(krb5_context context,
- krb5_enctype etype,
- unsigned char *key,
- unsigned int dh_key_len,
- krb5_keyblock *key_block)
+static krb5_error_code
+octetstring2key(krb5_context context, krb5_enctype etype,
+ const krb5_data *secret, krb5_keyblock *key_block)
{
krb5_error_code retval;
unsigned char *buf = NULL;
krb5_data random_data;
EVP_MD_CTX *sha1_ctx = NULL;
- buf = k5alloc(dh_key_len, &retval);
+ buf = k5alloc(secret->length, &retval);
if (buf == NULL)
goto cleanup;
do {
if (!EVP_DigestInit(sha1_ctx, EVP_sha1()) ||
!EVP_DigestUpdate(sha1_ctx, &counter, 1) ||
- !EVP_DigestUpdate(sha1_ctx, key, dh_key_len) ||
+ !EVP_DigestUpdate(sha1_ctx, secret->data, secret->length) ||
!EVP_DigestFinal(sha1_ctx, md, NULL)) {
retval = KRB5_CRYPTO_INTERNAL;
goto cleanup;
}
- if (dh_key_len - offset < sizeof(md))
- memcpy(buf + offset, md, dh_key_len - offset);
+ if (secret->length - offset < sizeof(md))
+ memcpy(buf + offset, md, secret->length - offset);
else
memcpy(buf + offset, md, sizeof(md));
offset += sizeof(md);
counter++;
- } while (offset < dh_key_len);
+ } while (offset < secret->length);
key_block->magic = 0;
key_block->enctype = etype;
random_data.data = (char *)buf;
retval = krb5_c_random_to_key(context, etype, &random_data, key_block);
+ if (retval)
+ goto cleanup;
+
+ TRACE_PKINIT_KDF_OS2K(context, key_block);
cleanup:
EVP_MD_CTX_free(sha1_ctx);
#define sskdf openssl_sskdf
static krb5_error_code
-openssl_sskdf(krb5_context context, const EVP_MD *md, krb5_data *key,
- krb5_data *info, size_t len, krb5_data *out)
+openssl_sskdf(krb5_context context, const EVP_MD *md, const krb5_data *secret,
+ const krb5_data *info, size_t len, krb5_data *out)
{
krb5_error_code ret;
EVP_KDF *kdf = NULL;
*p++ = OSSL_PARAM_construct_utf8_string(OSSL_KDF_PARAM_DIGEST,
(char *)EVP_MD_get0_name(md), 0);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_KEY,
- key->data, key->length);
+ secret->data, secret->length);
*p++ = OSSL_PARAM_construct_octet_string(OSSL_KDF_PARAM_INFO,
info->data, info->length);
*p = OSSL_PARAM_construct_end();
#define sskdf builtin_sskdf
static krb5_error_code
-builtin_sskdf(krb5_context context, const EVP_MD *md, krb5_data *key,
- krb5_data *info, size_t len, krb5_data *out)
+builtin_sskdf(krb5_context context, const EVP_MD *md, const krb5_data *secret,
+ const krb5_data *info, size_t len, krb5_data *out)
{
krb5_error_code ret;
uint32_t counter = 1, reps;
/* - Compute Hashi = H(counter || Z || OtherInfo). */
if (!EVP_DigestInit(ctx, md) ||
!EVP_DigestUpdate(ctx, be_counter, 4) ||
- !EVP_DigestUpdate(ctx, key->data, key->length) ||
+ !EVP_DigestUpdate(ctx, secret->data, secret->length) ||
!EVP_DigestUpdate(ctx, info->data, info->length) ||
!EVP_DigestFinal(ctx, outptr, &s)) {
ret = oerr(context, KRB5_CRYPTO_INTERNAL,
#endif /* OPENSSL_VERSION_NUMBER < 0x30000000L */
-/* id-pkinit-kdf family, as specified by RFC 8636. */
+/* id-pkinit-kdf family, as specified by RFC 8636. If alg_oid is null,
+ * octet2string(), as specified by RFC 4556. */
krb5_error_code
-pkinit_alg_agility_kdf(krb5_context context, krb5_data *secret,
- krb5_data *alg_oid, krb5_const_principal party_u_info,
- krb5_const_principal party_v_info,
- krb5_enctype enctype, krb5_data *as_req,
- krb5_data *pk_as_rep, krb5_keyblock *key_block)
+pkinit_kdf(krb5_context context, krb5_data *secret, const krb5_data *alg_oid,
+ krb5_const_principal party_u_info,
+ krb5_const_principal party_v_info, krb5_enctype enctype,
+ const krb5_data *as_req, const krb5_data *pk_as_rep,
+ krb5_keyblock *key_block)
{
krb5_error_code ret;
size_t rand_len = 0, key_len = 0;
krb5_algorithm_identifier alg_id;
char *hash_name = NULL;
+ if (alg_oid == NULL)
+ return octetstring2key(context, enctype, secret, key_block);
+
ret = krb5_c_keylengths(context, enctype, &rand_len, &key_len);
if (ret)
goto cleanup;
if (party_u_info &&
krb5_principal_compare_any_realm(context, party_u_info,
krb5_anonymous_principal())) {
- party_u_info = (krb5_principal)krb5_anonymous_principal();
+ party_u_info = krb5_anonymous_principal();
}
md = algid_to_md(alg_oid);
goto cleanup;
ret = krb5_c_random_to_key(context, enctype, &random_data, key_block);
+ if (ret)
+ goto cleanup;
+
+ TRACE_PKINIT_KDF_ALG(context, alg_oid, key_block);
cleanup:
if (ret)
* or implied warranty.
*/
-/*
- * pkinit_kdf_test.c -- Test to verify the correctness of the function
- * pkinit_alg_agility_kdf() in pkinit_crypto_openssl, which implements
- * the Key Derivation Function from the PKInit Algorithm Agility
- * document, currently draft-ietf-krb-wg-pkinit-alg-agility-04.txt.
- */
+/* Verify the correctness of pkinit_kdf() in pkinit_crypto_openssl, which
+ * implements the key derivation function from RFC 8636. */
#include "k5-platform.h"
#include "pkinit.h"
int
main(int argc, char **argv)
{
- /* arguments for calls to pkinit_alg_agility_kdf() */
krb5_context context = 0;
krb5_data secret;
krb5_algorithm_identifier alg_id;
enctype = enctype_aes;
- /* call pkinit_alg_agility_kdf() with test vector values*/
- if (0 != (retval = pkinit_alg_agility_kdf(context, &secret,
- &alg_id.algorithm,
- u_principal, v_principal,
- enctype, &as_req, &pk_as_rep,
- &key_block))) {
+ retval = pkinit_kdf(context, &secret, &alg_id.algorithm, u_principal,
+ v_principal, enctype, &as_req, &pk_as_rep, &key_block);
+ if (retval) {
printf("ERROR in pkinit_kdf_test: kdf call failed, retval = %d\n",
retval);
goto cleanup;
enctype = enctype_aes;
- /* call pkinit_alg_agility_kdf() with test vector values*/
- if (0 != (retval = pkinit_alg_agility_kdf(context, &secret,
- &alg_id.algorithm,
- u_principal, v_principal,
- enctype, &as_req, &pk_as_rep,
- &key_block))) {
+ retval = pkinit_kdf(context, &secret, &alg_id.algorithm, u_principal,
+ v_principal, enctype, &as_req, &pk_as_rep, &key_block);
+ if (retval) {
printf("ERROR in pkinit_kdf_test: kdf call failed, retval = %d\n",
retval);
goto cleanup;
enctype = enctype_des3;
- /* call pkinit_alg_agility_kdf() with test vector values*/
- if (0 != (retval = pkinit_alg_agility_kdf(context, &secret,
- &alg_id.algorithm,
- u_principal, v_principal,
- enctype, &as_req, &pk_as_rep,
- &key_block))) {
+ retval = pkinit_kdf(context, &secret, &alg_id.algorithm, u_principal,
+ v_principal, enctype, &as_req, &pk_as_rep, &key_block);
+ if (retval) {
printf("ERROR in pkinit_kdf_test: kdf call failed, retval = %d\n",
retval);
goto cleanup;
"/tmp/kdc_as_rep");
#endif
- /* If mutually supported KDFs were found, use the algorithm agility KDF. */
- if (rep->u.dh_Info.kdfID) {
- secret.data = (char *)server_key;
- secret.length = server_key_len;
-
- retval = pkinit_alg_agility_kdf(context, &secret, rep->u.dh_Info.kdfID,
- request->client, request->server,
- enctype, req_pkt, out_data,
- &reply_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, &reply_key);
- if (retval) {
- pkiDebug("pkinit_octetstring2key failed: %s\n",
- error_message(retval));
- goto cleanup;
- }
+ secret = make_data(server_key, server_key_len);
+ retval = pkinit_kdf(context, &secret, rep->u.dh_Info.kdfID,
+ request->client, request->server, enctype, req_pkt,
+ out_data, &reply_key);
+ if (retval) {
+ pkiDebug("pkinit_kdf failed: %s\n", error_message(retval));
+ goto cleanup;
}
retval = cb->replace_reply_key(context, rock, &reply_key, FALSE);
TRACE(c, "PKINIT client skipping EKU check due to configuration")
#define TRACE_PKINIT_CLIENT_FRESHNESS_TOKEN(c) \
TRACE(c, "PKINIT client received freshness token from KDC")
-#define TRACE_PKINIT_CLIENT_KDF_ALG(c, kdf, keyblock) \
- TRACE(c, "PKINIT client used KDF {hexdata} to compute reply key " \
- "{keyblock}", kdf, keyblock)
-#define TRACE_PKINIT_CLIENT_KDF_OS2K(c, keyblock) \
- TRACE(c, "PKINIT client used octetstring2key to compute reply key " \
- "{keyblock}", keyblock)
#define TRACE_PKINIT_CLIENT_NO_IDENTITY(c) \
TRACE(c, "PKINIT client has no configured identity; giving up")
#define TRACE_PKINIT_CLIENT_REP_CHECKSUM_FAIL(c, expected, received) \
TRACE(c, "PKINIT client key has group {str}, need at least {str}", \
desc, mindesc)
+#define TRACE_PKINIT_KDF_ALG(c, kdf, keyblock) \
+ TRACE(c, "PKINIT used KDF {hexdata} to compute reply key {keyblock}", \
+ kdf, keyblock)
+#define TRACE_PKINIT_KDF_OS2K(c, keyblock) \
+ TRACE(c, "PKINIT used octetstring2key to compute reply key {keyblock}", \
+ keyblock)
+
#define TRACE_PKINIT_OPENSSL_ERROR(c, msg) \
TRACE(c, "PKINIT OpenSSL error: {str}", msg)