krb5 commit: Refactor PKINIT KDF internal interfaces

ghudson at mit.edu ghudson at mit.edu
Tue Dec 12 18:20:51 EST 2023


https://github.com/krb5/krb5/commit/ec71ac1cabbb3926f8ffaf71e1ad007e4e56e0e5
commit ec71ac1cabbb3926f8ffaf71e1ad007e4e56e0e5
Author: Greg Hudson <ghudson at mit.edu>
Date:   Fri Dec 1 19:40:02 2023 -0500

    Refactor PKINIT KDF internal interfaces
    
    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.

 src/plugins/preauth/pkinit/pkinit_clnt.c           | 35 +++----------
 src/plugins/preauth/pkinit/pkinit_crypto.h         | 30 ++----------
 src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 57 +++++++++++++---------
 src/plugins/preauth/pkinit/pkinit_kdf_test.c       | 36 +++++---------
 src/plugins/preauth/pkinit/pkinit_srv.c            | 31 +++---------
 src/plugins/preauth/pkinit/pkinit_trace.h          | 13 ++---
 6 files changed, 70 insertions(+), 132 deletions(-)

diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
index b08022a21..0f76a62c0 100644
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
@@ -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;
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index 900dba776..8e4a81362 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -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
@@ -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;
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index cc5befc02..7c26899fa 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -2599,12 +2599,9 @@ cleanup:
     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;
@@ -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;
 
@@ -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;
@@ -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);
@@ -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;
@@ -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();
@@ -2741,8 +2742,8 @@ cleanup:
 
 #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;
@@ -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,
@@ -2805,13 +2806,14 @@ cleanup:
 
 #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;
@@ -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;
@@ -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);
@@ -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)
diff --git a/src/plugins/preauth/pkinit/pkinit_kdf_test.c b/src/plugins/preauth/pkinit/pkinit_kdf_test.c
index 7f38e8491..0a8a69b2a 100644
--- a/src/plugins/preauth/pkinit/pkinit_kdf_test.c
+++ b/src/plugins/preauth/pkinit/pkinit_kdf_test.c
@@ -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"
@@ -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;
@@ -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;
@@ -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;
@@ -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;
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index e22bcb195..c7880e3fe 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -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);
diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h
index 1c1ceb5a4..ab23b68ee 100644
--- a/src/plugins/preauth/pkinit/pkinit_trace.h
+++ b/src/plugins/preauth/pkinit/pkinit_trace.h
@@ -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)    \
@@ -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)
 


More information about the cvs-krb5 mailing list