]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
CMP: add support for genm with rootCaCert and genp with rootCaKeyUpdate
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>
Sat, 17 Sep 2022 08:56:21 +0000 (10:56 +0200)
committerPauli <pauli@openssl.org>
Sun, 16 Jul 2023 22:48:36 +0000 (08:48 +1000)
Reviewed-by: Tomas Mraz <tomas@openssl.org>
Reviewed-by: Paul Dale <pauli@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/21129)

22 files changed:
apps/cmp.c
apps/include/cmp_mock_srv.h
apps/lib/cmp_mock_srv.c
crypto/cmp/cmp_asn.c
crypto/cmp/cmp_err.c
crypto/cmp/cmp_genm.c
crypto/cmp/cmp_local.h
crypto/err/openssl.txt
doc/internal/man3/ossl_cmp_mock_srv_new.pod
doc/man1/openssl-cmp.pod.in
doc/man3/OSSL_CMP_ITAV_new_caCerts.pod
doc/man3/OSSL_CMP_exec_certreq.pod
include/openssl/cmp.h.in
include/openssl/cmperr.h
test/recipes/80-test_cmp_http.t
test/recipes/80-test_cmp_http_data/Mock/newWithNew.pem [new file with mode: 0644]
test/recipes/80-test_cmp_http_data/Mock/newWithOld.pem [new file with mode: 0644]
test/recipes/80-test_cmp_http_data/Mock/oldWithNew.pem [new file with mode: 0644]
test/recipes/80-test_cmp_http_data/Mock/oldWithOld.pem [new file with mode: 0644]
test/recipes/80-test_cmp_http_data/Mock/server.cnf
test/recipes/80-test_cmp_http_data/test_commands.csv
util/libcrypto.num

index d56a5e451cba0e0399aeeddaf38c272a5a420252..dbc609a2e00375ad2cedf87ae390aa626d3a913a 100644 (file)
@@ -89,6 +89,10 @@ static int opt_unprotected_errors = 0;
 static char *opt_srvcertout = NULL;
 static char *opt_extracertsout = NULL;
 static char *opt_cacertsout = NULL;
+static char *opt_oldwithold = NULL;
+static char *opt_newwithnew = NULL;
+static char *opt_newwithold = NULL;
+static char *opt_oldwithnew = NULL;
 
 /* client authentication */
 static char *opt_ref = NULL;
@@ -181,6 +185,10 @@ static char *opt_ref_cert = NULL;
 static char *opt_rsp_cert = NULL;
 static char *opt_rsp_extracerts = NULL;
 static char *opt_rsp_capubs = NULL;
+static char *opt_rsp_newwithnew = NULL;
+static char *opt_rsp_newwithold = NULL;
+static char *opt_rsp_oldwithnew = NULL;
+
 static int opt_poll_count = 0;
 static int opt_check_after = 1;
 static int opt_grant_implicitconf = 0;
@@ -224,6 +232,7 @@ typedef enum OPTION_choice {
     OPT_EXPECT_SENDER,
     OPT_IGNORE_KEYUSAGE, OPT_UNPROTECTED_ERRORS,
     OPT_SRVCERTOUT, OPT_EXTRACERTSOUT, OPT_CACERTSOUT,
+    OPT_OLDWITHOLD, OPT_NEWWITHNEW, OPT_NEWWITHOLD, OPT_OLDWITHNEW,
 
     OPT_REF, OPT_SECRET, OPT_CERT, OPT_OWN_TRUSTED, OPT_KEY, OPT_KEYPASS,
     OPT_DIGEST, OPT_MAC, OPT_EXTRACERTS,
@@ -254,6 +263,7 @@ typedef enum OPTION_choice {
     OPT_SRV_CERT, OPT_SRV_KEY, OPT_SRV_KEYPASS,
     OPT_SRV_TRUSTED, OPT_SRV_UNTRUSTED,
     OPT_REF_CERT, OPT_RSP_CERT, OPT_RSP_EXTRACERTS, OPT_RSP_CAPUBS,
+    OPT_RSP_NEWWITHNEW, OPT_RSP_NEWWITHOLD, OPT_RSP_OLDWITHNEW,
     OPT_POLL_COUNT, OPT_CHECK_AFTER,
     OPT_GRANT_IMPLICITCONF,
     OPT_PKISTATUS, OPT_FAILURE,
@@ -278,7 +288,9 @@ const OPTIONS cmp_options[] = {
     OPT_SECTION("Generic message"),
     {"cmd", OPT_CMD, 's', "CMP request to send: ir/cr/kur/p10cr/rr/genm"},
     {"infotype", OPT_INFOTYPE, 's',
-     "InfoType name for requesting specific info in genm, e.g. 'caCerts'"},
+     "InfoType name for requesting specific info in genm, with specific support"},
+    {OPT_MORE_STR, 0, 0,
+     "for 'caCerts' and 'rootCaCert'"},
     {"geninfo", OPT_GENINFO, 's',
      "generalInfo integer values to place in request PKIHeader with given OID"},
     {OPT_MORE_STR, 0, 0,
@@ -399,6 +411,14 @@ const OPTIONS cmp_options[] = {
      "File to save extra certificates received in the extraCerts field"},
     {"cacertsout", OPT_CACERTSOUT, 's',
      "File to save CA certs received in caPubs field or genp with id-it-caCerts"},
+    { "oldwithold", OPT_OLDWITHOLD, 's',
+      "Root CA certificate to request update for in genm of type rootCaCert"},
+    { "newwithnew", OPT_NEWWITHNEW, 's',
+      "File to save NewWithNew cert received in genp of type rootCaKeyUpdate"},
+    { "newwithold", OPT_NEWWITHOLD, 's',
+      "File to save NewWithOld cert received in genp of type rootCaKeyUpdate"},
+    { "oldwithnew", OPT_OLDWITHNEW, 's',
+      "File to save OldWithNew cert received in genp of type rootCaKeyUpdate"},
 
     OPT_SECTION("Client authentication"),
     {"ref", OPT_REF, 's',
@@ -517,6 +537,12 @@ const OPTIONS cmp_options[] = {
      "Extra certificates to be included in mock certification responses"},
     {"rsp_capubs", OPT_RSP_CAPUBS, 's',
      "CA certificates to be included in mock ip response"},
+    {"rsp_newwithnew", OPT_RSP_NEWWITHNEW, 's',
+     "New root CA certificate to include in genp of type rootCaKeyUpdate"},
+    {"rsp_newwithold", OPT_RSP_NEWWITHOLD, 's',
+     "NewWithOld transition cert to include in genp of type rootCaKeyUpdate"},
+    {"rsp_oldwithnew", OPT_RSP_OLDWITHNEW, 's',
+     "OldWithNew transition cert to include in genp of type rootCaKeyUpdate"},
     {"poll_count", OPT_POLL_COUNT, 'N',
      "Number of times the client must poll before receiving a certificate"},
     {"check_after", OPT_CHECK_AFTER, 'N',
@@ -584,6 +610,7 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */
     {&opt_expect_sender},
     {(char **)&opt_ignore_keyusage}, {(char **)&opt_unprotected_errors},
     {&opt_srvcertout}, {&opt_extracertsout}, {&opt_cacertsout},
+    {&opt_oldwithold}, {&opt_newwithnew}, {&opt_newwithold}, {&opt_oldwithnew},
 
     {&opt_ref}, {&opt_secret},
     {&opt_cert}, {&opt_own_trusted}, {&opt_key}, {&opt_keypass},
@@ -614,6 +641,8 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */
     {&opt_srv_cert}, {&opt_srv_key}, {&opt_srv_keypass},
     {&opt_srv_trusted}, {&opt_srv_untrusted},
     {&opt_ref_cert}, {&opt_rsp_cert}, {&opt_rsp_extracerts}, {&opt_rsp_capubs},
+    {&opt_rsp_newwithnew}, {&opt_rsp_newwithold}, {&opt_rsp_oldwithnew},
+
     {(char **)&opt_poll_count}, {(char **)&opt_check_after},
     {(char **)&opt_grant_implicitconf},
     {(char **)&opt_pkistatus}, {(char **)&opt_failure},
@@ -929,8 +958,23 @@ static X509_STORE *load_trusted(char *input, int for_new_cert, const char *desc)
     return NULL;
 }
 
-typedef int (*add_X509_stack_fn_t)(void *ctx, const STACK_OF(X509) *certs);
+typedef int (*add_X509_fn_t)(void *ctx, const X509 *cert);
+static int setup_cert(void *ctx, const char *file, const char *pass,
+                      const char *desc, add_X509_fn_t set1_fn)
+{
+    X509 *cert;
+    int ok;
+
+    if (file == NULL)
+        return 1;
+    if ((cert = load_cert_pwd(file, pass, desc)) == NULL)
+        return 0;
+    ok = (*set1_fn)(ctx, cert);
+    X509_free(cert);
+    return ok;
+}
 
+typedef int (*add_X509_stack_fn_t)(void *ctx, const STACK_OF(X509) *certs);
 static int setup_certs(char *files, const char *desc, void *ctx,
                        add_X509_stack_fn_t set1_fn)
 {
@@ -1043,16 +1087,10 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine)
         CMP_err("must give both -srv_cert and -srv_key options or neither");
         goto err;
     }
-    if (opt_srv_cert != NULL) {
-        X509 *srv_cert = load_cert_pwd(opt_srv_cert, opt_srv_keypass,
-                                       "certificate of the mock server");
-
-        if (srv_cert == NULL || !OSSL_CMP_CTX_set1_cert(ctx, srv_cert)) {
-            X509_free(srv_cert);
-            goto err;
-        }
-        X509_free(srv_cert);
-    }
+    if (!setup_cert(ctx, opt_srv_cert, opt_srv_keypass,
+                    "signer certificate of the mock server",
+                    (add_X509_fn_t)OSSL_CMP_CTX_set1_cert))
+        goto err;
     if (opt_srv_key != NULL) {
         EVP_PKEY *pkey = load_key_pwd(opt_srv_key, opt_keyform,
                                       opt_srv_keypass,
@@ -1082,31 +1120,17 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine)
                      (add_X509_stack_fn_t)OSSL_CMP_CTX_set1_untrusted))
         goto err;
 
-    if (opt_ref_cert != NULL) {
-        X509 *cert = load_cert_pwd(opt_ref_cert, opt_keypass,
-                                   "reference cert to be expected by the mock server");
-
-        if (cert == NULL)
-            goto err;
-        if (!ossl_cmp_mock_srv_set1_refCert(srv_ctx, cert)) {
-            X509_free(cert);
+    if (!setup_cert(srv_ctx, opt_ref_cert, opt_otherpass,
+                    "reference cert to be expected by the mock server",
+                    (add_X509_fn_t)ossl_cmp_mock_srv_set1_refCert))
             goto err;
-        }
-        X509_free(cert);
-    }
     if (opt_rsp_cert == NULL) {
         CMP_warn("no -rsp_cert given for mock server");
     } else {
-        X509 *cert = load_cert_pwd(opt_rsp_cert, opt_keypass,
-                                   "cert to be returned by the mock server");
-
-        if (cert == NULL)
-            goto err;
-        if (!ossl_cmp_mock_srv_set1_certOut(srv_ctx, cert)) {
-            X509_free(cert);
+        if (!setup_cert(srv_ctx, opt_rsp_cert, opt_keypass,
+                        "cert the mock server returns on certificate requests",
+                        (add_X509_fn_t)ossl_cmp_mock_srv_set1_certOut))
             goto err;
-        }
-        X509_free(cert);
     }
     if (!setup_certs(opt_rsp_extracerts,
                      "CMP extra certificates for mock server", srv_ctx,
@@ -1115,6 +1139,16 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine)
     if (!setup_certs(opt_rsp_capubs, "caPubs for mock server", srv_ctx,
                      (add_X509_stack_fn_t)ossl_cmp_mock_srv_set1_caPubsOut))
         goto err;
+    if (!setup_cert(srv_ctx, opt_rsp_newwithnew, opt_otherpass,
+                    "NewWithNew cert the mock server returns in rootCaKeyUpdate",
+                    (add_X509_fn_t)ossl_cmp_mock_srv_set1_newWithNew)
+        || !setup_cert(srv_ctx, opt_rsp_newwithold, opt_otherpass,
+                       "NewWithOld cert the mock server returns in rootCaKeyUpdate",
+                       (add_X509_fn_t)ossl_cmp_mock_srv_set1_newWithOld)
+        || !setup_cert(srv_ctx, opt_rsp_oldwithnew, opt_otherpass,
+                       "OldWithNew cert the mock server returns in rootCaKeyUpdate",
+                       (add_X509_fn_t)ossl_cmp_mock_srv_set1_oldWithNew))
+        goto err;
     (void)ossl_cmp_mock_srv_set_pollCount(srv_ctx, opt_poll_count);
     (void)ossl_cmp_mock_srv_set_checkAfterTime(srv_ctx, opt_check_after);
     if (opt_grant_implicitconf)
@@ -1171,10 +1205,6 @@ static int setup_verification_ctx(OSSL_CMP_CTX *ctx)
         return 0;
 
     if (opt_srvcert != NULL || opt_trusted != NULL) {
-        X509 *srvcert;
-        X509_STORE *ts;
-        int ok;
-
         if (opt_srvcert != NULL) {
             if (opt_trusted != NULL) {
                 CMP_warn("-trusted option is ignored since -srvcert option is present");
@@ -1184,14 +1214,14 @@ static int setup_verification_ctx(OSSL_CMP_CTX *ctx)
                 CMP_warn("-recipient option is ignored since -srvcert option is present");
                 opt_recipient = NULL;
             }
-            srvcert = load_cert_pwd(opt_srvcert, opt_otherpass,
-                                    "directly trusted CMP server certificate");
-            ok = srvcert != NULL && OSSL_CMP_CTX_set1_srvCert(ctx, srvcert);
-            X509_free(srvcert);
-            if (!ok)
+            if (!setup_cert(ctx, opt_srvcert, opt_otherpass,
+                            "directly trusted CMP server certificate",
+                            (add_X509_fn_t)OSSL_CMP_CTX_set1_srvCert))
                 return 0;
         }
         if (opt_trusted != NULL) {
+            X509_STORE *ts;
+
             /*
              * the 0 arg below clears any expected host/ip/email address;
              * opt_expect_sender is used instead
@@ -1408,7 +1438,7 @@ static int setup_protection_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine)
         CMP_err("must give -ref if no -cert and no -subject given");
         return 0;
     }
-    if (!opt_secret && ((opt_cert == NULL) != (opt_key == NULL))) {
+    if (opt_secret == NULL && ((opt_cert == NULL) != (opt_key == NULL))) {
         CMP_err("must give both -cert and -key options or neither");
         return 0;
     }
@@ -1786,22 +1816,13 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine)
         if (opt_cmd == CMP_GENM) {
             CMP_warn("-oldcert option is ignored for 'genm' command");
         } else {
-            X509 *oldcert = load_cert_pwd(opt_oldcert, opt_keypass,
-                                          opt_cmd == CMP_KUR ?
-                                          "certificate to be updated" :
-                                          opt_cmd == CMP_RR ?
-                                          "certificate to be revoked" :
-                                          "reference certificate (oldcert)");
-            /* opt_keypass needed if opt_oldcert is an encrypted PKCS#12 file */
-
-            if (oldcert == NULL)
-                return 0;
-            if (!OSSL_CMP_CTX_set1_oldCert(ctx, oldcert)) {
-                X509_free(oldcert);
-                CMP_err("out of memory");
+            if (!setup_cert(ctx, opt_oldcert, opt_keypass,
+                            /* needed if opt_oldcert is encrypted PKCS12 file */
+                            opt_cmd == CMP_KUR ? "certificate to be updated" :
+                            opt_cmd == CMP_RR ? "certificate to be revoked" :
+                            "reference certificate (oldcert)",
+                            (add_X509_fn_t)OSSL_CMP_CTX_set1_oldCert))
                 return 0;
-            }
-            X509_free(oldcert);
         }
     }
     cleanse(opt_keypass);
@@ -1969,6 +1990,18 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine)
             goto err;
         }
     }
+    if (opt_cmd != CMP_GENM || opt_infotype != NID_id_it_rootCaCert) {
+        const char *msg = "option is ignored unless -cmd 'genm' and -infotype rootCaCert is given";
+
+        if (opt_oldwithold != NULL)
+            CMP_warn1("-oldwithold %s", msg);
+        if (opt_newwithnew != NULL)
+            CMP_warn1("-newwithnew %s", msg);
+        if (opt_newwithold != NULL)
+            CMP_warn1("-newwithold %s", msg);
+        if (opt_oldwithnew != NULL)
+            CMP_warn1("-oldwithnew %s", msg);
+    }
 
     if (!setup_verification_ctx(ctx))
         goto err;
@@ -2549,6 +2582,18 @@ static int get_opts(int argc, char **argv)
         case OPT_CACERTSOUT:
             opt_cacertsout = opt_str();
             break;
+        case OPT_OLDWITHOLD:
+            opt_oldwithold = opt_str();
+            break;
+        case OPT_NEWWITHNEW:
+            opt_newwithnew = opt_str();
+            break;
+        case OPT_NEWWITHOLD:
+            opt_newwithold = opt_str();
+            break;
+        case OPT_OLDWITHNEW:
+            opt_oldwithnew = opt_str();
+            break;
 
         case OPT_V_CASES:
             if (!opt_verify(o, vpm))
@@ -2727,6 +2772,15 @@ static int get_opts(int argc, char **argv)
         case OPT_RSP_CAPUBS:
             opt_rsp_capubs = opt_str();
             break;
+        case OPT_RSP_NEWWITHNEW:
+            opt_rsp_newwithnew = opt_str();
+            break;
+        case OPT_RSP_NEWWITHOLD:
+            opt_rsp_newwithold = opt_str();
+            break;
+        case OPT_RSP_OLDWITHNEW:
+            opt_rsp_oldwithnew = opt_str();
+            break;
         case OPT_POLL_COUNT:
             opt_poll_count = opt_int_arg();
             break;
@@ -2905,6 +2959,49 @@ static int do_genm(OSSL_CMP_CTX *ctx)
             return 0;
         }
         return 1;
+    } else if (opt_infotype == NID_id_it_rootCaCert) {
+        X509 *oldwithold = NULL;
+        X509 *newwithnew = NULL;
+        X509 *newwithold = NULL;
+        X509 *oldwithnew = NULL;
+        int res = 0;
+
+        if (opt_newwithnew == NULL) {
+            CMP_err("Missing -newwithnew option for -infotype rootCaCert");
+            return 0;
+        }
+        if (opt_oldwithold == NULL) {
+            CMP_warn("No -oldwithold given, will use all certs given with -trusted as trust anchors for verifying the newWithNew cert");
+        } else {
+            oldwithold = load_cert_pwd(opt_oldwithold, opt_otherpass,
+                                       "OldWithOld cert for genm with -infotype rootCaCert");
+            if (oldwithold == NULL)
+                goto end_upd;
+        }
+        if (!OSSL_CMP_get1_rootCaKeyUpdate(ctx, oldwithold, &newwithnew,
+                                           &newwithold, &oldwithnew))
+            goto end_upd;
+        /* At this point might check authorization of response sender/origin */
+
+        if (newwithnew == NULL)
+            CMP_info("no root CA certificate update available");
+        else if (oldwithold == NULL && oldwithnew != NULL)
+            CMP_warn("oldWithNew certificate received in genp for verifying oldWithOld, but oldWithOld was not provided");
+
+        if (save_cert_or_delete(newwithnew, opt_newwithnew,
+                                "NewWithNew cert from genp")
+            && save_cert_or_delete(newwithold, opt_newwithold,
+                                   "NewWithOld cert from genp")
+            && save_cert_or_delete(oldwithnew, opt_oldwithnew,
+                                   "OldWithNew cert from genp"))
+            res = 1;
+
+        X509_free(newwithnew);
+        X509_free(newwithold);
+        X509_free(oldwithnew);
+    end_upd:
+        X509_free(oldwithold);
+        return res;
     } else {
         OSSL_CMP_ITAV *req;
         STACK_OF(OSSL_CMP_ITAV) *itavs;
index 68a83568570d662ec83a30ff38dab73c6628990d..6308ab93dac31b47084cfdf213034c00f3ba4c80 100644 (file)
@@ -26,6 +26,9 @@ int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx,
                                     STACK_OF(X509) *chain);
 int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx,
                                      STACK_OF(X509) *caPubs);
+int ossl_cmp_mock_srv_set1_newWithNew(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert);
+int ossl_cmp_mock_srv_set1_newWithOld(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert);
+int ossl_cmp_mock_srv_set1_oldWithNew(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert);
 int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status,
                                      int fail_info, const char *text);
 int ossl_cmp_mock_srv_set_sendError(OSSL_CMP_SRV_CTX *srv_ctx, int bodytype);
index e4c30e4438be1af6947e6bac58ba1eb3370f8b1c..f0ef2317db8a4c5f001033f8355c20400877f156 100644 (file)
@@ -22,6 +22,9 @@ typedef struct
     X509 *certOut;             /* certificate to be returned in cp/ip/kup msg */
     STACK_OF(X509) *chainOut;  /* chain of certOut to add to extraCerts field */
     STACK_OF(X509) *caPubsOut; /* used in caPubs of ip and in caCerts of genp */
+    X509 *newWithNew;          /* to return in newWithNew of rootKeyUpdate */
+    X509 *newWithOld;          /* to return in newWithOld of rootKeyUpdate */
+    X509 *oldWithNew;          /* to return in oldWithNew of rootKeyUpdate */
     OSSL_CMP_PKISI *statusOut; /* status for ip/cp/kup/rp msg unless polling */
     int sendError;             /* send error response on given request type */
     OSSL_CMP_MSG *certReq;     /* ir/cr/p10cr/kur remembered while polling */
@@ -63,37 +66,26 @@ static mock_srv_ctx *mock_srv_ctx_new(void)
     return NULL;
 }
 
-int ossl_cmp_mock_srv_set1_refCert(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert)
-{
-    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
-
-    if (ctx == NULL) {
-        ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
-        return 0;
-    }
-    if (cert == NULL || X509_up_ref(cert)) {
-        X509_free(ctx->refCert);
-        ctx->refCert = cert;
-        return 1;
+#define DEFINE_OSSL_SET1_CERT(FIELD) \
+    int ossl_cmp_mock_srv_set1_##FIELD(OSSL_CMP_SRV_CTX *srv_ctx, \
+                                       X509 *cert) \
+    { \
+        mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); \
+ \
+        if (ctx == NULL) { \
+            ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); \
+            return 0; \
+        } \
+        if (cert == NULL || X509_up_ref(cert)) { \
+            X509_free(ctx->FIELD); \
+            ctx->FIELD = cert; \
+            return 1; \
+        } \
+        return 0; \
     }
-    return 0;
-}
 
-int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert)
-{
-    mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
-
-    if (ctx == NULL) {
-        ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
-        return 0;
-    }
-    if (cert == NULL || X509_up_ref(cert)) {
-        X509_free(ctx->certOut);
-        ctx->certOut = cert;
-        return 1;
-    }
-    return 0;
-}
+DEFINE_OSSL_SET1_CERT(refCert)
+DEFINE_OSSL_SET1_CERT(certOut)
 
 int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx,
                                     STACK_OF(X509) *chain)
@@ -129,6 +121,10 @@ int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx,
     return 1;
 }
 
+DEFINE_OSSL_SET1_CERT(newWithNew)
+DEFINE_OSSL_SET1_CERT(newWithOld)
+DEFINE_OSSL_SET1_CERT(oldWithNew)
+
 int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status,
                                      int fail_info, const char *text)
 {
@@ -212,6 +208,7 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
                                             STACK_OF(X509) **caPubs)
 {
     mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
+    int bodytype;
     OSSL_CMP_PKISI *si = NULL;
 
     if (ctx == NULL || cert_req == NULL
@@ -219,8 +216,8 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
         ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
         return NULL;
     }
-    if (ctx->sendError == 1
-            || ctx->sendError == OSSL_CMP_MSG_get_bodytype(cert_req)) {
+    bodytype = OSSL_CMP_MSG_get_bodytype(cert_req);
+    if (ctx->sendError == 1 || ctx->sendError == bodytype) {
         ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
         return NULL;
     }
@@ -245,7 +242,7 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
         ctx->curr_pollCount = 0;
 
     /* accept cert update request only for the reference cert, if given */
-    if (OSSL_CMP_MSG_get_bodytype(cert_req) == OSSL_CMP_KUR
+    if (bodytype == OSSL_CMP_KUR
             && crm != NULL /* thus not p10cr */ && ctx->refCert != NULL) {
         const OSSL_CRMF_CERTID *cid = OSSL_CRMF_MSG_get0_regCtrl_oldCertID(crm);
 
@@ -268,7 +265,7 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
     if (ctx->chainOut != NULL
             && (*chainOut = X509_chain_up_ref(ctx->chainOut)) == NULL)
         goto err;
-    if (ctx->caPubsOut != NULL
+    if (ctx->caPubsOut != NULL /* OSSL_CMP_PKIBODY_IP not visible here */
             && (*caPubs = X509_chain_up_ref(ctx->caPubsOut)) == NULL)
         goto err;
     if (ctx->statusOut != NULL
@@ -314,6 +311,26 @@ static OSSL_CMP_PKISI *process_rr(OSSL_CMP_SRV_CTX *srv_ctx,
     return OSSL_CMP_PKISI_dup(ctx->statusOut);
 }
 
+static OSSL_CMP_ITAV *process_genm_itav(mock_srv_ctx *ctx, int req_nid,
+                                        const OSSL_CMP_ITAV *req)
+{
+    OSSL_CMP_ITAV *rsp;
+
+    switch (req_nid) {
+    case NID_id_it_caCerts:
+        rsp = OSSL_CMP_ITAV_new_caCerts(ctx->caPubsOut);
+        break;
+    case NID_id_it_rootCaCert:
+        rsp = OSSL_CMP_ITAV_new_rootCaKeyUpdate(ctx->newWithNew,
+                                                ctx->newWithOld,
+                                                ctx->oldWithNew);
+        break;
+    default:
+        rsp = OSSL_CMP_ITAV_dup(req);
+    }
+    return rsp;
+}
+
 static int process_genm(OSSL_CMP_SRV_CTX *srv_ctx,
                         const OSSL_CMP_MSG *genm,
                         const STACK_OF(OSSL_CMP_ITAV) *in,
@@ -335,16 +352,13 @@ static int process_genm(OSSL_CMP_SRV_CTX *srv_ctx,
         OSSL_CMP_ITAV *req = sk_OSSL_CMP_ITAV_value(in, 0), *rsp;
         ASN1_OBJECT *obj = OSSL_CMP_ITAV_get0_type(req);
 
-        if (OBJ_obj2nid(obj) == NID_id_it_caCerts) {
-            if ((*out = sk_OSSL_CMP_ITAV_new_reserve(NULL, 1)) == NULL)
-                return 0;
-            if ((rsp = OSSL_CMP_ITAV_new_caCerts(ctx->caPubsOut)) == NULL) {
-                sk_OSSL_CMP_ITAV_free(*out);
-                return 0;
-            }
-            (void)sk_OSSL_CMP_ITAV_push(*out, rsp);
+        if ((*out = sk_OSSL_CMP_ITAV_new_reserve(NULL, 1)) == NULL)
+            return 0;
+        rsp = process_genm_itav(ctx, OBJ_obj2nid(obj), req);
+        if (rsp != NULL && sk_OSSL_CMP_ITAV_push(*out, rsp))
             return 1;
-        }
+        sk_OSSL_CMP_ITAV_free(*out);
+        return 0;
     }
 
     *out = sk_OSSL_CMP_ITAV_deep_copy(in, OSSL_CMP_ITAV_dup,
index b97c8323ff6f52ca58567edfa332e36e3bb0d7f0..73bc6363e0215bf8d0feade7f34a7a2f47dfc9c3 100644 (file)
@@ -116,6 +116,11 @@ ASN1_ADB(OSSL_CMP_ITAV) = {
                                    ASN1_UTF8STRING)),
     ADB_ENTRY(NID_id_it_caCerts,
               ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ITAV, infoValue.caCerts, X509)),
+    ADB_ENTRY(NID_id_it_rootCaCert,
+              ASN1_OPT(OSSL_CMP_ITAV, infoValue.rootCaCert, X509)),
+    ADB_ENTRY(NID_id_it_rootCaKeyUpdate,
+              ASN1_OPT(OSSL_CMP_ITAV, infoValue.rootCaKeyUpdate,
+                       OSSL_CMP_ROOTCAKEYUPDATE)),
 } ASN1_ADB_END(OSSL_CMP_ITAV, 0, infoType, 0,
                &infotypeandvalue_default_tt, NULL);
 
@@ -126,6 +131,14 @@ ASN1_SEQUENCE(OSSL_CMP_ITAV) = {
 IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_ITAV)
 IMPLEMENT_ASN1_DUP_FUNCTION(OSSL_CMP_ITAV)
 
+ASN1_SEQUENCE(OSSL_CMP_ROOTCAKEYUPDATE) = {
+    /* OSSL_CMP_CMPCERTIFICATE is effectively X509 so it is used directly */
+    ASN1_SIMPLE(OSSL_CMP_ROOTCAKEYUPDATE, newWithNew, X509),
+    ASN1_EXP_OPT(OSSL_CMP_ROOTCAKEYUPDATE, newWithOld, X509, 0),
+    ASN1_EXP_OPT(OSSL_CMP_ROOTCAKEYUPDATE, oldWithNew, X509, 1)
+} ASN1_SEQUENCE_END(OSSL_CMP_ROOTCAKEYUPDATE)
+IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_ROOTCAKEYUPDATE)
+
 OSSL_CMP_ITAV *OSSL_CMP_ITAV_create(ASN1_OBJECT *type, ASN1_TYPE *value)
 {
     OSSL_CMP_ITAV *itav;
@@ -215,6 +228,84 @@ int OSSL_CMP_ITAV_get0_caCerts(const OSSL_CMP_ITAV *itav, STACK_OF(X509) **out)
     return 1;
 }
 
+OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaCert(const X509 *rootCaCert)
+{
+    OSSL_CMP_ITAV *itav = OSSL_CMP_ITAV_new();
+
+    if (itav == NULL)
+        return NULL;
+    if (rootCaCert != NULL
+            && (itav->infoValue.rootCaCert = X509_dup(rootCaCert)) == NULL) {
+        OSSL_CMP_ITAV_free(itav);
+        return NULL;
+    }
+    itav->infoType = OBJ_nid2obj(NID_id_it_rootCaCert);
+    return itav;
+}
+
+int OSSL_CMP_ITAV_get0_rootCaCert(const OSSL_CMP_ITAV *itav, X509 **out)
+{
+    if (itav == NULL || out == NULL) {
+        ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    if (OBJ_obj2nid(itav->infoType) != NID_id_it_rootCaCert) {
+        ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT);
+        return 0;
+    }
+    *out = itav->infoValue.rootCaCert;
+    return 1;
+}
+OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaKeyUpdate(const X509 *newWithNew,
+                                                 const X509 *newWithOld,
+                                                 const X509 *oldWithNew)
+{
+    OSSL_CMP_ITAV *itav;
+    OSSL_CMP_ROOTCAKEYUPDATE *upd = OSSL_CMP_ROOTCAKEYUPDATE_new();
+
+    if (upd == NULL)
+        return NULL;
+    if (newWithNew != NULL && (upd->newWithNew = X509_dup(newWithNew)) == NULL)
+        goto err;
+    if (newWithOld != NULL && (upd->newWithOld = X509_dup(newWithOld)) == NULL)
+        goto err;
+    if (oldWithNew != NULL && (upd->oldWithNew = X509_dup(oldWithNew)) == NULL)
+        goto err;
+    if ((itav = OSSL_CMP_ITAV_new()) == NULL)
+        goto err;
+    itav->infoType = OBJ_nid2obj(NID_id_it_rootCaKeyUpdate);
+    itav->infoValue.rootCaKeyUpdate = upd;
+    return itav;
+
+    err:
+    OSSL_CMP_ROOTCAKEYUPDATE_free(upd);
+    return NULL;
+}
+
+int OSSL_CMP_ITAV_get0_rootCaKeyUpdate(const OSSL_CMP_ITAV *itav,
+                                       X509 **newWithNew,
+                                       X509 **newWithOld,
+                                       X509 **oldWithNew)
+{
+    OSSL_CMP_ROOTCAKEYUPDATE *upd;
+
+    if (itav == NULL || newWithNew == NULL) {
+        ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    if (OBJ_obj2nid(itav->infoType) != NID_id_it_rootCaKeyUpdate) {
+        ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT);
+        return 0;
+    }
+    upd = itav->infoValue.rootCaKeyUpdate;
+    *newWithNew = upd->newWithNew;
+    if (newWithOld != NULL)
+        *newWithOld = upd->newWithOld;
+    if (oldWithNew != NULL)
+        *oldWithNew = upd->oldWithNew;
+    return 1;
+}
+
 /* get ASN.1 encoded integer, return -1 on error */
 int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a)
 {
index 9d0e9680329f01e46c987007e94940a08f18756c..3853e52605969a23e4a64f87d422104a9f83cf84 100644 (file)
@@ -88,6 +88,8 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_ARGS), "invalid args"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_GENP), "invalid genp"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_OPTION), "invalid option"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_ROOTCAKEYUPDATE),
+     "invalid rootcakeyupdate"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_CERTID), "missing certid"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION),
     "missing key input for creating protection"},
index 2faeaf0d282a6b63842b96cf8455861106162075..74ac1d4b05198176fe4ab5aabac4a4239bf1e048 100644 (file)
@@ -177,3 +177,170 @@ int OSSL_CMP_get1_caCerts(OSSL_CMP_CTX *ctx, STACK_OF(X509) **out)
     OSSL_CMP_ITAV_free(itav);
     return ret;
 }
+
+static int selfsigned_verify_cb(int ok, X509_STORE_CTX *store_ctx)
+{
+    if (ok == 0 && store_ctx != NULL
+            && X509_STORE_CTX_get_error_depth(store_ctx) == 0
+            && X509_STORE_CTX_get_error(store_ctx)
+            == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT) {
+        /* in this case, custom chain building */
+        int i;
+        STACK_OF(X509) *trust;
+        STACK_OF(X509) *chain = X509_STORE_CTX_get0_chain(store_ctx);
+        STACK_OF(X509) *untrusted = X509_STORE_CTX_get0_untrusted(store_ctx);
+        X509_STORE_CTX_check_issued_fn check_issued =
+            X509_STORE_CTX_get_check_issued(store_ctx);
+        X509 *cert = sk_X509_value(chain, 0); /* target cert */
+        X509 *issuer;
+
+        for (i = 0; i < sk_X509_num(untrusted); i++) {
+            cert = sk_X509_value(untrusted, i);
+            if (!X509_add_cert(chain, cert, X509_ADD_FLAG_UP_REF))
+                return 0;
+        }
+
+        trust = X509_STORE_get1_all_certs(X509_STORE_CTX_get0_store(store_ctx));
+        for (i = 0; i < sk_X509_num(trust); i++) {
+            issuer = sk_X509_value(trust, i);
+            if ((*check_issued)(store_ctx, cert, issuer)) {
+                if (X509_add_cert(chain, cert, X509_ADD_FLAG_UP_REF))
+                    ok = 1;
+                break;
+            }
+        }
+        sk_X509_pop_free(trust, X509_free);
+        return ok;
+    } else {
+        X509_STORE *ts = X509_STORE_CTX_get0_store(store_ctx);
+        X509_STORE_CTX_verify_cb verify_cb;
+
+        if (ts == NULL || (verify_cb = X509_STORE_get_verify_cb(ts)) == NULL)
+            return ok;
+        return (*verify_cb)(ok, store_ctx);
+    }
+}
+
+/* vanilla X509_verify_cert() does not support self-signed certs as target */
+static int verify_ss_cert(OSSL_LIB_CTX *libctx, const char *propq,
+                          X509_STORE *ts, STACK_OF(X509) *untrusted,
+                          X509 *target)
+{
+    X509_STORE_CTX *csc = NULL;
+    int ok = 0;
+
+    if (ts == NULL || target == NULL) {
+        ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+
+    if ((csc = X509_STORE_CTX_new_ex(libctx, propq)) == NULL
+            || !X509_STORE_CTX_init(csc, ts, target, untrusted))
+        goto err;
+    X509_STORE_CTX_set_verify_cb(csc, selfsigned_verify_cb);
+    ok = X509_verify_cert(csc) > 0;
+
+ err:
+    X509_STORE_CTX_free(csc);
+    return ok;
+}
+
+static int
+verify_ss_cert_trans(OSSL_CMP_CTX *ctx, X509 *trusted /* may be NULL */,
+                     X509 *trans /* the only untrusted cert, may be NULL */,
+                     X509 *target, const char *desc)
+{
+    X509_STORE *ts = OSSL_CMP_CTX_get0_trusted(ctx);
+    STACK_OF(X509) *untrusted = NULL;
+    int res = 0;
+
+    if (trusted != NULL) {
+        X509_VERIFY_PARAM *vpm = X509_STORE_get0_param(ts);
+
+        if ((ts = X509_STORE_new()) == NULL)
+            return 0;
+        if (!X509_STORE_set1_param(ts, vpm)
+            || !X509_STORE_add_cert(ts, trusted))
+            goto err;
+    }
+
+    if (trans != NULL
+            && !ossl_x509_add_cert_new(&untrusted, trans, X509_ADD_FLAG_UP_REF))
+        goto err;
+
+    res = verify_ss_cert(OSSL_CMP_CTX_get0_libctx(ctx),
+                         OSSL_CMP_CTX_get0_propq(ctx),
+                         ts, untrusted, target);
+    if (!res)
+        ERR_raise_data(ERR_LIB_CMP, CMP_R_INVALID_ROOTCAKEYUPDATE,
+                       "failed to validate %s certificate received in genp %s",
+                       desc, trusted == NULL ? "using trust store"
+                       : "with given certificate as trust anchor");
+
+ err:
+    sk_X509_pop_free(untrusted, X509_free);
+    if (trusted != NULL)
+        X509_STORE_free(ts);
+    return res;
+}
+
+int OSSL_CMP_get1_rootCaKeyUpdate(OSSL_CMP_CTX *ctx,
+                                  const X509 *oldWithOld, X509 **newWithNew,
+                                  X509 **newWithOld, X509 **oldWithNew)
+{
+    X509 *oldWithOld_copy = NULL, *my_newWithOld, *my_oldWithNew;
+    OSSL_CMP_ITAV *req, *itav;
+    int res = 0;
+
+    if (newWithNew == NULL) {
+        ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_NULL_PARAMETER);
+        return 0;
+    }
+    *newWithNew = NULL;
+
+    if ((req = OSSL_CMP_ITAV_new_rootCaCert(oldWithOld)) == NULL)
+        return 0;
+    itav = get_genm_itav(ctx, req, NID_id_it_rootCaKeyUpdate, "rootCaKeyUpdate");
+    if (itav == NULL)
+        return 0;
+
+    if (!OSSL_CMP_ITAV_get0_rootCaKeyUpdate(itav, newWithNew,
+                                            &my_newWithOld, &my_oldWithNew))
+        goto end;
+
+    if (*newWithNew == NULL) /* no root CA cert update available */
+        goto end;
+    if ((oldWithOld_copy = X509_dup(oldWithOld)) == NULL && oldWithOld != NULL)
+        goto end;
+    if (!verify_ss_cert_trans(ctx, oldWithOld_copy, my_newWithOld,
+                              *newWithNew, "newWithNew")) {
+        ERR_raise(ERR_LIB_CMP, CMP_R_INVALID_ROOTCAKEYUPDATE);
+        goto end;
+    }
+    if (oldWithOld != NULL && my_oldWithNew != NULL
+        && !verify_ss_cert_trans(ctx, *newWithNew, my_oldWithNew,
+                                 oldWithOld_copy, "oldWithOld")) {
+        ERR_raise(ERR_LIB_CMP, CMP_R_INVALID_ROOTCAKEYUPDATE);
+        goto end;
+    }
+
+    if (!X509_up_ref(*newWithNew))
+        goto end;
+    if (newWithOld != NULL &&
+        (*newWithOld = my_newWithOld) != NULL && !X509_up_ref(*newWithOld))
+        goto free;
+    if (oldWithNew == NULL ||
+        (*oldWithNew = my_oldWithNew) == NULL || X509_up_ref(*oldWithNew)) {
+        res = 1;
+        goto end;
+    }
+    if (newWithOld != NULL)
+        X509_free(*newWithOld);
+ free:
+    X509_free(*newWithNew);
+
+ end:
+    OSSL_CMP_ITAV_free(itav);
+    X509_free(oldWithOld_copy);
+    return res;
+}
index 18401ddb6070761180f10c5b728fdbde5871d68b..d1035c2da965a5180c80e90a5c3e2ec00da5ccde 100644 (file)
@@ -205,6 +205,9 @@ typedef struct ossl_cmp_cakeyupdanncontent_st {
 } OSSL_CMP_CAKEYUPDANNCONTENT;
 DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CAKEYUPDANNCONTENT)
 
+typedef struct ossl_cmp_rootcakeyupdate_st OSSL_CMP_ROOTCAKEYUPDATE;
+DECLARE_ASN1_FUNCTIONS(OSSL_CMP_ROOTCAKEYUPDATE)
+
 /*-
  * declared already here as it will be used in OSSL_CMP_MSG (nested) and
  * infoType and infoValue
@@ -252,6 +255,10 @@ struct ossl_cmp_itav_st {
         STACK_OF(ASN1_UTF8STRING) *suppLangTagsValue;
         /* NID_id_it_caCerts - CA Certificates */
         STACK_OF(X509) *caCerts;
+        /* NID_id_it_rootCaCert - Root CA Certificate */
+        X509 *rootCaCert;
+        /* NID_id_it_rootCaKeyUpdate - Root CA Certificate Update */
+        OSSL_CMP_ROOTCAKEYUPDATE *rootCaKeyUpdate;
         /* this is to be used for so far undeclared objects */
         ASN1_TYPE *other;
     } infoValue;
@@ -738,6 +745,21 @@ DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PROTECTEDPART)
  *   }
  */
 
+/*
+ * RootCaKeyUpdateContent ::= SEQUENCE {
+ *      newWithNew       CMPCertificate,
+ *      newWithOld   [0] CMPCertificate OPTIONAL,
+ *      oldWithNew   [1] CMPCertificate OPTIONAL
+ * }
+ */
+
+struct ossl_cmp_rootcakeyupdate_st {
+    X509 *newWithNew;
+    X509 *newWithOld;
+    X509 *oldWithNew;
+} /* OSSL_CMP_ROOTCAKEYUPDATE */;
+DECLARE_ASN1_FUNCTIONS(OSSL_CMP_ROOTCAKEYUPDATE)
+
 /* from cmp_asn.c */
 int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a);
 
index cbb32969428352504bef059c894918d8dca4a8a5..4b86dac55725bf4ba61207e5b9475b093606ad82 100644 (file)
@@ -235,6 +235,7 @@ CMP_R_GETTING_GENP:192:getting genp
 CMP_R_INVALID_ARGS:100:invalid args
 CMP_R_INVALID_GENP:193:invalid genp
 CMP_R_INVALID_OPTION:174:invalid option
+CMP_R_INVALID_ROOTCAKEYUPDATE:195:invalid rootcakeyupdate
 CMP_R_MISSING_CERTID:165:missing certid
 CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION:130:\
        missing key input for creating protection
index 59568c65fcf9f823275641dd2cc51c881514932f..1789fad2754c82e40c5c808eaff98caacb7d5074 100644 (file)
@@ -8,6 +8,9 @@ ossl_cmp_mock_srv_set1_refCert,
 ossl_cmp_mock_srv_set1_certOut,
 ossl_cmp_mock_srv_set1_chainOut,
 ossl_cmp_mock_srv_set1_caPubsOut,
+ossl_cmp_mock_srv_set1_newWithNew,
+ossl_cmp_mock_srv_set1_newWithOld,
+ossl_cmp_mock_srv_set1_oldWithNew,
 ossl_cmp_mock_srv_set_statusInfo,
 ossl_cmp_mock_srv_set_sendError,
 ossl_cmp_mock_srv_set_pollCount,
@@ -21,12 +24,15 @@ ossl_cmp_mock_srv_set_checkAfterTime
  OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(OSSL_LIB_CTX *libctx, const char *propq);
  void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx);
 
- int ossl_cmp_mock_srv_set1_refCert(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert);
- int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert);
+ int ossl_cmp_mock_srv_set1_refCert(OSSL_CMP_SRV_CTX *ctx, const X509 *cert);
+ int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *ctx, const X509 *cert);
  int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx,
-                                     STACK_OF(X509) *chain);
+                                     const STACK_OF(X509) *chain);
  int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx,
-                                      STACK_OF(X509) *caPubs);
+                                      const STACK_OF(X509) *caPubs);
+ int ossl_cmp_mock_srv_set1_newWithNew(OSSL_CMP_SRV_CTX *ctx, const X509 *cert);
+ int ossl_cmp_mock_srv_set1_newWithOld(OSSL_CMP_SRV_CTX *ctx, const X509 *cert);
+ int ossl_cmp_mock_srv_set1_oldWithNew(OSSL_CMP_SRV_CTX *ctx, const X509 *cert);
  int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status,
                                       int fail_info, const char *text);
  int ossl_cmp_mock_srv_set_sendError(OSSL_CMP_SRV_CTX *srv_ctx, int bodytype);
@@ -41,21 +47,30 @@ I<propq>, both of which may be NULL to select the defaults.
 
 ossl_cmp_mock_srv_free() deallocates the contexts for the CMP mock server.
 
-ossl_cmp_mock_srv_set1_refCert() sets the reference certificate to be expected
-for rr messages and for any oldCertID included in kur messages.
+ossl_cmp_mock_srv_set1_refCert() sets the reference certificate (or NULL)
+to be expected for rr messages and for any oldCertID included in kur messages.
 
-ossl_cmp_mock_srv_set1_certOut() sets the certificate to be returned in
-cp/ip/kup messages.
+ossl_cmp_mock_srv_set1_certOut() sets the certificate (or NULL)
+to be returned in cp/ip/kup messages.
 Note that on each certificate request the mock server does not produce
 a fresh certificate but just returns the same pre-existing certificate.
 
-ossl_cmp_mock_srv_set1_chainOut() sets the certificate chain to be added to
-the extraCerts in a cp/ip/kup message.
+ossl_cmp_mock_srv_set1_chainOut() sets the certificate chain (or NULL)
+to be added to the extraCerts in a cp/ip/kup message.
 It should be useful for the validation of the certificate given via
 ossl_cmp_mock_srv_set1_certOut().
 
-ossl_cmp_mock_srv_set1_caPubsOut() sets the caPubs to be returned in an ip msg
-and the list of certificates to be returned in a genp of infoType caCerts.
+ossl_cmp_mock_srv_set1_caPubsOut() sets list of certificates (or NULL) to be
+returned in the caPubs field an ip message and in a genp of infoType caCerts.
+
+ossl_cmp_mock_srv_set1_newWithNew() sets the value (which may be NULL)
+of the newWithNew field to be returned in a genp of infoType rootCaKeyUpdate.
+
+ossl_cmp_mock_srv_set1_newWithOld() sets the value (which may be NULL)
+of the newWithOld field to be returned in a genp of infoType rootCaKeyUpdate.
+
+ossl_cmp_mock_srv_set1_oldWithNew() sets the value (which may be NULL)
+of the oldWithNew field to be returned in a genp of infoType rootCaKeyUpdate.
 
 ossl_cmp_mock_srv_set_statusInfo() sets the status info to be returned.
 
index 4d077175537cf6fa096f75ba71418525fd000a35..7c68385f4b768929a18a1bb7257ec65c49b91afb 100644 (file)
@@ -68,6 +68,10 @@ Server authentication options:
 [B<-srvcertout> I<filename>]
 [B<-extracertsout> I<filename>]
 [B<-cacertsout> I<filename>]
+[B<-oldwithold> I<filename>]
+[B<-newwithnew> I<filename>]
+[B<-newwithold> I<filename>]
+[B<-oldwithnew> I<filename>]
 
 Client authentication and protection options:
 
@@ -129,6 +133,9 @@ Mock server options:
 [B<-rsp_cert> I<filename>|I<uri>]
 [B<-rsp_extracerts> I<filenames>|I<uris>]
 [B<-rsp_capubs> I<filenames>|I<uris>]
+[B<-rsp_newwithnew> I<filename>|I<uri>]
+[B<-rsp_newwithold> I<filename>|I<uri>]
+[B<-rsp_oldwithnew> I<filename>|I<uri>]
 [B<-poll_count> I<number>]
 [B<-check_after> I<number>]
 [B<-grant_implicitconf>]
@@ -237,7 +244,7 @@ ITAV B<infoType>s is printed to stdout.
 
 Set InfoType name to use for requesting specific info in B<genm>,
 e.g., C<signKeyPairTypes>.
-So far, there is specific support for C<caCerts>.
+So far, there is specific support for C<caCerts> and C<rootCaCert>.
 
 =item B<-geninfo> I<OID:int:N>
 
@@ -669,6 +676,43 @@ The file where to save the list of CA certificates contained in the caPubs field
 if a positive certificate response (i.e., IP, CP, or KUP) message was received
 or contained in a general response (genp) message with infoType C<caCerts>.
 
+=item B<-oldwithold> I<filename>
+
+The root CA certificate to include in a genm request of infoType C<rootCaCert>.
+If present and the optional oldWithNew certificate is received,
+it is verified using the newWithNew certificate as the (only) trust anchor.
+
+=item B<-newwithnew> I<filename>
+
+This option must be provided when B<-infotype> I<rootCaCert> is given.
+It specifies the file to save the newWithNew certificate
+received in a genp message of type C<rootCaKeyUpdate>.
+If on success no such cert was received, this file (if present) is deleted
+to indicate that the requested root CA certificate update is not available.
+
+Any received newWithNew certificate is verified
+using any received newWithOld certificate as untrusted intermediate certificate
+and the certificate provided with B<-oldwithold> as the (only) trust anchor,
+or if not provided, using the certificates given with the B<-trusted> option.
+
+B<WARNING:>
+The newWithNew certificate is meant to be a certificate that will be trusted.
+The trust placed in it cannot be stronger than the trust placed in
+the B<-oldwithold> certificate if present, otherwise it cannot be stronger than
+the weakest trust placed in any of the B<-trusted> certificates.
+
+=item B<-newwithold> I<filename>
+
+The file to save any newWithOld certificate
+received in a genp message of infoType C<rootCaKeyUpdate>.
+If on success no such cert was received, this is indicated by deleting the file.
+
+=item B<-oldwithnew> I<filename>
+
+The file to save any oldWithNew certificate
+received in a genp message of infoType C<rootCaKeyUpdate>.
+If on success no such cert was received, this is indicated by deleting the file.
+
 =back
 
 =head2 Client authentication options
@@ -803,7 +847,9 @@ See L<openssl(1)/Format Options> for details.
 
 Pass phrase source for certificate given with the B<-trusted>, B<-untrusted>,
 B<-own_trusted>, B<-srvcert>, B<-out_trusted>, B<-extracerts>,
-B<-srv_trusted>, B<-srv_untrusted>, B<-rsp_extracerts>, B<-rsp_capubs>,
+B<-srv_trusted>, B<-srv_untrusted>, B<-ref_cert>, B<-rsp_cert>,
+B<-rsp_extracerts>, B<-rsp_capubs>,
+B<-rsp_newwithnew>, B<-rsp_newwithold>, B<-rsp_oldwithnew>,
 B<-tls_extra>, and B<-tls_trusted> options.
 If not given here, the password will be prompted for if needed.
 
@@ -1054,6 +1100,18 @@ Extra certificates to be included in mock certification responses.
 
 CA certificates to be included in mock Initialization Response (IP) message.
 
+=item B<-rsp_newwithnew> I<filename>|I<uri>
+
+Certificate to be returned in newWithNew field of genp of type rootCaKeyUpdate.
+
+=item B<-rsp_newwithold> I<filename>|I<uri>
+
+Certificate to be returned in newWithOld field of genp of type rootCaKeyUpdate.
+
+=item B<-rsp_oldwithnew> I<filename>|I<uri>
+
+Certificate to be returned in oldWithNew field of genp of type rootCaKeyUpdate.
+
 =item B<-poll_count> I<number>
 
 Number of times the client must poll before receiving a certificate.
@@ -1127,9 +1185,9 @@ only affect the certificate verification enabled via the B<-out_trusted> option.
 
 =head1 NOTES
 
-When a client obtains from a CMP server CA certificates that it is going to
+When a client obtains, from a CMP server, CA certificates that it is going to
 trust, for instance via the C<caPubs> field of a certificate response
-or using general messages with infoType C<caCerts>,
+or using general messages with infoType C<caCerts> or C<rootCaCert>,
 authentication of the CMP server is particularly critical.
 So special care must be taken setting up server authentication
 using B<-trusted> and related options for certificate-based authentication
index eb397388aa64d38f756bedf9e4a512db716650ea..882103f4c3b54adda5a2a0d81877753b50aa9056 100644 (file)
@@ -3,7 +3,11 @@
 =head1 NAME
 
 OSSL_CMP_ITAV_new_caCerts,
-OSSL_CMP_ITAV_get0_caCerts
+OSSL_CMP_ITAV_get0_caCerts,
+OSSL_CMP_ITAV_new_rootCaCert,
+OSSL_CMP_ITAV_get0_rootCaCert,
+OSSL_CMP_ITAV_new_rootCaKeyUpdate,
+OSSL_CMP_ITAV_get0_rootCaKeyUpdate
 - CMP utility functions for handling specific genm and genp messages
 
 =head1 SYNOPSIS
@@ -13,6 +17,16 @@ OSSL_CMP_ITAV_get0_caCerts
  OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_caCerts(const STACK_OF(X509) *caCerts);
  int OSSL_CMP_ITAV_get0_caCerts(const OSSL_CMP_ITAV *itav, STACK_OF(X509) **out);
 
+ OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaCert(const X509 *rootCaCert);
+ int OSSL_CMP_ITAV_get0_rootCaCert(const OSSL_CMP_ITAV *itav, X509 **out);
+ OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaKeyUpdate(const X509 *newWithNew,
+                                                  const X509 *newWithOld,
+                                                  const X509 *oldWithNew);
+ int OSSL_CMP_ITAV_get0_rootCaKeyUpdate(const OSSL_CMP_ITAV *itav,
+                                        X509 **newWithNew,
+                                        X509 **newWithOld,
+                                        X509 **oldWithNew);
+
 =head1 DESCRIPTION
 
 ITAV is short for InfoTypeAndValue.
@@ -25,17 +39,41 @@ OSSL_CMP_ITAV_get0_caCerts() requires that I<itav> has type B<caCerts>.
 It assigns NULL to I<*out> if there are no CA certificates in I<itav>, otherwise
 the internal pointer of type B<STACK_OF(X509)> with the certificates present.
 
+OSSL_CMP_ITAV_new_rootCaCert() creates a new B<OSSL_CMP_ITAV> structure
+of type B<rootCaCert> that includes the optionally given certificate.
+
+OSSL_CMP_ITAV_get0_rootCaCert() requires that I<itav> has type B<rootCaCert>.
+It assigns NULL to I<*out> if no certificate is included in I<itav>, otherwise
+the internal pointer to the certificate contained in the infoValue field.
+
+OSSL_CMP_ITAV_new_rootCaKeyUpdate() creates a new B<OSSL_CMP_ITAV> structure
+of type B<rootCaKeyUpdate> that includes an RootCaKeyUpdateContent structure
+with the optional I<newWithNew>, I<newWithOld>, and I<oldWithNew> certificates.
+
+OSSL_CMP_ITAV_get0_rootCaKeyUpdate() requires that I<itav> has infoType
+B<rootCaKeyUpdate>.
+If an update of a root CA certificate is included,
+it assigns to I<*newWithNew> the internal pointer
+to the certificate contained in the newWithNew infoValue sub-field of I<itav>.
+If I<newWithOld> is not NULL, it assigns to I<*newWithOld> the internal pointer
+to the certificate contained in the newWithOld infoValue sub-field of I<itav>.
+If I<oldWithNew> is not NULL, it assigns to I<*oldWithNew> the internal pointer
+to the certificate contained in the oldWithNew infoValue sub-field of I<itav>.
+Each of these pointers will be NULL if the respective sub-field is not set.
+
 =head1 NOTES
 
 CMP is defined in RFC 4210.
 
 =head1 RETURN VALUES
 
-OSSL_CMP_ITAV_new_caCerts()
-returns a pointer to the new ITAV structure on success, or NULL on error.
+OSSL_CMP_ITAV_new_caCerts(),
+OSSL_CMP_ITAV_new_rootCaCert(), and OSSL_CMP_ITAV_new_rootCaKeyUpdate()
+return a pointer to the new ITAV structure on success, or NULL on error.
 
-OSSL_CMP_ITAV_get0_caCerts()
-returns 1 on success, 0 on error.
+OSSL_CMP_ITAV_get0_caCerts(),
+OSSL_CMP_ITAV_get0_rootCaCert(), and OSSL_CMP_ITAV_get0_rootCaKeyUpdate()
+return 1 on success, 0 on error.
 
 =head1 SEE ALSO
 
@@ -43,8 +81,9 @@ L<OSSL_CMP_ITAV_create(3)> and L<OSSL_CMP_ITAV_get0_type(3)>
 
 =head1 HISTORY
 
-OSSL_CMP_ITAV_new_caCerts() and
-OSSL_CMP_ITAV_get0_rootCaCert()
+OSSL_CMP_ITAV_new_caCerts(), OSSL_CMP_ITAV_get0_caCerts(),
+OSSL_CMP_ITAV_new_rootCaCert(), OSSL_CMP_ITAV_get0_rootCaCert(),
+OSSL_CMP_ITAV_new_rootCaKeyUpdate(), and OSSL_CMP_ITAV_get0_rootCaKeyUpdate()
 were added in OpenSSL 3.2.
 
 =head1 COPYRIGHT
index fbf118c2b16ceab5af17034aacb61f66ff013750..e752b8e270697853944649c014efa09f551986d5 100644 (file)
@@ -14,7 +14,8 @@ OSSL_CMP_KUR,
 OSSL_CMP_try_certreq,
 OSSL_CMP_exec_RR_ses,
 OSSL_CMP_exec_GENM_ses,
-OSSL_CMP_get1_caCerts
+OSSL_CMP_get1_caCerts,
+OSSL_CMP_get1_rootCaKeyUpdate
 - functions implementing CMP client transactions
 
 =head1 SYNOPSIS
@@ -37,6 +38,9 @@ OSSL_CMP_get1_caCerts
 
  STACK_OF(OSSL_CMP_ITAV) *OSSL_CMP_exec_GENM_ses(OSSL_CMP_CTX *ctx);
  int OSSL_CMP_get1_caCerts(OSSL_CMP_CTX *ctx, STACK_OF(X509) **out);
+ int OSSL_CMP_get1_rootCaKeyUpdate(OSSL_CMP_CTX *ctx,
+                                   const X509 *oldWithOld, X509 **newWithNew,
+                                   X509 **newWithOld, X509 **oldWithNew);
 
 =head1 DESCRIPTION
 
@@ -132,6 +136,23 @@ On success it assigns to I<*out> the list of certificates received,
 which must be freed by the caller.
 NULL output means that no CA certificates were provided by the server.
 
+OSSL_CMP_get1_rootCaKeyUpdate() uses a genm request message
+with infoType rootCaCert to obtain from the CMP server referenced by I<ctx>
+in a genp response message with infoType rootCaKeyUpdate any update of the
+given root CA certificate I<oldWithOld> and verifies it as far as possible.
+See RFC 4210 section 4.4 for details.
+On success it assigns to I<*newWithNew> the root certificate received.
+When the I<newWithOld> and I<oldWithNew> output parameters are not NULL,
+it assigns to them the corresponding transition certificates.
+NULL means that the respective certificate was not provided by the server.
+All certificates obtained this way must be freed by the caller.
+
+B<WARNING:>
+The I<newWithNew> certificate is meant to be a certificate that will be trusted.
+The trust placed in it cannot be stronger than the trust placed in
+the I<oldwithold> certificate if present, otherwise it cannot be stronger than
+the weakest trust in any of the certificates in the trust store of I<ctx>.
+
 =head1 NOTES
 
 CMP is defined in RFC 4210 (and CRMF in RFC 4211).
@@ -140,8 +161,8 @@ The CMP client implementation is limited to one request per CMP message
 (and consequently to at most one response component per CMP message).
 
 When a client obtains from a CMP server CA certificates that it is going to
-trust, for instance via the caPubs field of a certificate response
-or using functions like OSSL_CMP_get1_caCerts(),
+trust, for instance via the caPubs field of a certificate response or using
+functions like OSSL_CMP_get1_caCerts() and OSSL_CMP_get1_rootCaKeyUpdate(),
 authentication of the CMP server is particularly critical.
 So special care must be taken setting up server authentication in I<ctx>
 using functions such as
@@ -167,7 +188,8 @@ In the latter case L<OSSL_CMP_CTX_get0_newCert(3)> yields NULL
 and the output parameter I<checkAfter> has been used to
 assign the received value unless I<checkAfter> is NULL.
 
-OSSL_CMP_exec_RR_ses() and OSSL_CMP_get1_caCerts()
+OSSL_CMP_exec_RR_ses(), OSSL_CMP_get1_caCerts(),
+and OSSL_CMP_get1_rootCaKeyUpdate()
 return 1 on success, 0 on error.
 
 OSSL_CMP_exec_GENM_ses() returns NULL on error,
@@ -191,7 +213,8 @@ L<OSSL_CMP_MSG_http_perform(3)>
 
 The OpenSSL CMP support was added in OpenSSL 3.0.
 
-OSSL_CMP_get1_caCerts() was added in OpenSSL 3.2.
+OSSL_CMP_get1_caCerts() and OSSL_CMP_get1_rootCaKeyUpdate()
+were added in OpenSSL 3.2.
 
 =head1 COPYRIGHT
 
index 0e49ee9d519ed2c6b8fd868a1afc6122bb1c7d64..d7f2354b3a9740d1235b512c5c9bebbf5c8c96fb 100644 (file)
@@ -264,6 +264,16 @@ void OSSL_CMP_ITAV_free(OSSL_CMP_ITAV *itav);
 OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_caCerts(const STACK_OF(X509) *caCerts);
 int OSSL_CMP_ITAV_get0_caCerts(const OSSL_CMP_ITAV *itav, STACK_OF(X509) **out);
 
+OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaCert(const X509 *rootCaCert);
+int OSSL_CMP_ITAV_get0_rootCaCert(const OSSL_CMP_ITAV *itav, X509 **out);
+OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaKeyUpdate(const X509 *newWithNew,
+                                                 const X509 *newWithOld,
+                                                 const X509 *oldWithNew);
+int OSSL_CMP_ITAV_get0_rootCaKeyUpdate(const OSSL_CMP_ITAV *itav,
+                                       X509 **newWithNew,
+                                       X509 **newWithOld,
+                                       X509 **oldWithNew);
+
 void OSSL_CMP_MSG_free(OSSL_CMP_MSG *msg);
 
 /* from cmp_ctx.c */
@@ -488,6 +498,9 @@ STACK_OF(OSSL_CMP_ITAV) *OSSL_CMP_exec_GENM_ses(OSSL_CMP_CTX *ctx);
 
 /* from cmp_genm.c */
 int OSSL_CMP_get1_caCerts(OSSL_CMP_CTX *ctx, STACK_OF(X509) **out);
+int OSSL_CMP_get1_rootCaKeyUpdate(OSSL_CMP_CTX *ctx,
+                                  const X509 *oldWithOld, X509 **newWithNew,
+                                  X509 **newWithOld, X509 **oldWithNew);
 
 #  ifdef  __cplusplus
 }
index f4435d825d08b41f9c229b247e1c19542f09f9bf..57a6effbe3fc2db148abe0c9bec7ddeb79e27dc3 100644 (file)
@@ -63,6 +63,7 @@
 #  define CMP_R_INVALID_ARGS                               100
 #  define CMP_R_INVALID_GENP                               193
 #  define CMP_R_INVALID_OPTION                             174
+#  define CMP_R_INVALID_ROOTCAKEYUPDATE                    195
 #  define CMP_R_MISSING_CERTID                             165
 #  define CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION  130
 #  define CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE         142
index 4fd03e8b2d9e5b07b21b610cb0ea7e714a921775..2695c0f28f35b5900cab2a837b7965efec7882f7 100644 (file)
@@ -26,8 +26,8 @@ plan skip_all => "These tests are not supported in a fuzz build"
 
 plan skip_all => "These tests are not supported in a no-cmp build"
     if disabled("cmp");
-plan skip_all => "These tests are not supported in a no-ec build"
-    if disabled("ec");
+plan skip_all => "These tests are not supported in a no-ecx build"
+    if disabled("ecx"); # EC and EDDSA test certs, e.g., in Mock/newWithNew.pem
 plan skip_all => "These tests are not supported in a no-sock build"
     if disabled("sock");
 plan skip_all => "These tests are not supported in a no-http build"
diff --git a/test/recipes/80-test_cmp_http_data/Mock/newWithNew.pem b/test/recipes/80-test_cmp_http_data/Mock/newWithNew.pem
new file mode 100644 (file)
index 0000000..1a02d19
--- /dev/null
@@ -0,0 +1,11 @@
+-----BEGIN PRIVATE KEY-----
+MC4CAQAwBQYDK2VwBCIEINTuctv5E1hK1bbY8fdp+K06/nwoy/HU++CXqI9EdVhC
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIBAzCBtqADAgECAgH+MAUGAytlcDASMRAwDgYDVQQDDAdSb290IENBMCAXDTIz
+MDYwNTIwMjMwMFoYDzIxMjMwNjA1MjAyMzAwWjASMRAwDgYDVQQDDAdSb290IENB
+MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuGjLzAt
+MAwGA1UdEwQFMAMBAf8wHQYDVR0OBBYEFKKMwfhuWWDT4DrnXJYsl6jUSCk8MAUG
+AytlcANBAEG62N+3Go9h1ekWyQMf1hYFQMPQF/XVP2EH1euP7mVxJt0mquGpVsm+
+qLt/W4xBKiu08Jfcv4Gxi6CjgOekGww=
+-----END CERTIFICATE-----
diff --git a/test/recipes/80-test_cmp_http_data/Mock/newWithOld.pem b/test/recipes/80-test_cmp_http_data/Mock/newWithOld.pem
new file mode 100644 (file)
index 0000000..988496c
--- /dev/null
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIICCTCB8qADAgECAhR+y2i70DQe9ryvJ8uPJO8qOMfX+zANBgkqhkiG9w0BAQsF
+ADASMRAwDgYDVQQDDAdSb290IENBMCAXDTIzMDYwNTIwMjg1N1oYDzIxMjMwNjA1
+MjAyODU3WjASMRAwDgYDVQQDDAdSb290IENBMCowBQYDK2VwAyEAGb9ECWmEzf6F
+QbrBZ9w7lshQhqowtrbLDFw4rXAxZuGjUDBOMAwGA1UdEwQFMAMBAf8wHQYDVR0O
+BBYEFKKMwfhuWWDT4DrnXJYsl6jUSCk8MB8GA1UdIwQYMBaAFHB/Lq6DaFmYBCMq
+zes+F80k3QFJMA0GCSqGSIb3DQEBCwUAA4IBAQB6Eg6lRxiUUXMGO8l7XYJ3d49x
+YDqwt+fvaQcnwVN3kJ1GAb/0lcB6k4mt8jHizT2HKw1ZMHK7CGbHYAMKvtxML3px
+GXqeEQO2IlWU23kEyPhX/yoOG0cp9QWm4tdTvr3xCr4E4rNZJUNbSqyOCdcAs39H
+4dDBHBQrL530/XquKdXmq4fAwyKIGxNW1WTohKq9Yzd3NK+0Ku11Ny86FIzB3iks
+a8NdsE88xfBQcQMo9omZZbPQBg7YMId4zRyDFplrLWZjhoNmStmTHTX/nOYUMGm3
+75iikSsNRJl4A/ZvnZrDA2am3ihvMghVIN4IVfXrk5tHiZ/XHZuu3vetK2jp
+-----END CERTIFICATE-----
diff --git a/test/recipes/80-test_cmp_http_data/Mock/oldWithNew.pem b/test/recipes/80-test_cmp_http_data/Mock/oldWithNew.pem
new file mode 100644 (file)
index 0000000..8fa15f8
--- /dev/null
@@ -0,0 +1,14 @@
+-----BEGIN CERTIFICATE-----
+MIICMjCCAeSgAwIBAgIUcaAacl/D9rcbM5ytumMvdL3J+HIwBQYDK2VwMBIxEDAO
+BgNVBAMMB1Jvb3QgQ0EwIBcNMjMwNjA1MjAyOTI0WhgPMjEyMzA2MDUyMDI5MjRa
+MBIxEDAOBgNVBAMMB1Jvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQC/mhXWzc26ztIg2Duia7kDG54SAr3uaHk9TeGBmmWJIVoRKYvaosZ4/rT2
+hez/rxcNdVbi61QsI6MuHSen7lfLeLcZENeAFnvZAN7bdaqpCqpoGVBVWbVbEb5q
+ZG1kkRZ1IiyIUG2T7x0ESUeHZZAOEM5aocYdBqtCAk/EYH3sxGExKVtPArVPkoBY
+6WqLmYlbkvq82tDtOtr9hx4fvR9TR8lg5eEHEz3Y3APVttV30Y9gVKqt2tWPX1u+
+jrdezFl257HlAetGRapPnDmaAAdoSAKpatL/rir1NH1QTCsHySJlmDeT3+Kb7MHA
+RQtNm7SvygwSSmNtOVcua3wQwGrHAgMBAAGjUDBOMAwGA1UdEwQFMAMBAf8wHQYD
+VR0OBBYEFHB/Lq6DaFmYBCMqzes+F80k3QFJMB8GA1UdIwQYMBaAFKKMwfhuWWDT
+4DrnXJYsl6jUSCk8MAUGAytlcANBAHFKIp57/EisMF84ZvOFzxnS2o8/qKsRrrh5
+w1nBOmOvavZxbtFyO9batLEWikNV0LDFIHw9g3uYmgB1VUzhcw4=
+-----END CERTIFICATE-----
diff --git a/test/recipes/80-test_cmp_http_data/Mock/oldWithOld.pem b/test/recipes/80-test_cmp_http_data/Mock/oldWithOld.pem
new file mode 100644 (file)
index 0000000..7c6db11
--- /dev/null
@@ -0,0 +1,46 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQC/mhXWzc26ztIg
+2Duia7kDG54SAr3uaHk9TeGBmmWJIVoRKYvaosZ4/rT2hez/rxcNdVbi61QsI6Mu
+HSen7lfLeLcZENeAFnvZAN7bdaqpCqpoGVBVWbVbEb5qZG1kkRZ1IiyIUG2T7x0E
+SUeHZZAOEM5aocYdBqtCAk/EYH3sxGExKVtPArVPkoBY6WqLmYlbkvq82tDtOtr9
+hx4fvR9TR8lg5eEHEz3Y3APVttV30Y9gVKqt2tWPX1u+jrdezFl257HlAetGRapP
+nDmaAAdoSAKpatL/rir1NH1QTCsHySJlmDeT3+Kb7MHARQtNm7SvygwSSmNtOVcu
+a3wQwGrHAgMBAAECggEBAL4rWle8JuCuHGNbGz1nO9d41tg7fnYdnZAaN6OiMfr8
+bl+wY84aV3GKJOS2InfYOcIy340UU5QHvxOq/kwwRVV/uAOZ8rqAFmZY9djOnhdv
+rZjq3xAHnPgJ0XvZt7XkR2z1AUw+v7Pf1WYGsYcSZ/t99MKB5Je0odA/aRqZRwLy
+YflbsnAJtxdJ6fsiVCSJcU76V8sxfiCimw6ppLMEp3zCjveQ5Lv0eVoL2zNYeh+l
+GiSwqTqaR+WJekkDiXRd9KYI19drf7OkTII1DtOd6bgvKX3zv2lNiere4J4k7cAP
+rW6fBFgtSq2oklTpWUlXRH7XQAgDtDvldXdlKaj96dkCgYEA8KPSu5ywg8pjCofE
+nLtJTfVyD2g9tgNLj9dI3kuSniZU51kOtk5rZZwL0S8piGczL908aV9DIWdXWsND
+5hlXquKUTSjxPYEzZvaN+tvf9e0AcY/D/UaK0mKPjEbh7vg6pS77aZZz2EL2inOs
+dam8famOOC9RUkxH5JWa3UV4UhsCgYEAy9T0wPQctjuvDkZQTqKEKsHrmrgY2PXT
+Re8DDGI8hxjYb8l+NoFQ7eiwTHir/DULupxQoBBUQtS+idQzUu02tzLMnGcjHNwh
+Tu+vZ4xlVnXxfgIRjDKkfQjiAC5SLzoNO9Jn8g4eS/1mEPXhQ0TXIsFonZDypp/n
+RMp21DkvdMUCgYAIMgwjR5rbYjEtUqJnlBlTBmD0FWDEqigQpgxdRcWgjT2nA2l0
+3AbcVwwv+6M2eg1MPASqsgvfP13CQZQ2afaKY10Zo6NTrOrLPupm+MYP4hp5w6Ox
+JI3lzGWHKYLYWKvmpEr7tZwMaXtsC7R77WP2A6hMUZA7dU2dg1ra3lrSsQKBgQDA
+sPIsUtmtwOBtqzUSEXrGfQqA+larDEGNVDVaiKfVwzwg+aeyWS+rqRS5Rj64L2GG
+KW3i020EvN/fplZap9vY9lIN7UZ5avSmDdqRFl1ajiccy1HRarKrbTFRoHibItMN
+4YvYfVZQ2h2aHQe2Myb6OULv6e4qbPIRyyDo4aKmTQKBgQCadq2JfICFIP9Q1aQn
+93oD7Z4WcYs+KsLYO+/uJxWMrn0/gv90cGrSfstJqDOHnRq4WKUcgK9ErxaE4LkW
+sD0mBhRM3SMxnRJZRO+6roRdehtjHkvzKu75KjcsuwefoMs2sFa4CLQ1YU2vO3Tx
+dgzpnKS2bH/i5yLwhelRfddZ6Q==
+-----END PRIVATE KEY-----
+-----BEGIN CERTIFICATE-----
+MIIC8TCCAdmgAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290
+IENBMCAXDTE2MDExNDIyMjkwNVoYDzIxMTYwMTE1MjIyOTA1WjASMRAwDgYDVQQD
+DAdSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAv5oV1s3N
+us7SINg7omu5AxueEgK97mh5PU3hgZpliSFaESmL2qLGeP609oXs/68XDXVW4utU
+LCOjLh0np+5Xy3i3GRDXgBZ72QDe23WqqQqqaBlQVVm1WxG+amRtZJEWdSIsiFBt
+k+8dBElHh2WQDhDOWqHGHQarQgJPxGB97MRhMSlbTwK1T5KAWOlqi5mJW5L6vNrQ
+7Tra/YceH70fU0fJYOXhBxM92NwD1bbVd9GPYFSqrdrVj19bvo63XsxZduex5QHr
+RkWqT5w5mgAHaEgCqWrS/64q9TR9UEwrB8kiZZg3k9/im+zBwEULTZu0r8oMEkpj
+bTlXLmt8EMBqxwIDAQABo1AwTjAdBgNVHQ4EFgQUcH8uroNoWZgEIyrN6z4XzSTd
+AUkwHwYDVR0jBBgwFoAUcH8uroNoWZgEIyrN6z4XzSTdAUkwDAYDVR0TBAUwAwEB
+/zANBgkqhkiG9w0BAQsFAAOCAQEAuiLq2lhcOJHrwUP0txbHk2vy6rmGTPxqmcCo
+CUQFZ3KrvUQM+rtRqqQ0+LzU4wSTFogBz9KSMfT03gPegY3b/7L2TOaMmUFRzTdd
+c9PNT0lP8V3pNQrxp0IjKir791QkGe2Ux45iMKf/SXpeTWASp4zeMiD6/LXFzzaK
+BfNS5IrIWRDev41lFasDzudK5/kmVaMvDOFyW51KkKkqb64VS4UA81JIEzClvz+3
+Vp3k1AXup5+XnTvhqu2nRhrLpJR5w8OXQpcn6qjKlVc2BXtb3xwci1/ibHlZy3CZ
+n70e2NYihU5yYKccReP+fjLgVFsuhsDs/0hRML1u9bLp9nUbYA==
+-----END CERTIFICATE-----
index 991c1cf525fdf3681be8317138f6f00ff0b469d5..04b612cde2d078bac945b0bf378770d766a65fd1 100644 (file)
@@ -11,7 +11,11 @@ srv_trusted = signer_root.crt
 
 ref_cert = signer_only.crt
 rsp_cert = signer_only.crt
-rsp_capubs = signer_root.crt
+rsp_capubs = trusted.crt
 rsp_extracerts = signer_issuing.crt
 
+rsp_newwithnew = newWithNew.pem
+rsp_newwithold = newWithOld.pem
+rsp_oldwithnew = oldWithNew.pem
+
 verbosity = 7
index dc2e922aaaf3fd5e2f4177c4b2f81ce655ced6de..5ab2ca3fd7a61696b1b235e81f1e9dbe3a49ef59 100644 (file)
@@ -56,8 +56,26 @@ expected,description, -section,val, -cmd,val,val2, -cacertsout,val,val2, -infoty
 0,genm with missing infotype value, -section,, -cmd,genm,,BLANK,,, -infotype,,,BLANK,,BLANK,
 0,genm with invalid infotype value, -section,, -cmd,genm,,BLANK,,, -infotype,asdf,,BLANK,,BLANK,
 1,genm with infotype signKeyPairTypes, -section,, -cmd,genm,,BLANK,,, -infotype,signKeyPairTypes,,BLANK,,BLANK,
-0,genm with infotype caCerts but missing -cacertsout, -section,, -cmd,genm,,BLANK,,, -infotype,caCerts,,BLANK,,BLANK,
-1,genm with infotype caCerts, -section,, -cmd,genm,, -cacertsout,_RESULT_DIR/test.cacerts.pem,, -infotype,caCerts,,BLANK,,BLANK,
+,,,,,,,,,,,,,,,,,,,,,,
+1,genm caCerts                           , -section,, -cmd,genm,, -cacertsout,_RESULT_DIR/test.cacerts.pem,, -infotype,caCerts,,BLANK,,BLANK,
+0,genm caCerts missing cacertsout option , -section,, -cmd,genm,, BLANK      ,                            ,, -infotype,caCerts,,BLANK,,BLANK,
+0,genm caCerts missing cacertsout arg    , -section,, -cmd,genm,, -cacertsout,BLANK                       ,, -infotype,caCerts,,BLANK,,BLANK,
+0,genm caCerts extra cacertsout arg      , -section,, -cmd,genm,, -cacertsout,_RESULT_DIR/test.cacerts.pem,_RESULT_DIR/test.cacerts.pem, -infotype,caCerts,,BLANK,,BLANK,
+,,,,,,,,,,,,,,,,,,,,,,
+1,genm rootCaCert with oldwithold        , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew0.pem
+1,genm rootCaCert without oldwithold     , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, BLANK      ,               , -newwithnew, _RESULT_DIR/test.newwithnew.pem
+0,genm rootCaCert oldwithold missing arg , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold,               , -newwithnew, _RESULT_DIR/test.newwithnew.pem
+0,genm rootCaCert oldwithold empty file  , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, empty.txt     , -newwithnew, _RESULT_DIR/test.newwithnew.pem
+0,genm rootCaCert oldwithold random file , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, random.bin    , -newwithnew, _RESULT_DIR/test.newwithnew.pem
+0,genm rootCaCert oldwithold nonexistent , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, idontexist    , -newwithnew, _RESULT_DIR/test.newwithnew.pem
+0,genm rootCaCert oldwithold wrong       , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, signer.crt    , -newwithnew, _RESULT_DIR/test.newwithnew.pem
+0,genm rootCaCert missing newwithnew     , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, BLANK      ,,
+0,genm rootCaCert newwithnew missing arg , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew,,
+1,genm rootCaCert with oldwithnew        , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew1.pem, -oldwithnew, _RESULT_DIR/test.oldwithnew1.pem
+0,genm rootCaCert oldwithnew missing arg , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew.pem, -oldwithnew,,
+1,genm rootCaCert newwithnew oldwithnew newwithold  , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew2.pem, -oldwithnew, _RESULT_DIR/test.oldwithnew2.pem, -newwithold, _RESULT_DIR/test.newwithold1.pem
+0,genm rootCaCert newwithold missig arg  , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew.pem, -oldwithnew, _RESULT_DIR/test.oldwithnew.pem, -newwithold,,
+1,genm rootCaCert newwithnew newwithold  , -section,, -cmd,genm,, BLANK,,, -infotype,rootCaCert,, -oldwithold, oldWithOld.pem, -newwithnew, _RESULT_DIR/test.newwithnew3.pem, -newwithold, _RESULT_DIR/test.newwithold2.pem
 ,,,,,,,,,,,,,,,,,,,,,,
 1,geninfo, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,1.2.3:int:987,BLANK,,BLANK,
 0,geninfo missing argument, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,,,,,
index 24947c673f02a7f251b83325ac557e1203b3dab6..9871821a6f6bce6b00ab5e1ede8d3d680fbe94eb 100644 (file)
@@ -5448,6 +5448,11 @@ BIO_ADDR_dup                            ?        3_2_0   EXIST::FUNCTION:SOCK
 OSSL_CMP_ITAV_new_caCerts               ?      3_2_0   EXIST::FUNCTION:CMP
 OSSL_CMP_ITAV_get0_caCerts              ?      3_2_0   EXIST::FUNCTION:CMP
 OSSL_CMP_get1_caCerts                   ?      3_2_0   EXIST::FUNCTION:CMP
+OSSL_CMP_ITAV_new_rootCaCert            ?      3_2_0   EXIST::FUNCTION:CMP
+OSSL_CMP_ITAV_get0_rootCaCert           ?      3_2_0   EXIST::FUNCTION:CMP
+OSSL_CMP_ITAV_new_rootCaKeyUpdate       ?      3_2_0   EXIST::FUNCTION:CMP
+OSSL_CMP_ITAV_get0_rootCaKeyUpdate      ?      3_2_0   EXIST::FUNCTION:CMP
+OSSL_CMP_get1_rootCaKeyUpdate           ?      3_2_0   EXIST::FUNCTION:CMP
 OSSL_CMP_CTX_get0_libctx                ?      3_2_0   EXIST::FUNCTION:CMP
 OSSL_CMP_CTX_get0_propq                 ?      3_2_0   EXIST::FUNCTION:CMP
 OSSL_CMP_CTX_reset_geninfo_ITAVs        ?      3_0_8   EXIST::FUNCTION:CMP