[openssl] master update

dev at ddvo.net dev at ddvo.net
Sat Sep 5 16:11:52 UTC 2020


The branch master has been updated
       via  15076c26d794dbbdc5413a72e7feded0c9a2ba07 (commit)
      from  39082af2fa6549c3d92c917ea5a423bca57c7b42 (commit)


- Log -----------------------------------------------------------------
commit 15076c26d794dbbdc5413a72e7feded0c9a2ba07
Author: Dr. David von Oheimb <David.von.Oheimb at siemens.com>
Date:   Fri Sep 4 15:24:14 2020 +0200

    Strengthen chain building for CMP
    
    * Add -own_trusted option to CMP app
    * Add OSSL_CMP_CTX_build_cert_chain()
    * Add optional trust store arg to ossl_cmp_build_cert_chain()
    * Extend the tests in cmp_protect_test.c and the documentation accordingly
    
    Reviewed-by: Matt Caswell <matt at openssl.org>
    (Merged from https://github.com/openssl/openssl/pull/12791)

-----------------------------------------------------------------------

Summary of changes:
 apps/cmp.c                                 | 34 ++++++++++++------
 crypto/cmp/cmp_ctx.c                       | 28 +++++++++++++++
 crypto/cmp/cmp_err.c                       |  2 ++
 crypto/cmp/cmp_local.h                     |  1 +
 crypto/cmp/cmp_protect.c                   |  2 +-
 crypto/cmp/cmp_util.c                      | 58 ++++++++++++++----------------
 crypto/err/openssl.txt                     |  1 +
 doc/internal/man3/ossl_cmp_msg_protect.pod | 30 +++++++---------
 doc/man1/openssl-cmp.pod.in                | 14 +++++++-
 doc/man3/OSSL_CMP_CTX_new.pod              | 17 +++++++++
 include/openssl/cmp.h                      |  6 ++--
 include/openssl/cmperr.h                   |  1 +
 test/cmp_protect_test.c                    | 28 +++++++++++++--
 util/libcrypto.num                         |  1 +
 14 files changed, 157 insertions(+), 66 deletions(-)

diff --git a/apps/cmp.c b/apps/cmp.c
index 1af27f7881..799ec34e1f 100644
--- a/apps/cmp.c
+++ b/apps/cmp.c
@@ -97,6 +97,7 @@ static char *opt_cacertsout = NULL;
 static char *opt_ref = NULL;
 static char *opt_secret = NULL;
 static char *opt_cert = NULL;
+static char *opt_own_trusted = NULL;
 static char *opt_key = NULL;
 static char *opt_keypass = NULL;
 static char *opt_digest = NULL;
@@ -218,7 +219,7 @@ typedef enum OPTION_choice {
     OPT_IGNORE_KEYUSAGE, OPT_UNPROTECTED_ERRORS,
     OPT_EXTRACERTSOUT, OPT_CACERTSOUT,
 
-    OPT_REF, OPT_SECRET, OPT_CERT, OPT_KEY, OPT_KEYPASS,
+    OPT_REF, OPT_SECRET, OPT_CERT, OPT_OWN_TRUSTED, OPT_KEY, OPT_KEYPASS,
     OPT_DIGEST, OPT_MAC, OPT_EXTRACERTS,
     OPT_UNPROTECTED_REQUESTS,
 
@@ -383,6 +384,8 @@ const OPTIONS cmp_options[] = {
      "Client's current certificate (needed unless using -secret for PBM);"},
     {OPT_MORE_STR, 0, 0,
      "any further certs included are appended in extraCerts field"},
+    {"own_trusted", OPT_OWN_TRUSTED, 's',
+     "Optional certs to verify chain building for own CMP signer cert"},
     {"key", OPT_KEY, 's', "Private key for the client's current certificate"},
     {"keypass", OPT_KEYPASS, 's',
      "Client private key (and cert and old cert file) pass phrase source"},
@@ -536,7 +539,8 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */
     {(char **)&opt_ignore_keyusage}, {(char **)&opt_unprotected_errors},
     {&opt_extracertsout}, {&opt_cacertsout},
 
-    {&opt_ref}, {&opt_secret}, {&opt_cert}, {&opt_key}, {&opt_keypass},
+    {&opt_ref}, {&opt_secret},
+    {&opt_cert}, {&opt_own_trusted}, {&opt_key}, {&opt_keypass},
     {&opt_digest}, {&opt_mac}, {&opt_extracerts},
     {(char **)&opt_unprotected_requests},
 
@@ -1595,6 +1599,7 @@ static int setup_protection_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine)
     if (opt_cert != NULL) {
         X509 *cert;
         STACK_OF(X509) *certs = NULL;
+        X509_STORE *own_trusted = NULL;
         int ok = 0;
 
         if (!load_cert_certs(opt_cert, &cert, &certs, 0, opt_keypass,
@@ -1603,18 +1608,24 @@ static int setup_protection_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine)
             goto err;
         ok = OSSL_CMP_CTX_set1_cert(ctx, cert);
         X509_free(cert);
-
-        if (ok) {
-            /* add any remaining certs to the list of untrusted certs */
-            STACK_OF(X509) *untrusted = OSSL_CMP_CTX_get0_untrusted_certs(ctx);
-            ok = untrusted != NULL ?
-                X509_add_certs(untrusted, certs,
-                               X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP)
-                : OSSL_CMP_CTX_set1_untrusted_certs(ctx, certs);
+        if (!ok) {
+            CMP_err("out of memory");
+        } else {
+            if (opt_own_trusted != NULL) {
+                own_trusted = load_certstore(opt_own_trusted,
+                                             "trusted certs for verifying own CMP signer cert");
+                ok = own_trusted != NULL
+                    && set1_store_parameters(own_trusted)
+                    && truststore_set_host_etc(own_trusted, NULL);
+            }
+            ok = ok && OSSL_CMP_CTX_build_cert_chain(ctx, own_trusted, certs);
         }
+        X509_STORE_free(own_trusted);
         sk_X509_pop_free(certs, X509_free);
         if (!ok)
             goto err;
+    } else if (opt_own_trusted != NULL) {
+        CMP_warn("-own_trusted option is ignored without -cert");
     }
 
     if (!setup_certs(opt_extracerts, "extra certificates for CMP", ctx,
@@ -2400,6 +2411,9 @@ static int get_opts(int argc, char **argv)
         case OPT_CERT:
             opt_cert = opt_str("cert");
             break;
+        case OPT_OWN_TRUSTED:
+            opt_own_trusted = opt_str("own_trusted");
+            break;
         case OPT_KEY:
             opt_key = opt_str("key");
             break;
diff --git a/crypto/cmp/cmp_ctx.c b/crypto/cmp/cmp_ctx.c
index 50c5d0e061..adb3ff564b 100644
--- a/crypto/cmp/cmp_ctx.c
+++ b/crypto/cmp/cmp_ctx.c
@@ -742,6 +742,34 @@ int OSSL_CMP_CTX_push1_subjectAltName(OSSL_CMP_CTX *ctx,
  */
 DEFINE_OSSL_CMP_CTX_set1_up_ref(cert, X509)
 
+int OSSL_CMP_CTX_build_cert_chain(OSSL_CMP_CTX *ctx, X509_STORE *own_trusted,
+                                  STACK_OF(X509) *candidates)
+{
+    STACK_OF(X509) *chain;
+
+    if (ctx == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+
+    if (ctx->untrusted_certs != NULL ?
+        !X509_add_certs(ctx->untrusted_certs, candidates,
+                        X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP) :
+        !OSSL_CMP_CTX_set1_untrusted_certs(ctx, candidates))
+        return 0;
+
+    ossl_cmp_debug(ctx, "trying to build chain for own CMP signer cert");
+    chain = ossl_cmp_build_cert_chain(ctx->libctx, ctx->propq, own_trusted,
+                                      ctx->untrusted_certs, ctx->cert);
+    if (chain == NULL) {
+        CMPerr(0, CMP_R_FAILED_BUILDING_OWN_CHAIN);
+        return 0;
+    }
+    ossl_cmp_debug(ctx, "success building chain for own CMP signer cert");
+    sk_X509_pop_free(chain, X509_free); /* TODO(3.0) replace this by 'ctx->chain = chain;' when ctx->chain is available */    
+    return 1;
+}
+
 /*
  * Set the old certificate that we are updating in KUR
  * or the certificate to be revoked in RR, respectively.
diff --git a/crypto/cmp/cmp_err.c b/crypto/cmp/cmp_err.c
index 19d1556426..260e8386d5 100644
--- a/crypto/cmp/cmp_err.c
+++ b/crypto/cmp/cmp_err.c
@@ -73,6 +73,8 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
     "error validating protection"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_VALIDATING_SIGNATURE),
     "error validating signature"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILED_BUILDING_OWN_CHAIN),
+    "failed building own chain"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILED_EXTRACTING_PUBKEY),
     "failed extracting pubkey"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILURE_OBTAINING_RANDOM),
diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h
index a6e55cfd1b..e3dcb94704 100644
--- a/crypto/cmp/cmp_local.h
+++ b/crypto/cmp/cmp_local.h
@@ -747,6 +747,7 @@ int ossl_cmp_asn1_octet_string_set1_bytes(ASN1_OCTET_STRING **tgt,
                                           const unsigned char *bytes, int len);
 STACK_OF(X509)
     *ossl_cmp_build_cert_chain(OPENSSL_CTX *libctx, const char *propq,
+                               X509_STORE *store,
                                STACK_OF(X509) *certs, X509 *cert);
 
 /* from cmp_ctx.c */
diff --git a/crypto/cmp/cmp_protect.c b/crypto/cmp/cmp_protect.c
index 140b1720c8..2a008bd0bf 100644
--- a/crypto/cmp/cmp_protect.c
+++ b/crypto/cmp/cmp_protect.c
@@ -152,7 +152,7 @@ int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
 
             ossl_cmp_debug(ctx,
                            "trying to build chain for own CMP signer cert");
-            chain = ossl_cmp_build_cert_chain(ctx->libctx, ctx->propq,
+            chain = ossl_cmp_build_cert_chain(ctx->libctx, ctx->propq, NULL,
                                               ctx->untrusted_certs, ctx->cert);
             res = X509_add_certs(msg->extraCerts, chain,
                                  X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP
diff --git a/crypto/cmp/cmp_util.c b/crypto/cmp/cmp_util.c
index c4797f1691..c2ee9b6e0d 100644
--- a/crypto/cmp/cmp_util.c
+++ b/crypto/cmp/cmp_util.c
@@ -206,56 +206,49 @@ int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
 }
 
 /*-
- * Builds up the chain of intermediate CA certificates
- * starting from the given certificate <cert> as high up as possible using
- * the given list of candidate certificates, similarly to ssl_add_cert_chain().
+ * Builds a certificate chain starting from <cert>
+ * using the optional list of intermediate CA certificates <certs>.
+ * If <store> is NULL builds the chain as far down as possible, ignoring errors.
+ * Else the chain must reach a trust anchor contained in <store>.
  *
- * Intended use of this function is to find all the certificates above the trust
- * anchor needed to verify an EE's own certificate.  Those are supposed to be
- * included in the ExtraCerts field of every first CMP message of a transaction
- * when MSG_SIG_ALG is utilized.
+ * Returns NULL on error, else a pointer to a stack of (up_ref'ed) certificates
+ * starting with given EE certificate and followed by all available intermediate
+ * certificates down towards any trust anchor but without including the latter.
  *
- * NOTE: This allocates a stack and increments the reference count of each cert,
- * so when not needed any more the stack and all its elements should be freed.
+ * NOTE: If a non-NULL stack is returned the caller is responsible for freeing.
  * NOTE: In case there is more than one possibility for the chain,
  * OpenSSL seems to take the first one; check X509_verify_cert() for details.
- *
- * returns a pointer to a stack of (up_ref'ed) X509 certificates containing:
- *      - the EE certificate given in the function arguments (cert)
- *      - all intermediate certificates up the chain toward the trust anchor
- *        whereas the (self-signed) trust anchor is not included
- * returns NULL on error
  */
+/* TODO this should be of more general interest and thus be exported. */
 STACK_OF(X509)
     *ossl_cmp_build_cert_chain(OPENSSL_CTX *libctx, const char *propq,
+                               X509_STORE *store,
                                STACK_OF(X509) *certs, X509 *cert)
 {
     STACK_OF(X509) *chain = NULL, *result = NULL;
-    X509_STORE *store = X509_STORE_new();
+    X509_STORE *ts = store == NULL ? X509_STORE_new() : store;
     X509_STORE_CTX *csc = NULL;
 
-    if (certs == NULL || cert == NULL || store == NULL) {
+    if (ts == NULL || cert == NULL) {
         CMPerr(0, CMP_R_NULL_ARGUMENT);
         goto err;
     }
 
-    csc = X509_STORE_CTX_new_with_libctx(libctx, propq);
-    if (csc == NULL)
+    if ((csc = X509_STORE_CTX_new_with_libctx(libctx, propq)) == NULL)
         goto err;
-
-    if (!ossl_cmp_X509_STORE_add1_certs(store, certs, 0)
-            || !X509_STORE_CTX_init(csc, store, cert, NULL))
+    if (store == NULL && certs != NULL
+            && !ossl_cmp_X509_STORE_add1_certs(ts, certs, 0))
         goto err;
+    if (!X509_STORE_CTX_init(csc, ts, cert,
+                             store == NULL ? NULL : certs))
+        goto err;
+    /* disable any cert status/revocation checking etc. */
+    X509_VERIFY_PARAM_clear_flags(X509_STORE_CTX_get0_param(csc),
+                                  ~(X509_V_FLAG_USE_CHECK_TIME
+                                    | X509_V_FLAG_NO_CHECK_TIME));
 
-    (void)ERR_set_mark();
-    /*
-     * ignore return value as it would fail without trust anchor given in store
-     */
-    (void)X509_verify_cert(csc);
-
-    /* don't leave any new errors in the queue */
-    (void)ERR_pop_to_mark();
-
+    if (X509_verify_cert(csc) <= 0 && store != NULL)
+        goto err;
     chain = X509_STORE_CTX_get0_chain(csc);
 
     /* result list to store the up_ref'ed not self-signed certificates */
@@ -269,7 +262,8 @@ STACK_OF(X509)
     }
 
  err:
-    X509_STORE_free(store);
+    if (store == NULL)
+        X509_STORE_free(ts);
     X509_STORE_CTX_free(csc);
     return result;
 }
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 592fb6b50a..7c37a3e56e 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -2114,6 +2114,7 @@ CMP_R_ERROR_SETTING_CERTHASH:128:error setting certhash
 CMP_R_ERROR_UNEXPECTED_CERTCONF:160:error unexpected certconf
 CMP_R_ERROR_VALIDATING_PROTECTION:140:error validating protection
 CMP_R_ERROR_VALIDATING_SIGNATURE:171:error validating signature
+CMP_R_FAILED_BUILDING_OWN_CHAIN:164:failed building own chain
 CMP_R_FAILED_EXTRACTING_PUBKEY:141:failed extracting pubkey
 CMP_R_FAILURE_OBTAINING_RANDOM:110:failure obtaining random
 CMP_R_FAIL_INFO_OUT_OF_RANGE:129:fail info out of range
diff --git a/doc/internal/man3/ossl_cmp_msg_protect.pod b/doc/internal/man3/ossl_cmp_msg_protect.pod
index 6c33db6954..39f5146530 100644
--- a/doc/internal/man3/ossl_cmp_msg_protect.pod
+++ b/doc/internal/man3/ossl_cmp_msg_protect.pod
@@ -14,6 +14,7 @@ ossl_cmp_msg_add_extraCerts
 
  STACK_OF(X509)
      *ossl_cmp_build_cert_chain(OPENSSL_CTX *libctx, const char *propq,
+                                X509_STORE *store,
                                 STACK_OF(X509) *certs, X509 *cert);
  ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_CTX *ctx,
                                            const OSSL_CMP_MSG *msg);
@@ -22,19 +23,15 @@ ossl_cmp_msg_add_extraCerts
 
 =head1 DESCRIPTION
 
-ossl_cmp_build_cert_chain() builds up the chain of intermediate CA certificates
-starting from the given certificate I<cert> as high up as possible using
-the given list of candidate certificates, similarly to ssl_add_cert_chain().
+ossl_cmp_build_cert_chain() builds a certificate chain starting from I<cert>
+using the optional list of intermediate CA certificates I<certs>.
+If I<store> is NULL builds the chain as far down as possible, ignoring errors.
+Else the chain must reach a trust anchor contained in I<store>.
 It internally uses a B<X509_STORE_CTX> structure associated with the library
 context I<libctx> and property query string I<propq>, both of which may be NULL.
-Intended use of this function is to find all the certificates above the trust
-anchor needed to verify an EE's own certificate.
-Those are supposed to be included in the ExtraCerts field of every first
-CMP message of a transaction when MSG_SIG_ALG is utilized.
-This allocates a stack and increments the reference count of each cert,
-so when not needed any more the stack and all its elements should be freed.
+If a non-NULL stack is returned the caller is responsible for freeing it.
 In case there is more than one possibility for the chain,
-OpenSSL seems to take the first one; check X509_verify_cert() for details.
+OpenSSL seems to take the first one; check L<X509_verify_cert(3)> for details.
 
 ossl_cmp_calc_protection() calculates the protection for the given I<msg>
 according to the algorithm and parameters in the message header's protectionAlg
@@ -46,10 +43,10 @@ If there is a secretValue it selects PBMAC, else if there is a protection cert
 it selects Signature and uses L<ossl_cmp_msg_add_extraCerts(3)>.
 It also sets the protectionAlg field in the message header accordingly.
 
-ossl_cmp_msg_add_extraCerts() adds elements to the extraCerts field in the given
-message I<msg>. It tries to build the certificate chain of the client cert in
-the I<ctx> if present by using certificates in ctx->untrusted_certs;
-if no untrusted certs are set, it will at least add the client certificate.
+ossl_cmp_msg_add_extraCerts() adds elements to the extraCerts field in I<msg>.
+If signature-based message protection is used it adds first the CMP signer cert
+ctx->cert and then its chain ctx->chain. If this chain is not present in I<ctx>
+tries to build it using ctx->untrusted_certs and caches the result in ctx->chain.
 In any case all the certificates explicitly specified to be sent out (i.e.,
 I<ctx->extraCertsOut>) are added. Note that it will NOT add the root certificate
 of the chain, i.e, the trust anchor (unless it is part of extraCertsOut).
@@ -62,9 +59,8 @@ CMP is defined in RFC 4210 (and CRMF in RFC 4211).
 
 ossl_cmp_build_cert_chain() returns NULL on error,
 else a pointer to a stack of (up_ref'ed) certificates
-containing the EE certificate given in the function arguments (cert)
-and all intermediate certificates up the chain toward the trust anchor.
-The (self-signed) trust anchor is not included.
+starting with given EE certificate and followed by all available intermediate
+certificates down towards (but excluding) any trusted root certificate.
 
 ossl_cmp_calc_protection() returns the protection on success, else NULL.
 
diff --git a/doc/man1/openssl-cmp.pod.in b/doc/man1/openssl-cmp.pod.in
index d91bd31684..3dc193cd4d 100644
--- a/doc/man1/openssl-cmp.pod.in
+++ b/doc/man1/openssl-cmp.pod.in
@@ -32,6 +32,7 @@ B<openssl> B<cmp>
 [B<-ref> I<value>]
 [B<-secret> I<arg>]
 [B<-cert> I<filename>]
+[B<-own_trusted> I<filenames>]
 [B<-key> I<filename>]
 [B<-keypass> I<arg>]
 [B<-digest> I<name>]
@@ -617,7 +618,7 @@ B<PASS PHRASE ARGUMENTS> section in L<openssl(1)>.
 
 =item B<-cert> I<filename>
 
-The client's current certificate.
+The client's current CMP signer certificate.
 Requires the corresponding key to be given with B<-key>.
 The subject of this certificate will be used as sender of outgoing CMP messages,
 while the subject of B<-oldcert> or B<-subjectName> may provide fallback values.
@@ -629,6 +630,16 @@ For Key Update Request (KUR) messages this is also used as
 the certificate to be updated if the B<-oldcert> option is not given.
 If the file includes further certs, they are appended to the untrusted certs.
 
+=item B<-own_trusted> I<filenames>
+
+If this list of certificates is provided then the chain built for
+the CMP signer certificate given with the B<-cert> option is verified
+using the given certificates as trust anchors.
+
+Multiple filenames may be given, separated by commas and/or whitespace
+(where in the latter case the whole argument must be enclosed in "...").
+Each source may contain multiple certificates.
+
 =item B<-key> I<filename>
 
 The corresponding private key file for the client's current certificate given in
@@ -694,6 +705,7 @@ The only value with effect is B<ENGINE>.
 =item B<-otherpass> I<arg>
 
 Pass phrase source for certificate given with the B<-trusted>, B<-untrusted>,
+B<-own_trusted>,
 B<-out_trusted>, B<-extracerts>, B<-tls_extra>, or B<-tls_trusted> options.
 If not given here, the password will be prompted for if needed.
 
diff --git a/doc/man3/OSSL_CMP_CTX_new.pod b/doc/man3/OSSL_CMP_CTX_new.pod
index fda5150434..f4425d511a 100644
--- a/doc/man3/OSSL_CMP_CTX_new.pod
+++ b/doc/man3/OSSL_CMP_CTX_new.pod
@@ -29,6 +29,7 @@ OSSL_CMP_CTX_get0_trustedStore,
 OSSL_CMP_CTX_set1_untrusted_certs,
 OSSL_CMP_CTX_get0_untrusted_certs,
 OSSL_CMP_CTX_set1_cert,
+OSSL_CMP_CTX_build_cert_chain,
 OSSL_CMP_CTX_set1_pkey,
 OSSL_CMP_CTX_set1_referenceValue,
 OSSL_CMP_CTX_set1_secretValue,
@@ -104,6 +105,8 @@ OSSL_CMP_CTX_set1_senderNonce
 
  /* client authentication: */
  int OSSL_CMP_CTX_set1_cert(OSSL_CMP_CTX *ctx, X509 *cert);
+ int OSSL_CMP_CTX_build_cert_chain(OSSL_CMP_CTX *ctx, X509_STORE *own_trusted,
+                                   STACK_OF(X509) *candidates);
  int OSSL_CMP_CTX_set1_pkey(OSSL_CMP_CTX *ctx, EVP_PKEY *pkey);
  int OSSL_CMP_CTX_set1_referenceValue(OSSL_CMP_CTX *ctx,
                                       const unsigned char *ref, int len);
@@ -436,6 +439,20 @@ messages, while the subject of any cert set via B<OSSL_CMP_CTX_set1_oldCert()>
 and any value set via B<OSSL_CMP_CTX_set1_subjectName()> are used as fallback.
 The B<cert> argument may be NULL to clear the entry.
 
+OSSL_CMP_CTX_build_cert_chain() builds a certificate chain for the CMP signer
+certificate previously set in the B<ctx>. It adds the optional B<candidates>,
+a list of intermediate CA certs that may already constitute the targeted chain,
+to the untrusted certs that may already exist in the B<ctx>.
+Then the function uses this augumented set of certs for chain construction.
+If I<own_trusted> is NULL it builds the chain as far down as possible and
+ignores any verification errors. Else the CMP signer certificate must be
+verifiable where the chain reaches a trust anchor contained in I<own_trusted>.
+On success the function stores the resulting chain in B<ctx>
+for inclusion in the extraCerts field of signature-protected messages.
+Calling this function is optional; by default a chain construction
+is performed on demand that is equivalent to calling this function
+with the B<candidates> and I<own_trusted> arguments being NULL.
+
 OSSL_CMP_CTX_set1_pkey() sets the private key corresponding to the
 protection certificate B<cert> set via B<OSSL_CMP_CTX_set1_cert()>.
 This key is used create signature-based protection (protectionAlg = MSG_SIG_ALG)
diff --git a/include/openssl/cmp.h b/include/openssl/cmp.h
index d12d48ba4f..edab120364 100644
--- a/include/openssl/cmp.h
+++ b/include/openssl/cmp.h
@@ -295,6 +295,8 @@ int OSSL_CMP_CTX_set1_untrusted_certs(OSSL_CMP_CTX *ctx, STACK_OF(X509) *certs);
 STACK_OF(X509) *OSSL_CMP_CTX_get0_untrusted_certs(const OSSL_CMP_CTX *ctx);
 /* client authentication: */
 int OSSL_CMP_CTX_set1_cert(OSSL_CMP_CTX *ctx, X509 *cert);
+int OSSL_CMP_CTX_build_cert_chain(OSSL_CMP_CTX *ctx, X509_STORE *own_trusted,
+                                  STACK_OF(X509) *candidates);
 int OSSL_CMP_CTX_set1_pkey(OSSL_CMP_CTX *ctx, EVP_PKEY *pkey);
 int OSSL_CMP_CTX_set1_referenceValue(OSSL_CMP_CTX *ctx,
                                      const unsigned char *ref, int len);
@@ -322,6 +324,8 @@ int OSSL_CMP_CTX_push0_genm_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav);
 /* certificate confirmation: */
 typedef int (*OSSL_CMP_certConf_cb_t) (OSSL_CMP_CTX *ctx, X509 *cert,
                                        int fail_info, const char **txt);
+int OSSL_CMP_certConf_cb(OSSL_CMP_CTX *ctx, X509 *cert, int fail_info,
+                         const char **text);
 int OSSL_CMP_CTX_set_certConf_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_certConf_cb_t cb);
 int OSSL_CMP_CTX_set_certConf_cb_arg(OSSL_CMP_CTX *ctx, void *arg);
 void *OSSL_CMP_CTX_get_certConf_cb_arg(const OSSL_CMP_CTX *ctx);
@@ -437,8 +441,6 @@ X509 *OSSL_CMP_exec_certreq(OSSL_CMP_CTX *ctx, int req_type,
     OSSL_CMP_exec_certreq(ctx, OSSL_CMP_KUR, NULL)
 int OSSL_CMP_try_certreq(OSSL_CMP_CTX *ctx, int req_type,
                          const OSSL_CRMF_MSG *crm, int *checkAfter);
-int OSSL_CMP_certConf_cb(OSSL_CMP_CTX *ctx, X509 *cert, int fail_info,
-                         const char **text);
 X509 *OSSL_CMP_exec_RR_ses(OSSL_CMP_CTX *ctx);
 STACK_OF(OSSL_CMP_ITAV) *OSSL_CMP_exec_GENM_ses(OSSL_CMP_CTX *ctx);
 
diff --git a/include/openssl/cmperr.h b/include/openssl/cmperr.h
index 2ae82974a9..190e1a96bd 100644
--- a/include/openssl/cmperr.h
+++ b/include/openssl/cmperr.h
@@ -66,6 +66,7 @@ int ERR_load_CMP_strings(void);
 #  define CMP_R_ERROR_UNEXPECTED_CERTCONF                  160
 #  define CMP_R_ERROR_VALIDATING_PROTECTION                140
 #  define CMP_R_ERROR_VALIDATING_SIGNATURE                 171
+#  define CMP_R_FAILED_BUILDING_OWN_CHAIN                  164
 #  define CMP_R_FAILED_EXTRACTING_PUBKEY                   141
 #  define CMP_R_FAILURE_OBTAINING_RANDOM                   110
 #  define CMP_R_FAIL_INFO_OUT_OF_RANGE                     129
diff --git a/test/cmp_protect_test.c b/test/cmp_protect_test.c
index 66cc6af370..7132ccc5cb 100644
--- a/test/cmp_protect_test.c
+++ b/test/cmp_protect_test.c
@@ -333,8 +333,9 @@ static int execute_cmp_build_cert_chain_test(CMP_PROTECT_TEST_FIXTURE *fixture)
 {
     int ret = 0;
     OSSL_CMP_CTX *ctx = fixture->cmp_ctx;
+    X509_STORE *store;
     STACK_OF(X509) *chain =
-        ossl_cmp_build_cert_chain(ctx->libctx, ctx->propq,
+        ossl_cmp_build_cert_chain(ctx->libctx, ctx->propq, NULL,
                                   fixture->certs, fixture->cert);
 
     if (TEST_ptr(chain)) {
@@ -342,12 +343,30 @@ static int execute_cmp_build_cert_chain_test(CMP_PROTECT_TEST_FIXTURE *fixture)
         ret = TEST_int_eq(0, STACK_OF_X509_cmp(chain, fixture->chain));
         sk_X509_pop_free(chain, X509_free);
     }
+    if (!ret)
+        return 0;
+
+    if (TEST_ptr(store = X509_STORE_new())
+            && TEST_true(X509_STORE_add_cert(store, root))) {
+        X509_VERIFY_PARAM_set_flags(X509_STORE_get0_param(store),
+                                    X509_V_FLAG_NO_CHECK_TIME);
+        chain = ossl_cmp_build_cert_chain(ctx->libctx, ctx->propq,
+                                          store, fixture->certs, fixture->cert);
+        ret = TEST_int_eq(fixture->expected, chain != NULL);
+        if (ret && chain != NULL) {
+            /* Check whether chain built is equal to the expected one */
+            ret = TEST_int_eq(0, STACK_OF_X509_cmp(chain, fixture->chain));
+            sk_X509_pop_free(chain, X509_free);
+        }
+    }
+    X509_STORE_free(store);
     return ret;
 }
 
 static int test_cmp_build_cert_chain(void)
 {
     SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
     fixture->cert = endentity2;
     if (!TEST_ptr(fixture->certs = sk_X509_new_null())
             || !TEST_ptr(fixture->chain = sk_X509_new_null())
@@ -366,6 +385,7 @@ static int test_cmp_build_cert_chain(void)
 static int test_cmp_build_cert_chain_missing_intermediate(void)
 {
     SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->expected = 0;
     fixture->cert = endentity2;
     if (!TEST_ptr(fixture->certs = sk_X509_new_null())
             || !TEST_ptr(fixture->chain = sk_X509_new_null())
@@ -379,9 +399,10 @@ static int test_cmp_build_cert_chain_missing_intermediate(void)
     return result;
 }
 
-static int test_cmp_build_cert_chain_missing_root(void)
+static int test_cmp_build_cert_chain_no_root(void)
 {
     SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
     fixture->cert = endentity2;
     if (!TEST_ptr(fixture->certs = sk_X509_new_null())
             || !TEST_ptr(fixture->chain = sk_X509_new_null())
@@ -399,6 +420,7 @@ static int test_cmp_build_cert_chain_missing_root(void)
 static int test_cmp_build_cert_chain_no_certs(void)
 {
     SETUP_TEST_FIXTURE(CMP_PROTECT_TEST_FIXTURE, set_up);
+    fixture->expected = 0;
     fixture->cert = endentity2;
     if (!TEST_ptr(fixture->certs = sk_X509_new_null())
             || !TEST_ptr(fixture->chain = sk_X509_new_null())
@@ -556,7 +578,7 @@ int setup_tests(void)
 
 #ifndef OPENSSL_NO_EC
     ADD_TEST(test_cmp_build_cert_chain);
-    ADD_TEST(test_cmp_build_cert_chain_missing_root);
+    ADD_TEST(test_cmp_build_cert_chain_no_root);
     ADD_TEST(test_cmp_build_cert_chain_missing_intermediate);
     ADD_TEST(test_cmp_build_cert_chain_no_certs);
 #endif
diff --git a/util/libcrypto.num b/util/libcrypto.num
index cfe1cb8bc6..25ee44144b 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -4774,6 +4774,7 @@ OSSL_CMP_CTX_set1_untrusted_certs       ?	3_0_0	EXIST::FUNCTION:CMP
 OSSL_CMP_CTX_get0_untrusted_certs       ?	3_0_0	EXIST::FUNCTION:CMP
 OSSL_CMP_CTX_set1_cert                  ?	3_0_0	EXIST::FUNCTION:CMP
 OSSL_CMP_CTX_set1_pkey                  ?	3_0_0	EXIST::FUNCTION:CMP
+OSSL_CMP_CTX_build_cert_chain           ?	3_0_0	EXIST::FUNCTION:CMP
 OSSL_CMP_CTX_set1_referenceValue        ?	3_0_0	EXIST::FUNCTION:CMP
 OSSL_CMP_CTX_set1_secretValue           ?	3_0_0	EXIST::FUNCTION:CMP
 OSSL_CMP_CTX_set1_recipient             ?	3_0_0	EXIST::FUNCTION:CMP


More information about the openssl-commits mailing list