]> git.ipfire.org Git - thirdparty/krb5.git/commitdiff
Refactor PKINIT KDF internal interfaces 1322/head
authorGreg Hudson <ghudson@mit.edu>
Sat, 2 Dec 2023 00:40:02 +0000 (19:40 -0500)
committerGreg Hudson <ghudson@mit.edu>
Tue, 12 Dec 2023 22:35:56 +0000 (17:35 -0500)
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
src/plugins/preauth/pkinit/pkinit_crypto.h
src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
src/plugins/preauth/pkinit/pkinit_kdf_test.c
src/plugins/preauth/pkinit/pkinit_srv.c
src/plugins/preauth/pkinit/pkinit_trace.h

index b08022a2145d3f65b3247575aa7fcf263131ac64..0f76a62c052eb8e977d6e6df863313c8cc26b4fe 100644 (file)
@@ -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;
index 900dba7769d2d2fbaf66779eecf1b14e7197cb80..8e4a813622193ce064d9b6ad9a8d0664edcaad40 100644 (file)
@@ -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;
index cc5befc02a51cc3f4f43838e5bc090c93d2005fd..7c26899fa7700875103c01eb364a1a6d9b4cc9e9 100644 (file)
@@ -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)
index 7f38e84910aa10fb3ed5d5e5c8e9573511383d72..0a8a69b2a731828b06c8cf9089f2066fd7b9d212 100644 (file)
  * 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;
index e22bcb195b5bb636ffef1c49bde770f72908e6ba..c7880e3fe8de447dc1beb1522ed9ec3f1318f704 100644 (file)
@@ -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);
index 1c1ceb5a415136f05681fe63cd90ab9495ee41db..ab23b68ee18d05935c50559c4010ac637d480d08 100644 (file)
     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)