krb5 commit: Add PKINIT paChecksum2 from MS-PKCA v20230920

ghudson at mit.edu ghudson at mit.edu
Thu Mar 13 19:17:41 EDT 2025


https://github.com/krb5/krb5/commit/310793ba63782af5ffa3a95d20e41f8f03ca7e00
commit 310793ba63782af5ffa3a95d20e41f8f03ca7e00
Author: Julien Rische <jrische at redhat.com>
Date:   Tue Jan 14 13:31:11 2025 +0100

    Add PKINIT paChecksum2 from MS-PKCA v20230920
    
    In 2023, Microsoft updated MS-PKCA to add the optional paChecksum2
    element in the PKAuthenticator sequence.  This checksum accepts SHA-1,
    SHA-256, SHA-384, and SHA-512 digests.
    
    In Windows Server 2025, this checksum becomes mandatory when using
    PKINIT with FFDH (but strangely not with ECDH if SHA-1 is configured as
    allowed).
    
    [ghudson at mit.edu: refactored crypto interfaces to reduce complexity of
    calling code]
    
    ticket: 9166 (new)

 src/include/k5-int-pkinit.h                        |  25 +++--
 src/lib/krb5/asn.1/asn1_k_encode.c                 |  18 +++-
 src/plugins/preauth/pkinit/pkinit.h                |   1 +
 src/plugins/preauth/pkinit/pkinit_clnt.c           |  41 +++-----
 src/plugins/preauth/pkinit/pkinit_constants.c      |  42 ++++++--
 src/plugins/preauth/pkinit/pkinit_crypto.h         |  24 ++++-
 src/plugins/preauth/pkinit/pkinit_crypto_openssl.c | 116 ++++++++++++++++++++-
 src/plugins/preauth/pkinit/pkinit_kdf_test.c       |   6 +-
 src/plugins/preauth/pkinit/pkinit_lib.c            |  16 ++-
 src/plugins/preauth/pkinit/pkinit_srv.c            |  38 ++-----
 src/plugins/preauth/pkinit/pkinit_trace.h          |   5 +-
 src/tests/asn.1/krb5_decode_test.c                 |   2 +-
 src/tests/asn.1/ktest.c                            |   7 +-
 src/tests/asn.1/ktest_equal.c                      |   2 +-
 src/tests/asn.1/pkinit_encode.out                  |   2 +-
 src/tests/asn.1/pkinit_trval.out                   |   2 +-
 16 files changed, 251 insertions(+), 96 deletions(-)

diff --git a/src/include/k5-int-pkinit.h b/src/include/k5-int-pkinit.h
index 915904e51..cf6b1f99c 100644
--- a/src/include/k5-int-pkinit.h
+++ b/src/include/k5-int-pkinit.h
@@ -36,21 +36,28 @@
  * pkinit structures
  */
 
-/* PKAuthenticator */
-typedef struct _krb5_pk_authenticator {
-    krb5_int32      cusec;  /* (0..999999) */
-    krb5_timestamp  ctime;
-    krb5_int32      nonce;  /* (0..4294967295) */
-    krb5_checksum   paChecksum;
-    krb5_data      *freshnessToken;
-} krb5_pk_authenticator;
-
 /* AlgorithmIdentifier */
 typedef struct _krb5_algorithm_identifier {
     krb5_data algorithm;      /* OID */
     krb5_data parameters; /* Optional */
 } krb5_algorithm_identifier;
 
+/* PAChecksum2 */
+typedef struct _krb5_pachecksum2 {
+    krb5_data checksum;
+    krb5_algorithm_identifier algorithmIdentifier;
+} krb5_pachecksum2;
+
+/* PKAuthenticator */
+typedef struct _krb5_pk_authenticator {
+    krb5_int32        cusec;  /* (0..999999) */
+    krb5_timestamp    ctime;
+    krb5_int32        nonce;  /* (0..4294967295) */
+    krb5_data         paChecksum;
+    krb5_data        *freshnessToken; /* Optional */
+    krb5_pachecksum2 *paChecksum2; /* Optional */
+} krb5_pk_authenticator;
+
 /** AuthPack from RFC 4556*/
 typedef struct _krb5_auth_pack {
     krb5_pk_authenticator       pkAuthenticator;
diff --git a/src/lib/krb5/asn.1/asn1_k_encode.c b/src/lib/krb5/asn.1/asn1_k_encode.c
index 1a250c98c..f30cbd77c 100644
--- a/src/lib/krb5/asn.1/asn1_k_encode.c
+++ b/src/lib/krb5/asn.1/asn1_k_encode.c
@@ -1394,20 +1394,30 @@ DEFSEQTYPE(pkinit_supp_pub_info, krb5_pkinit_supp_pub_info,
 MAKE_ENCODER(encode_krb5_pkinit_supp_pub_info, pkinit_supp_pub_info);
 MAKE_ENCODER(encode_krb5_sp80056a_other_info, sp80056a_other_info);
 
-/* A krb5_checksum encoded as an OCTET STRING, for PKAuthenticator. */
-DEFCOUNTEDTYPE(ostring_checksum, krb5_checksum, contents, length, octetstring);
+DEFFIELD(pachecksum2_0, krb5_pachecksum2, checksum, 0, ostring_data);
+DEFFIELD(pachecksum2_1, krb5_pachecksum2, algorithmIdentifier, 1,
+         algorithm_identifier);
+static const struct atype_info *pachecksum2_fields[] = {
+    &k5_atype_pachecksum2_0, &k5_atype_pachecksum2_1
+};
+DEFSEQTYPE(pachecksum2, krb5_pachecksum2, pachecksum2_fields);
+
+DEFPTRTYPE(pachecksum2_ptr, pachecksum2);
+DEFOPTIONALZEROTYPE(opt_pachecksum2_ptr, pachecksum2_ptr);
 
 DEFFIELD(pk_authenticator_0, krb5_pk_authenticator, cusec, 0, int32);
 DEFFIELD(pk_authenticator_1, krb5_pk_authenticator, ctime, 1, kerberos_time);
 DEFFIELD(pk_authenticator_2, krb5_pk_authenticator, nonce, 2, int32);
 DEFFIELD(pk_authenticator_3, krb5_pk_authenticator, paChecksum, 3,
-         ostring_checksum);
+         ostring_data);
 DEFFIELD(pk_authenticator_4, krb5_pk_authenticator, freshnessToken, 4,
          opt_ostring_data_ptr);
+DEFFIELD(pk_authenticator_5, krb5_pk_authenticator, paChecksum2, 5,
+         opt_pachecksum2_ptr);
 static const struct atype_info *pk_authenticator_fields[] = {
     &k5_atype_pk_authenticator_0, &k5_atype_pk_authenticator_1,
     &k5_atype_pk_authenticator_2, &k5_atype_pk_authenticator_3,
-    &k5_atype_pk_authenticator_4
+    &k5_atype_pk_authenticator_4, &k5_atype_pk_authenticator_5
 };
 DEFSEQTYPE(pk_authenticator, krb5_pk_authenticator, pk_authenticator_fields);
 
diff --git a/src/plugins/preauth/pkinit/pkinit.h b/src/plugins/preauth/pkinit/pkinit.h
index 200e75afe..40e712b24 100644
--- a/src/plugins/preauth/pkinit/pkinit.h
+++ b/src/plugins/preauth/pkinit/pkinit.h
@@ -340,6 +340,7 @@ void free_krb5_external_principal_identifier(krb5_external_principal_identifier
 void free_krb5_algorithm_identifiers(krb5_algorithm_identifier ***in);
 void free_krb5_algorithm_identifier(krb5_algorithm_identifier *in);
 void free_krb5_kdc_dh_key_info(krb5_kdc_dh_key_info **in);
+void free_pachecksum2(krb5_context context, krb5_pachecksum2 **in);
 krb5_error_code pkinit_copy_krb5_data(krb5_data *dst, const krb5_data *src);
 
 
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
index 9312ff4b1..94beeb8cf 100644
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
@@ -55,10 +55,9 @@ use_content_info(krb5_context context, pkinit_req_context req,
 static krb5_error_code
 pkinit_as_req_create(krb5_context context, pkinit_context plgctx,
                      pkinit_req_context reqctx, krb5_timestamp ctsec,
-                     krb5_int32 cusec, krb5_ui_4 nonce,
-                     const krb5_checksum *cksum,
-                     krb5_principal client, krb5_principal server,
-                     krb5_data **as_req);
+                     krb5_int32 cusec, krb5_ui_4 nonce, const krb5_data *cksum,
+                     const krb5_pachecksum2 *cksum2, krb5_principal client,
+                     krb5_principal server, krb5_data **as_req);
 
 static krb5_error_code
 pkinit_as_rep_parse(krb5_context context, pkinit_context plgctx,
@@ -88,7 +87,8 @@ pa_pkinit_gen_req(krb5_context context,
     krb5_timestamp ctsec = 0;
     krb5_int32 cusec = 0;
     krb5_ui_4 nonce = 0;
-    krb5_checksum cksum;
+    krb5_data cksum = empty_data();
+    krb5_pachecksum2 *cksum2 = NULL;
     krb5_data *der_req = NULL;
     krb5_pa_data **return_pa_data = NULL;
 
@@ -117,15 +117,10 @@ pa_pkinit_gen_req(krb5_context context,
         goto cleanup;
     }
 
-    retval = krb5_c_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, der_req,
-                                  &cksum);
+    retval = crypto_generate_checksums(context, der_req, &cksum, &cksum2);
     if (retval)
         goto cleanup;
-    TRACE_PKINIT_CLIENT_REQ_CHECKSUM(context, &cksum);
-#ifdef DEBUG_CKSUM
-    pkiDebug("calculating checksum on buf size (%d)\n", der_req->length);
-    print_buffer(der_req->data, der_req->length);
-#endif
+    TRACE_PKINIT_CLIENT_REQ_CHECKSUMS(context, &cksum, cksum2);
 
     retval = cb->get_preauth_time(context, rock, TRUE, &ctsec, &cusec);
     if (retval)
@@ -139,7 +134,8 @@ pa_pkinit_gen_req(krb5_context context,
     nonce = request->nonce;
 
     retval = pkinit_as_req_create(context, plgctx, reqctx, ctsec, cusec,
-                                  nonce, &cksum, request->client, request->server, &out_data);
+                                  nonce, &cksum, cksum2, request->client,
+                                  request->server, &out_data);
     if (retval) {
         pkiDebug("error %d on pkinit_as_req_create; aborting PKINIT\n",
                  (int) retval);
@@ -167,23 +163,19 @@ pa_pkinit_gen_req(krb5_context context,
 
 cleanup:
     krb5_free_data(context, der_req);
-    krb5_free_checksum_contents(context, &cksum);
+    krb5_free_data_contents(context, &cksum);
+    free_pachecksum2(context, &cksum2);
     krb5_free_data(context, out_data);
     krb5_free_pa_data(context, return_pa_data);
     return retval;
 }
 
 static krb5_error_code
-pkinit_as_req_create(krb5_context context,
-                     pkinit_context plgctx,
-                     pkinit_req_context reqctx,
-                     krb5_timestamp ctsec,
-                     krb5_int32 cusec,
-                     krb5_ui_4 nonce,
-                     const krb5_checksum * cksum,
-                     krb5_principal client,
-                     krb5_principal server,
-                     krb5_data ** as_req)
+pkinit_as_req_create(krb5_context context, pkinit_context plgctx,
+                     pkinit_req_context reqctx, krb5_timestamp ctsec,
+                     krb5_int32 cusec, krb5_ui_4 nonce, const krb5_data *cksum,
+                     const krb5_pachecksum2 *cksum2, krb5_principal client,
+                     krb5_principal server, krb5_data **as_req)
 {
     krb5_error_code retval = ENOMEM;
     krb5_data spki = empty_data(), *coded_auth_pack = NULL;
@@ -201,6 +193,7 @@ pkinit_as_req_create(krb5_context context,
     auth_pack.pkAuthenticator.paChecksum = *cksum;
     if (!reqctx->opts->disable_freshness)
         auth_pack.pkAuthenticator.freshnessToken = reqctx->freshness_token;
+    auth_pack.pkAuthenticator.paChecksum2 = (krb5_pachecksum2 *)cksum2;
     auth_pack.clientDHNonce.length = 0;
     auth_pack.supportedKDFs = (krb5_data **)supported_kdf_alg_ids;
 
diff --git a/src/plugins/preauth/pkinit/pkinit_constants.c b/src/plugins/preauth/pkinit/pkinit_constants.c
index 905e90d29..a32b373c3 100644
--- a/src/plugins/preauth/pkinit/pkinit_constants.c
+++ b/src/plugins/preauth/pkinit/pkinit_constants.c
@@ -34,25 +34,49 @@
 
 /* RFC 8636 id-pkinit-kdf-ah-sha1: iso(1) identified-organization(3) dod(6)
  * internet(1) security(5) kerberosv5(2) pkinit(3) kdf(6) sha1(1) */
-static char sha1_oid[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x01 };
+static char kdf_sha1[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x01 };
 /* RFC 8636 id-pkinit-kdf-ah-sha256: iso(1) identified-organization(3) dod(6)
  * internet(1) security(5) kerberosv5(2) pkinit(3) kdf(6) sha256(2) */
-static char sha256_oid[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x02 };
+static char kdf_sha256[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x02 };
 /* RFC 8636 id-pkinit-kdf-ah-sha512: iso(1) identified-organization(3) dod(6)
  * internet(1) security(5) kerberosv5(2) pkinit(3) kdf(6) sha512(3) */
-static char sha512_oid[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x03 };
+static char kdf_sha512[8] = { 0x2B, 0x06, 0x01, 0x05, 0x02, 0x03, 0x06, 0x03 };
 
-const krb5_data sha1_id = { KV5M_DATA, sizeof(sha1_oid), sha1_oid };
-const krb5_data sha256_id = { KV5M_DATA, sizeof(sha256_oid), sha256_oid };
-const krb5_data sha512_id = { KV5M_DATA, sizeof(sha512_oid), sha512_oid };
+const krb5_data kdf_sha1_id = { KV5M_DATA, sizeof(kdf_sha1), kdf_sha1 };
+const krb5_data kdf_sha256_id = { KV5M_DATA, sizeof(kdf_sha256), kdf_sha256 };
+const krb5_data kdf_sha512_id = { KV5M_DATA, sizeof(kdf_sha512), kdf_sha512 };
 
 krb5_data const * const supported_kdf_alg_ids[] = {
-    &sha256_id,
-    &sha1_id,
-    &sha512_id,
+    &kdf_sha256_id,
+    &kdf_sha1_id,
+    &kdf_sha512_id,
     NULL
 };
 
+/* RFC 3370 sha-1: iso(1) identified-organization(3) oiw(14) secsig(3)
+ * algorithm(2) 26 */
+static char cms_sha1[] = { 0x2b, 0x0e, 0x03, 0x02, 0x1a };
+/* RFC 5754 id-sha256: joint-iso-itu-t(2) country(16) us(840) organization(1)
+ * gov(101) csor(3) nistalgorithm(4) hashalgs(2) 1 */
+static char cms_sha256[] = {
+    0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+/* RFC 5754 id-sha384: joint-iso-itu-t(2) country(16) us(840) organization(1)
+ * gov(101) csor(3) nistalgorithm(4) hashalgs(2) 2 */
+static char cms_sha384[] = {
+    0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+/* RFC 5754 id-sha512: joint-iso-itu-t(2) country(16) us(840) organization(1)
+ * gov(101) csor(3) nistalgorithm(4) hashalgs(2) 3 */
+static char cms_sha512[] = {
+    0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+const krb5_data cms_sha1_id = { KV5M_DATA, sizeof(cms_sha1), cms_sha1 };
+const krb5_data cms_sha256_id = { KV5M_DATA, sizeof(cms_sha256), cms_sha256 };
+const krb5_data cms_sha384_id = { KV5M_DATA, sizeof(cms_sha384), cms_sha384 };
+const krb5_data cms_sha512_id = { KV5M_DATA, sizeof(cms_sha512), cms_sha512 };
+
 /* RFC 4055 sha256WithRSAEncryption: iso(1) member-body(2) us(840)
  * rsadsi(113549) pkcs(1) 1 11 */
 static char sha256WithRSAEncr_oid[9] = {
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index 8e4a81362..57bb3cb84 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -542,9 +542,13 @@ pkinit_kdf(krb5_context context, krb5_data *secret, const krb5_data *alg_oid,
 	   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;
-extern const krb5_data sha512_id;
+extern const krb5_data kdf_sha1_id;
+extern const krb5_data kdf_sha256_id;
+extern const krb5_data kdf_sha512_id;
+extern const krb5_data cms_sha1_id;
+extern const krb5_data cms_sha256_id;
+extern const krb5_data cms_sha384_id;
+extern const krb5_data cms_sha512_id;
 extern const krb5_data oakley_1024;
 extern const krb5_data oakley_2048;
 extern const krb5_data oakley_4096;
@@ -577,4 +581,18 @@ crypto_req_cert_matching_data(krb5_context context,
 
 int parse_dh_min_bits(krb5_context context, const char *str);
 
+/* Generate a SHA-1 checksum over body in *cksum1_out and a SHA-256 checksum
+ * over body in *cksum2_out with appropriate metadata. */
+krb5_error_code
+crypto_generate_checksums(krb5_context context, const krb5_data *body,
+			  krb5_data *cksum1_out,
+			  krb5_pachecksum2 **cksum2_out);
+
+/* Verify the SHA-1 checksum in cksum1 and the tagged checksum in cksum2.
+ * cksum2 may be NULL, in which case only cksum1 is verified. */
+krb5_error_code
+crypto_verify_checksums(krb5_context context, krb5_data *body,
+			const krb5_data *cksum1,
+			const krb5_pachecksum2 *cksum2);
+
 #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 8098028eb..f222dbdf9 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -2651,11 +2651,11 @@ cleanup:
 static const EVP_MD *
 algid_to_md(const krb5_data *alg_id)
 {
-    if (data_eq(*alg_id, sha1_id))
+    if (data_eq(*alg_id, kdf_sha1_id))
         return EVP_sha1();
-    if (data_eq(*alg_id, sha256_id))
+    if (data_eq(*alg_id, kdf_sha256_id))
         return EVP_sha256();
-    if (data_eq(*alg_id, sha512_id))
+    if (data_eq(*alg_id, kdf_sha512_id))
         return EVP_sha512();
     return NULL;
 }
@@ -5699,6 +5699,116 @@ parse_dh_min_bits(krb5_context context, const char *str)
     return PKINIT_DEFAULT_DH_MIN_BITS;
 }
 
+/* Return the OpenSSL message digest type matching the given CMS OID, or NULL
+ * if it doesn't match any of the CMS OIDs we know about. */
+static const EVP_MD *
+md_from_cms_oid(const krb5_data *alg_id)
+{
+    if (data_eq(*alg_id, cms_sha1_id))
+        return EVP_sha1();
+    if (data_eq(*alg_id, cms_sha256_id))
+        return EVP_sha256();
+    if (data_eq(*alg_id, cms_sha384_id))
+        return EVP_sha384();
+    if (data_eq(*alg_id, cms_sha512_id))
+        return EVP_sha512();
+    return NULL;
+}
+
+/* Compute a message digest of the given type over body, placing the result in
+ * *digest_out in allocated storage.  Return true on success. */
+static krb5_boolean
+make_digest(const krb5_data *body, const EVP_MD *md, krb5_data *digest_out)
+{
+    krb5_error_code ret;
+    krb5_data d;
+
+    if (md == NULL)
+        return FALSE;
+    ret = alloc_data(&d, EVP_MD_size(md));
+    if (ret)
+        return FALSE;
+    if (!EVP_Digest(body->data, body->length, (uint8_t *)d.data, &d.length, md,
+                    NULL)) {
+        free(d.data);
+        return FALSE;
+    }
+    *digest_out = d;
+    return TRUE;
+}
+
+/* Return true if digest verifies for the given body and message digest
+ * type. */
+static krb5_boolean
+check_digest(const krb5_data *body, const EVP_MD *md, const krb5_data *digest)
+{
+    unsigned int digest_len;
+    uint8_t buf[EVP_MAX_MD_SIZE];
+
+    if (md == NULL)
+        return FALSE;
+    if (!EVP_Digest(body->data, body->length, buf, &digest_len, md, NULL))
+        return FALSE;
+    return (digest->length == digest_len &&
+            CRYPTO_memcmp(digest->data, buf, digest_len) == 0);
+}
+
+krb5_error_code
+crypto_generate_checksums(krb5_context context, const krb5_data *body,
+                          krb5_data *cksum1_out, krb5_pachecksum2 **cksum2_out)
+{
+    krb5_data cksum1 = empty_data();
+    krb5_pachecksum2 *cksum2 = NULL;
+    krb5_error_code ret;
+
+    if (!make_digest(body, EVP_sha1(), &cksum1))
+        goto fail;
+
+    cksum2 = k5alloc(sizeof(*cksum2), &ret);
+    if (cksum2 == NULL)
+        goto fail;
+
+    if (!make_digest(body, EVP_sha256(), &cksum2->checksum))
+        goto fail;
+
+    if (krb5int_copy_data_contents(context, &cms_sha256_id,
+                                   &cksum2->algorithmIdentifier.algorithm))
+        goto fail;
+
+    cksum2->algorithmIdentifier.parameters = empty_data();
+
+    *cksum1_out = cksum1;
+    *cksum2_out = cksum2;
+    return 0;
+
+fail:
+    krb5_free_data_contents(context, &cksum1);
+    free_pachecksum2(context, &cksum2);
+    return KRB5_CRYPTO_INTERNAL;
+}
+
+krb5_error_code
+crypto_verify_checksums(krb5_context context, krb5_data *body,
+                        const krb5_data *cksum1,
+                        const krb5_pachecksum2 *cksum2)
+{
+    const EVP_MD *md;
+
+    /* RFC 4556 doesn't say what error to return if the checksum doesn't match.
+     * Windows returns this one. */
+    if (!check_digest(body, EVP_sha1(), cksum1))
+        return KRB5KRB_AP_ERR_MODIFIED;
+
+    if (cksum2 == NULL)
+        return 0;
+
+    md = md_from_cms_oid(&cksum2->algorithmIdentifier.algorithm);
+    if (!check_digest(body, md, &cksum2->checksum))
+        return KRB5KRB_AP_ERR_MODIFIED;
+
+    return 0;
+}
+
 #ifdef _WIN32
 BOOL WINAPI
 DllMain(HANDLE hModule, DWORD fdwReason, LPVOID lpvReserved)
diff --git a/src/plugins/preauth/pkinit/pkinit_kdf_test.c b/src/plugins/preauth/pkinit/pkinit_kdf_test.c
index 0a8a69b2a..3d0f7198e 100644
--- a/src/plugins/preauth/pkinit/pkinit_kdf_test.c
+++ b/src/plugins/preauth/pkinit/pkinit_kdf_test.c
@@ -122,7 +122,7 @@ main(int argc, char **argv)
 
     /* TEST 1:  SHA-1/AES */
     /* set up algorithm id */
-    alg_id.algorithm = sha1_id;
+    alg_id.algorithm = kdf_sha1_id;
 
     enctype = enctype_aes;
 
@@ -150,7 +150,7 @@ main(int argc, char **argv)
 
     /* TEST 2: SHA-256/AES */
     /* set up algorithm id */
-    alg_id.algorithm = sha256_id;
+    alg_id.algorithm = kdf_sha256_id;
 
     enctype = enctype_aes;
 
@@ -178,7 +178,7 @@ main(int argc, char **argv)
 
     /* TEST 3: SHA-512/DES3 */
     /* set up algorithm id */
-    alg_id.algorithm = sha512_id;
+    alg_id.algorithm = kdf_sha512_id;
 
     enctype = enctype_des3;
 
diff --git a/src/plugins/preauth/pkinit/pkinit_lib.c b/src/plugins/preauth/pkinit/pkinit_lib.c
index 25965eb5d..891f47fd2 100644
--- a/src/plugins/preauth/pkinit/pkinit_lib.c
+++ b/src/plugins/preauth/pkinit/pkinit_lib.c
@@ -29,6 +29,7 @@
  * SUCH DAMAGES.
  */
 
+#include "k5-int.h"
 #include "pkinit.h"
 
 #define FAKECERT
@@ -119,8 +120,9 @@ free_krb5_auth_pack(krb5_auth_pack **in)
 {
     if ((*in) == NULL) return;
     krb5_free_data_contents(NULL, &(*in)->clientPublicValue);
-    free((*in)->pkAuthenticator.paChecksum.contents);
+    free((*in)->pkAuthenticator.paChecksum.data);
     krb5_free_data(NULL, (*in)->pkAuthenticator.freshnessToken);
+    free_pachecksum2(NULL, &(*in)->pkAuthenticator.paChecksum2);
     if ((*in)->supportedCMSTypes != NULL)
         free_krb5_algorithm_identifiers(&((*in)->supportedCMSTypes));
     if ((*in)->supportedKDFs) {
@@ -196,6 +198,18 @@ free_krb5_kdc_dh_key_info(krb5_kdc_dh_key_info **in)
     free(*in);
 }
 
+void
+free_pachecksum2(krb5_context context, krb5_pachecksum2 **in)
+{
+    if (*in == NULL)
+        return;
+    krb5_free_data_contents(context, &(*in)->checksum);
+    krb5_free_data_contents(context, &(*in)->algorithmIdentifier.algorithm);
+    krb5_free_data_contents(context, &(*in)->algorithmIdentifier.parameters);
+    free(*in);
+    *in = NULL;
+}
+
 void
 init_krb5_pa_pk_as_req(krb5_pa_pk_as_req **in)
 {
diff --git a/src/plugins/preauth/pkinit/pkinit_srv.c b/src/plugins/preauth/pkinit/pkinit_srv.c
index 1f3db4f27..7a0fa69ee 100644
--- a/src/plugins/preauth/pkinit/pkinit_srv.c
+++ b/src/plugins/preauth/pkinit/pkinit_srv.c
@@ -428,11 +428,12 @@ pkinit_server_verify_padata(krb5_context context,
     krb5_data authp_data = {0, 0, NULL}, krb5_authz = {0, 0, NULL};
     krb5_pa_pk_as_req *reqp = NULL;
     krb5_auth_pack *auth_pack = NULL;
+    krb5_pk_authenticator *pka;
     pkinit_kdc_context plgctx = NULL;
     pkinit_kdc_req_context reqctx = NULL;
     krb5_checksum cksum = {0, 0, 0, NULL};
     krb5_data *der_req = NULL;
-    krb5_data k5data, *ftoken;
+    krb5_data k5data;
     int is_signed = 1;
     krb5_pa_data **e_data = NULL;
     krb5_kdcpreauth_modreq modreq = NULL;
@@ -524,8 +525,9 @@ pkinit_server_verify_padata(krb5_context context,
         pkiDebug("failed to decode krb5_auth_pack\n");
         goto cleanup;
     }
+    pka = &auth_pack->pkAuthenticator;
 
-    retval = krb5_check_clockskew(context, auth_pack->pkAuthenticator.ctime);
+    retval = krb5_check_clockskew(context, pka->ctime);
     if (retval)
         goto cleanup;
 
@@ -548,36 +550,14 @@ pkinit_server_verify_padata(krb5_context context,
         goto cleanup;
     }
     der_req = cb->request_body(context, rock);
-    retval = krb5_c_make_checksum(context, CKSUMTYPE_SHA1, NULL, 0, der_req,
-                                  &cksum);
-    if (retval) {
-        pkiDebug("unable to calculate AS REQ checksum\n");
-        goto cleanup;
-    }
-    if (cksum.length != auth_pack->pkAuthenticator.paChecksum.length ||
-        k5_bcmp(cksum.contents, auth_pack->pkAuthenticator.paChecksum.contents,
-                cksum.length) != 0) {
-        pkiDebug("failed to match the checksum\n");
-#ifdef DEBUG_CKSUM
-        pkiDebug("calculating checksum on buf size (%d)\n", req_pkt->length);
-        print_buffer(req_pkt->data, req_pkt->length);
-        pkiDebug("received checksum type=%d size=%d ",
-                 auth_pack->pkAuthenticator.paChecksum.checksum_type,
-                 auth_pack->pkAuthenticator.paChecksum.length);
-        print_buffer(auth_pack->pkAuthenticator.paChecksum.contents,
-                     auth_pack->pkAuthenticator.paChecksum.length);
-        pkiDebug("expected checksum type=%d size=%d ",
-                 cksum.checksum_type, cksum.length);
-        print_buffer(cksum.contents, cksum.length);
-#endif
 
-        retval = KRB5KDC_ERR_PA_CHECKSUM_MUST_BE_INCLUDED;
+    retval = crypto_verify_checksums(context, der_req, &pka->paChecksum,
+                                     pka->paChecksum2);
+    if (retval)
         goto cleanup;
-    }
 
-    ftoken = auth_pack->pkAuthenticator.freshnessToken;
-    if (ftoken != NULL) {
-        retval = cb->check_freshness_token(context, rock, ftoken);
+    if (pka->freshnessToken != NULL) {
+        retval = cb->check_freshness_token(context, rock, pka->freshnessToken);
         if (retval)
             goto cleanup;
         valid_freshness_token = TRUE;
diff --git a/src/plugins/preauth/pkinit/pkinit_trace.h b/src/plugins/preauth/pkinit/pkinit_trace.h
index c0b1e2c13..7d19167eb 100644
--- a/src/plugins/preauth/pkinit/pkinit_trace.h
+++ b/src/plugins/preauth/pkinit/pkinit_trace.h
@@ -52,8 +52,9 @@
     TRACE(c, "PKINIT client verified DH reply")
 #define TRACE_PKINIT_CLIENT_REP_DH_FAIL(c)              \
     TRACE(c, "PKINIT client could not verify DH reply")
-#define TRACE_PKINIT_CLIENT_REQ_CHECKSUM(c, cksum)                      \
-    TRACE(c, "PKINIT client computed kdc-req-body checksum {cksum}", cksum)
+#define TRACE_PKINIT_CLIENT_REQ_CHECKSUMS(c, ck1, ck2)                  \
+    TRACE(c, "PKINIT client computed checksums: {hexdata} {hexdata}",   \
+          ck1, &(ck2)->checksum)
 #define TRACE_PKINIT_CLIENT_REQ_DH(c)                           \
     TRACE(c, "PKINIT client making DH request")
 #define TRACE_PKINIT_CLIENT_SAN_CONFIG_DNSNAME(c, host)                 \
diff --git a/src/tests/asn.1/krb5_decode_test.c b/src/tests/asn.1/krb5_decode_test.c
index 6ead19d5d..25ed30e42 100644
--- a/src/tests/asn.1/krb5_decode_test.c
+++ b/src/tests/asn.1/krb5_decode_test.c
@@ -1178,7 +1178,7 @@ main(int argc, char **argv)
     /* decode_krb5_auth_pack */
     {
         setup(krb5_auth_pack,ktest_make_sample_auth_pack);
-        decode_run("krb5_auth_pack","","30 81 85 A0 35 30 33 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 06 04 04 31 32 33 34 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61",
+        decode_run("krb5_auth_pack","","30 81 89 A0 39 30 37 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61",
                    acc.decode_krb5_auth_pack,
                    ktest_equal_auth_pack,ktest_free_auth_pack);
         ktest_empty_auth_pack(&ref);
diff --git a/src/tests/asn.1/ktest.c b/src/tests/asn.1/ktest.c
index 02d26c085..20360c8ff 100644
--- a/src/tests/asn.1/ktest.c
+++ b/src/tests/asn.1/ktest.c
@@ -700,9 +700,7 @@ ktest_make_sample_pk_authenticator(krb5_pk_authenticator *p)
     p->cusec = SAMPLE_USEC;
     p->ctime = SAMPLE_TIME;
     p->nonce = SAMPLE_NONCE;
-    ktest_make_sample_checksum(&p->paChecksum);
-    /* We don't encode the checksum type, only the contents. */
-    p->paChecksum.checksum_type = 0;
+    ktest_make_sample_data(&p->paChecksum);
     p->freshnessToken = ealloc(sizeof(krb5_data));
     ktest_make_sample_data(p->freshnessToken);
 }
@@ -1604,8 +1602,7 @@ ktest_empty_pa_otp_req(krb5_pa_otp_req *p)
 static void
 ktest_empty_pk_authenticator(krb5_pk_authenticator *p)
 {
-    ktest_empty_checksum(&p->paChecksum);
-    p->paChecksum.contents = NULL;
+    ktest_empty_data(&p->paChecksum);
     krb5_free_data(NULL, p->freshnessToken);
     p->freshnessToken = NULL;
 }
diff --git a/src/tests/asn.1/ktest_equal.c b/src/tests/asn.1/ktest_equal.c
index b48a0285d..13786dd1e 100644
--- a/src/tests/asn.1/ktest_equal.c
+++ b/src/tests/asn.1/ktest_equal.c
@@ -844,7 +844,7 @@ ktest_equal_pk_authenticator(krb5_pk_authenticator *ref,
     p = p && scalar_equal(cusec);
     p = p && scalar_equal(ctime);
     p = p && scalar_equal(nonce);
-    p = p && struct_equal(paChecksum, ktest_equal_checksum);
+    p = p && data_eq(ref->paChecksum, var->paChecksum);
     return p;
 }
 
diff --git a/src/tests/asn.1/pkinit_encode.out b/src/tests/asn.1/pkinit_encode.out
index 6ec7aaa36..a764182e1 100644
--- a/src/tests/asn.1/pkinit_encode.out
+++ b/src/tests/asn.1/pkinit_encode.out
@@ -1,7 +1,7 @@
 encode_krb5_pa_pk_as_req: 30 38 80 08 6B 72 62 35 64 61 74 61 A1 22 30 20 30 1E 80 08 6B 72 62 35 64 61 74 61 81 08 6B 72 62 35 64 61 74 61 82 08 6B 72 62 35 64 61 74 61 82 08 6B 72 62 35 64 61 74 61
 encode_krb5_pa_pk_as_rep(dhInfo): A0 28 30 26 80 08 6B 72 62 35 64 61 74 61 A1 0A 04 08 6B 72 62 35 64 61 74 61 A2 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61
 encode_krb5_pa_pk_as_rep(encKeyPack): 81 08 6B 72 62 35 64 61 74 61
-encode_krb5_auth_pack: 30 81 85 A0 35 30 33 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 06 04 04 31 32 33 34 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61
+encode_krb5_auth_pack: 30 81 89 A0 39 30 37 A0 05 02 03 01 E2 40 A1 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A A2 03 02 01 2A A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 0A 04 08 6B 72 62 35 64 61 74 61 A1 08 04 06 70 76 61 6C 75 65 A2 24 30 22 30 13 06 09 2A 86 48 86 F7 12 01 02 02 04 06 70 61 72 61 6D 73 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A3 0A 04 08 6B 72 62 35 64 61 74 61 A4 10 30 0E 30 0C A0 0A 06 08 6B 72 62 35 64 61 74 61
 encode_krb5_kdc_dh_key_info: 30 25 A0 0B 03 09 00 6B 72 62 35 64 61 74 61 A1 03 02 01 2A A2 11 18 0F 31 39 39 34 30 36 31 30 30 36 30 33 31 37 5A
 encode_krb5_reply_key_pack: 30 26 A0 13 30 11 A0 03 02 01 01 A1 0A 04 08 31 32 33 34 35 36 37 38 A1 0F 30 0D A0 03 02 01 01 A1 06 04 04 31 32 33 34
 encode_krb5_sp80056a_other_info: 30 81 81 30 0B 06 09 2A 86 48 86 F7 12 01 02 02 A0 32 04 30 30 2E A0 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A1 32 04 30 30 2E A0 10 1B 0E 41 54 48 45 4E 41 2E 4D 49 54 2E 45 44 55 A1 1A 30 18 A0 03 02 01 01 A1 11 30 0F 1B 06 68 66 74 73 61 69 1B 05 65 78 74 72 61 A2 0A 04 08 6B 72 62 35 64 61 74 61
diff --git a/src/tests/asn.1/pkinit_trval.out b/src/tests/asn.1/pkinit_trval.out
index 46f4a3410..c47bd71f6 100644
--- a/src/tests/asn.1/pkinit_trval.out
+++ b/src/tests/asn.1/pkinit_trval.out
@@ -38,7 +38,7 @@ encode_krb5_auth_pack:
 .  .  [0] [Integer] 123456
 .  .  [1] [Generalized Time] "19940610060317Z"
 .  .  [2] [Integer] 42
-.  .  [3] [Octet String] "1234"
+.  .  [3] [Octet String] "krb5data"
 .  .  [4] [Octet String] "krb5data"
 .  [1] [Octet String] "pvalue"
 .  [2] [Sequence/Sequence Of]


More information about the cvs-krb5 mailing list