Skip to content

Commit

Permalink
Refactor PKINIT KDF internal interfaces
Browse files Browse the repository at this point in the history
Simplify the client and server PKINIT code by renaming
pkinit_alg_agility_kdf() to pkinit_kdf() and making it do RFC 4556
octet2string if alg_oid is null.  Move responsibility for tracing
inside the new interface.  Constify some parameters and remove some
unnecessary casts.  Rename "key" to "secret" in several internal
functions to avoid confusion between the input DH secret and the
output key.
  • Loading branch information
greghudson committed Dec 12, 2023
1 parent 401f584 commit ec71ac1
Show file tree
Hide file tree
Showing 6 changed files with 70 additions and 132 deletions.
35 changes: 7 additions & 28 deletions src/plugins/preauth/pkinit/pkinit_clnt.c
Original file line number Diff line number Diff line change
Expand Up @@ -621,34 +621,13 @@ pkinit_as_rep_parse(krb5_context context,
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;
Expand Down
30 changes: 5 additions & 25 deletions src/plugins/preauth/pkinit/pkinit_crypto.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,22 +244,6 @@ krb5_error_code crypto_check_cert_eku
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
Expand Down Expand Up @@ -552,15 +536,11 @@ krb5_error_code pkinit_identity_set_prompter
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;
Expand Down
57 changes: 33 additions & 24 deletions src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
Original file line number Diff line number Diff line change
Expand Up @@ -2599,12 +2599,9 @@ crypto_check_cert_eku(krb5_context context,
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;
Expand All @@ -2614,7 +2611,7 @@ pkinit_octetstring2key(krb5_context context,
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;

Expand All @@ -2629,20 +2626,20 @@ pkinit_octetstring2key(krb5_context context,
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;
Expand All @@ -2660,6 +2657,10 @@ pkinit_octetstring2key(krb5_context context,
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);
Expand Down Expand Up @@ -2691,8 +2692,8 @@ algid_to_md(const krb5_data *alg_id)

#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;
Expand All @@ -2719,7 +2720,7 @@ openssl_sskdf(krb5_context context, const EVP_MD *md, krb5_data *key,
*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();
Expand All @@ -2741,8 +2742,8 @@ openssl_sskdf(krb5_context context, const EVP_MD *md, krb5_data *key,

#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;
Expand Down Expand Up @@ -2783,7 +2784,7 @@ builtin_sskdf(krb5_context context, const EVP_MD *md, krb5_data *key,
/* - 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,
Expand All @@ -2805,13 +2806,14 @@ builtin_sskdf(krb5_context context, const EVP_MD *md, krb5_data *key,

#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;
Expand All @@ -2823,6 +2825,9 @@ pkinit_alg_agility_kdf(krb5_context context, krb5_data *secret,
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;
Expand All @@ -2840,7 +2845,7 @@ pkinit_alg_agility_kdf(krb5_context context, krb5_data *secret,
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);
Expand Down Expand Up @@ -2875,6 +2880,10 @@ pkinit_alg_agility_kdf(krb5_context context, krb5_data *secret,
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)
Expand Down
36 changes: 11 additions & 25 deletions src/plugins/preauth/pkinit/pkinit_kdf_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,8 @@
* 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"
Expand Down Expand Up @@ -72,7 +68,6 @@ krb5_octet key3_hex[] =
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;
Expand Down Expand Up @@ -131,12 +126,9 @@ main(int argc, char **argv)

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;
Expand All @@ -162,12 +154,9 @@ main(int argc, char **argv)

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;
Expand All @@ -193,12 +182,9 @@ main(int argc, char **argv)

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;
Expand Down
31 changes: 7 additions & 24 deletions src/plugins/preauth/pkinit/pkinit_srv.c
Original file line number Diff line number Diff line change
Expand Up @@ -896,30 +896,13 @@ pkinit_server_return_padata(krb5_context context,
"/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);
Expand Down
13 changes: 7 additions & 6 deletions src/plugins/preauth/pkinit/pkinit_trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,6 @@
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) \
Expand Down Expand Up @@ -95,6 +89,13 @@
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)

Expand Down

0 comments on commit ec71ac1

Please sign in to comment.