From dea9421ccdbe5c8f63aae85341a8f091c6019407 Mon Sep 17 00:00:00 2001
From: Julien Rische <jrische@redhat.com>
Date: Wed, 1 Jun 2022 18:02:04 +0200
Subject: [PATCH] Set reasonable supportedCMSTypes in PKINIT

The PKINIT client uses AuthPack.supportedCMSTypes to let the KDC know
the algorithms it supports for verification of the CMS data signature.
(The MIT krb5 KDC currently ignores this list, but other
implementations use it.)

Replace 3DES with sha512WithRSAEncryption and sha256WithRSAEncryption.

[ghudson@mit.edu: simplified code and used appropriate helpers; edited
commit message]

ticket: 9066 (new)
---
 src/plugins/preauth/pkinit/Makefile.in        |  4 +-
 src/plugins/preauth/pkinit/pkinit_clnt.c      |  8 ++++
 ...nit_kdf_constants.c => pkinit_constants.c} | 24 ++++++++++++
 src/plugins/preauth/pkinit/pkinit_crypto.h    | 16 ++++++++
 .../preauth/pkinit/pkinit_crypto_openssl.c    | 39 +++++++++++++++++++
 5 files changed, 89 insertions(+), 2 deletions(-)
 rename src/plugins/preauth/pkinit/{pkinit_kdf_constants.c => pkinit_constants.c} (76%)

diff --git a/src/plugins/preauth/pkinit/Makefile.in b/src/plugins/preauth/pkinit/Makefile.in
index d20fb18a8..97aaded03 100644
--- a/src/plugins/preauth/pkinit/Makefile.in
+++ b/src/plugins/preauth/pkinit/Makefile.in
@@ -18,7 +18,7 @@ STLIBOBJS= \
 	pkinit_srv.o \
 	pkinit_lib.o \
 	pkinit_clnt.o \
-	pkinit_kdf_constants.o \
+	pkinit_constants.o \
 	pkinit_profile.o \
 	pkinit_identity.o \
 	pkinit_matching.o \
@@ -29,7 +29,7 @@ SRCS= \
 	$(srcdir)/pkinit_srv.c \
 	$(srcdir)/pkinit_lib.c \
 	$(srcdir)/pkinit_kdf_test.c \
-	$(srcdir)/pkinit_kdf_constants.c \
+	$(srcdir)/pkinit_constants.c \
 	$(srcdir)/pkinit_clnt.c \
 	$(srcdir)/pkinit_profile.c \
 	$(srcdir)/pkinit_identity.c \
diff --git a/src/plugins/preauth/pkinit/pkinit_clnt.c b/src/plugins/preauth/pkinit/pkinit_clnt.c
index a385da7c3..2817cc213 100644
--- a/src/plugins/preauth/pkinit/pkinit_clnt.c
+++ b/src/plugins/preauth/pkinit/pkinit_clnt.c
@@ -212,6 +212,14 @@ pkinit_as_req_create(krb5_context context,
     auth_pack.clientPublicValue = &info;
     auth_pack.supportedKDFs = (krb5_data **)supported_kdf_alg_ids;
 
+    /* add List of CMS algorithms */
+    retval = create_krb5_supportedCMSTypes(context, plgctx->cryptoctx,
+                                           reqctx->cryptoctx,
+                                           reqctx->idctx, &cmstypes);
+    auth_pack.supportedCMSTypes = cmstypes;
+    if (retval)
+        goto cleanup;
+
     switch(protocol) {
     case DH_PROTOCOL:
         TRACE_PKINIT_CLIENT_REQ_DH(context);
diff --git a/src/plugins/preauth/pkinit/pkinit_kdf_constants.c b/src/plugins/preauth/pkinit/pkinit_constants.c
similarity index 76%
rename from src/plugins/preauth/pkinit/pkinit_kdf_constants.c
rename to src/plugins/preauth/pkinit/pkinit_constants.c
index 1604f1670..1832e8f7b 100644
--- a/src/plugins/preauth/pkinit/pkinit_kdf_constants.c
+++ b/src/plugins/preauth/pkinit/pkinit_constants.c
@@ -57,3 +57,27 @@ krb5_data const * const supported_kdf_alg_ids[] = {
     &sha512_id,
     NULL
 };
+
+/* RFC 4055 sha256WithRSAEncryption: iso(1) member-body(2) us(840)
+ * rsadsi(113549) pkcs(1) 1 11 */
+static char sha256WithRSAEncr_oid[9] = {
+    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b
+};
+/* RFC 4055 sha256WithRSAEncryption: iso(1) member-body(2) us(840)
+ * rsadsi(113549) pkcs(1) 1 13 */
+static char sha512WithRSAEncr_oid[9] = {
+    0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0d
+};
+
+const krb5_data sha256WithRSAEncr_id = {
+    KV5M_DATA, sizeof(sha256WithRSAEncr_oid), sha256WithRSAEncr_oid
+};
+const krb5_data sha512WithRSAEncr_id = {
+    KV5M_DATA, sizeof(sha512WithRSAEncr_oid), sha512WithRSAEncr_oid
+};
+
+krb5_data const * const supported_cms_algs[] = {
+    &sha512WithRSAEncr_id,
+    &sha256WithRSAEncr_id,
+    NULL
+};
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto.h b/src/plugins/preauth/pkinit/pkinit_crypto.h
index 1f9868351..f38a77093 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto.h
+++ b/src/plugins/preauth/pkinit/pkinit_crypto.h
@@ -380,6 +380,18 @@ krb5_error_code server_process_dh
 	unsigned int *server_key_len_out);		/* OUT
 		    receives length of DH secret key */
 
+/*
+ * this functions takes in crypto specific representation of
+ * supportedCMSTypes and creates a list of
+ * krb5_algorithm_identifier
+ */
+krb5_error_code create_krb5_supportedCMSTypes
+       (krb5_context context,                          /* IN */
+       pkinit_plg_crypto_context plg_cryptoctx,        /* IN */
+       pkinit_req_crypto_context req_cryptoctx,        /* IN */
+       pkinit_identity_crypto_context id_cryptoctx,    /* IN */
+       krb5_algorithm_identifier ***supportedCMSTypes); /* OUT */
+
 /*
  * this functions takes in crypto specific representation of
  * trustedCertifiers and creates a list of
@@ -617,6 +629,10 @@ extern const size_t  krb5_pkinit_sha512_oid_len;
  */
 extern krb5_data const * const supported_kdf_alg_ids[];
 
+/* CMS signature algorithms supported by this implementation, in order of
+ * decreasing preference. */
+extern krb5_data const * const supported_cms_algs[];
+
 krb5_error_code
 crypto_encode_der_cert(krb5_context context, pkinit_req_crypto_context reqctx,
 		       uint8_t **der_out, size_t *der_len);
diff --git a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
index 2a6ef4aaa..41a7464b5 100644
--- a/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
+++ b/src/plugins/preauth/pkinit/pkinit_crypto_openssl.c
@@ -5582,6 +5582,45 @@ cleanup:
     return retval;
 }
 
+krb5_error_code
+create_krb5_supportedCMSTypes(krb5_context context,
+                              pkinit_plg_crypto_context plg_cryptoctx,
+                              pkinit_req_crypto_context req_cryptoctx,
+                              pkinit_identity_crypto_context id_cryptoctx,
+                              krb5_algorithm_identifier ***algs_out)
+{
+    krb5_error_code ret;
+    krb5_algorithm_identifier **algs = NULL;
+    size_t i, count;
+
+    *algs_out = NULL;
+
+    /* Count supported OIDs and allocate list (including null terminator). */
+    for (count = 0; supported_cms_algs[count] != NULL; count++);
+    algs = k5calloc(count + 1, sizeof(*algs), &ret);
+    if (algs == NULL)
+        goto cleanup;
+
+    /* Add an algorithm identifier for each OID, with no parameters. */
+    for (i = 0; i < count; i++) {
+        algs[i] = k5alloc(sizeof(*algs[i]), &ret);
+        if (algs[i] == NULL)
+            goto cleanup;
+        ret = krb5int_copy_data_contents(context, supported_cms_algs[i],
+                                         &algs[i]->algorithm);
+        if (ret)
+            goto cleanup;
+        algs[i]->parameters = empty_data();
+    }
+
+    *algs_out = algs;
+    algs = NULL;
+
+cleanup:
+    free_krb5_algorithm_identifiers(&algs);
+    return ret;
+}
+
 krb5_error_code
 create_krb5_trustedCertifiers(krb5_context context,
                               pkinit_plg_crypto_context plg_cryptoctx,
-- 
2.35.3

