Add -reqin_new_tid option to apps/cmp.c and OSSL_CMP_MSG_update_transactionID()
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>
Wed, 29 Apr 2020 16:06:43 +0000 (18:06 +0200)
committerDr. David von Oheimb <David.von.Oheimb@siemens.com>
Wed, 13 May 2020 17:42:00 +0000 (19:42 +0200)
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
(Merged from https://github.com/openssl/openssl/pull/11470)

13 files changed:
apps/cmp.c
crypto/cmp/cmp_asn.c
crypto/cmp/cmp_client.c
crypto/cmp/cmp_hdr.c
crypto/cmp/cmp_local.h
crypto/cmp/cmp_msg.c
crypto/cmp/cmp_protect.c
crypto/cmp/cmp_server.c
doc/internal/man3/ossl_cmp_msg_protect.pod
doc/man1/openssl-cmp.pod.in
doc/man3/OSSL_CMP_MSG_get0_header.pod
include/openssl/cmp.h
util/libcrypto.num

index 1e4642d..cf36d67 100644 (file)
@@ -314,6 +314,7 @@ static char *opt_tls_host = NULL;
 static int opt_batch = 0;
 static int opt_repeat = 1;
 static char *opt_reqin = NULL;
+static int opt_reqin_new_tid = 0;
 static char *opt_reqout = NULL;
 static char *opt_rspin = NULL;
 static char *opt_rspout = NULL;
@@ -391,7 +392,7 @@ typedef enum OPTION_choice {
     OPT_TLS_EXTRA, OPT_TLS_TRUSTED, OPT_TLS_HOST,
 
     OPT_BATCH, OPT_REPEAT,
-    OPT_REQIN, OPT_REQOUT, OPT_RSPIN, OPT_RSPOUT,
+    OPT_REQIN, OPT_REQIN_NEW_TID, OPT_REQOUT, OPT_RSPIN, OPT_RSPOUT,
 
     OPT_USE_MOCK_SRV, OPT_PORT, OPT_MAX_MSGS,
     OPT_SRV_REF, OPT_SRV_SECRET,
@@ -594,6 +595,8 @@ const OPTIONS cmp_options[] = {
     {"repeat", OPT_REPEAT, 'n',
      "Invoke the transaction the given number of times. Default 1"},
     {"reqin", OPT_REQIN, 's', "Take sequence of CMP requests from file(s)"},
+    {"reqin_new_tid", OPT_REQIN_NEW_TID, '-',
+     "Use fresh transactionID for CMP requests read from -reqin"},
     {"reqout", OPT_REQOUT, 's', "Save sequence of CMP requests to file(s)"},
     {"rspin", OPT_RSPIN, 's',
      "Process sequence of CMP responses provided in file(s), skipping server"},
@@ -706,7 +709,8 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */
     {&opt_tls_extra}, {&opt_tls_trusted}, {&opt_tls_host},
 
     {(char **)&opt_batch}, {(char **)&opt_repeat},
-    {&opt_reqin}, {&opt_reqout}, {&opt_rspin}, {&opt_rspout},
+    {&opt_reqin}, {(char **)&opt_reqin_new_tid},
+    {&opt_reqout}, {&opt_rspin}, {&opt_rspout},
 
     {(char **)&opt_use_mock_srv}, {&opt_port}, {(char **)&opt_max_msgs},
     {&opt_srv_ref}, {&opt_srv_secret},
@@ -1161,26 +1165,17 @@ static OSSL_CMP_MSG *read_write_req_resp(OSSL_CMP_CTX *ctx,
     if (req != NULL && opt_reqout != NULL
             && !write_PKIMESSAGE(req, &opt_reqout))
         goto err;
-    if (opt_reqin != NULL) {
-        if (opt_rspin != NULL) {
-            CMP_warn("-reqin is ignored since -rspin is present");
-        } else {
-            if ((req_new = read_PKIMESSAGE(&opt_reqin)) == NULL)
-                goto err;
-            /*-
-             * The transaction ID in req_new may not be fresh.
-             * In this case the Insta Demo CA correctly complains:
-             * "Transaction id already in use."
-             * The following workaround unfortunately requires re-protection.
-             * See also https://github.com/mpeylo/cmpossl/issues/8
-             */
-#if defined(USE_TRANSACTIONID_WORKAROUND)
-            hdr = OSSL_CMP_MSG_get0_header(req_new);
-            if (!OSSL_CMP_CTX_set1_transactionID(hdr, NULL)
-                    || !ossl_cmp_msg_protect(ctx, req_new))
-                goto err;
-#endif
-        }
+    if (opt_reqin != NULL && opt_rspin == NULL) {
+        if ((req_new = read_PKIMESSAGE(&opt_reqin)) == NULL)
+            goto err;
+        /*-
+         * The transaction ID in req_new read from opt_reqin may not be fresh.
+         * In this case the server may complain "Transaction id already in use."
+         * The following workaround unfortunately requires re-protection.
+         */
+        if (opt_reqin_new_tid
+                && !OSSL_CMP_MSG_update_transactionID(ctx, req_new))
+            goto err;
     }
 
     if (opt_rspin != NULL) {
@@ -2325,6 +2320,10 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *e)
         (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_TOTAL_TIMEOUT,
                                       opt_total_timeout);
 
+    if (opt_reqin != NULL && opt_rspin != NULL)
+        CMP_warn("-reqin is ignored since -rspin is present");
+    if (opt_reqin_new_tid && opt_reqin == NULL)
+        CMP_warn("-reqin_new_tid is ignored since -reqin is not present");
     if (opt_reqin != NULL || opt_reqout != NULL
             || opt_rspin != NULL || opt_rspout != NULL || opt_use_mock_srv)
         (void)OSSL_CMP_CTX_set_transfer_cb(ctx, read_write_req_resp);
@@ -2899,6 +2898,9 @@ static int get_opts(int argc, char **argv)
         case OPT_REQIN:
             opt_reqin = opt_str("reqin");
             break;
+        case OPT_REQIN_NEW_TID:
+            opt_reqin_new_tid = 1;
+            break;
         case OPT_REQOUT:
             opt_reqout = opt_str("reqout");
             break;
index 703bd8c..f109af0 100644 (file)
@@ -70,7 +70,8 @@ ASN1_SEQUENCE(OSSL_CMP_ERRORMSGCONTENT) = {
      * so it is used directly
      *
      */
-    ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ERRORMSGCONTENT, errorDetails, ASN1_UTF8STRING)
+    ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ERRORMSGCONTENT, errorDetails,
+                         ASN1_UTF8STRING)
 } ASN1_SEQUENCE_END(OSSL_CMP_ERRORMSGCONTENT)
 IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_ERRORMSGCONTENT)
 
@@ -352,8 +353,10 @@ ASN1_CHOICE(OSSL_CMP_PKIBODY) = {
     ASN1_EXP(OSSL_CMP_PKIBODY, value.cr, OSSL_CRMF_MSGS, 2),
     ASN1_EXP(OSSL_CMP_PKIBODY, value.cp, OSSL_CMP_CERTREPMESSAGE, 3),
     ASN1_EXP(OSSL_CMP_PKIBODY, value.p10cr, X509_REQ, 4),
-    ASN1_EXP(OSSL_CMP_PKIBODY, value.popdecc, OSSL_CMP_POPODECKEYCHALLCONTENT, 5),
-    ASN1_EXP(OSSL_CMP_PKIBODY, value.popdecr, OSSL_CMP_POPODECKEYRESPCONTENT, 6),
+    ASN1_EXP(OSSL_CMP_PKIBODY, value.popdecc,
+             OSSL_CMP_POPODECKEYCHALLCONTENT, 5),
+    ASN1_EXP(OSSL_CMP_PKIBODY, value.popdecr,
+             OSSL_CMP_POPODECKEYRESPCONTENT, 6),
     ASN1_EXP(OSSL_CMP_PKIBODY, value.kur, OSSL_CRMF_MSGS, 7),
     ASN1_EXP(OSSL_CMP_PKIBODY, value.kup, OSSL_CMP_CERTREPMESSAGE, 8),
     ASN1_EXP(OSSL_CMP_PKIBODY, value.krr, OSSL_CRMF_MSGS, 9),
index f561f72..d309f84 100644 (file)
@@ -176,7 +176,7 @@ static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req,
 
     if (*rep == NULL) {
         CMPerr(0, CMP_R_TRANSFER_ERROR); /* or receiving response */
-        ERR_add_error_data(1, req_type_str);
+        ERR_add_error_data(2, "request sent: ", req_type_str);
         ERR_add_error_data(2, ", expected response: ", expected_type_str);
         return 0;
     }
@@ -211,7 +211,8 @@ static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req,
         char buf[OSSL_CMP_PKISI_BUFLEN];
 
         if (save_statusInfo(ctx, si)
-                && OSSL_CMP_CTX_snprint_PKIStatus(ctx, buf, sizeof(buf)) != NULL)
+                && OSSL_CMP_CTX_snprint_PKIStatus(ctx, buf,
+                                                  sizeof(buf)) != NULL)
             ERR_add_error_data(1, buf);
         if (emc->errorCode != NULL
                 && BIO_snprintf(buf, sizeof(buf), "; errorCode: %ld",
index c249342..157247d 100644 (file)
@@ -41,7 +41,8 @@ int ossl_cmp_hdr_get_pvno(const OSSL_CMP_PKIHEADER *hdr)
     return (int)pvno;
 }
 
-ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const OSSL_CMP_PKIHEADER *hdr)
+ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const
+                                                   OSSL_CMP_PKIHEADER *hdr)
 {
     if (hdr == NULL) {
         CMPerr(0, CMP_R_NULL_ARGUMENT);
@@ -266,6 +267,25 @@ int ossl_cmp_hdr_has_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr)
     return 0;
 }
 
+/*
+ * set ctx->transactionID in CMP header
+ * if ctx->transactionID is NULL, a random one is created with 128 bit
+ * according to section 5.1.1:
+ *
+ * It is RECOMMENDED that the clients fill the transactionID field with
+ * 128 bits of (pseudo-) random data for the start of a transaction to
+ * reduce the probability of having the transactionID in use at the server.
+ */
+int ossl_cmp_hdr_set_transactionID(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr)
+{
+    if (ctx->transactionID == NULL
+            && !set1_aostr_else_random(&ctx->transactionID, NULL,
+                                       OSSL_CMP_TRANSACTIONID_LENGTH))
+        return 0;
+    return ossl_cmp_asn1_octet_string_set1(&hdr->transactionID,
+                                           ctx->transactionID);
+}
+
 /* fill in all fields of the hdr according to the info given in ctx */
 int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr)
 {
@@ -316,21 +336,7 @@ int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr)
                                                 ctx->recipNonce))
         return 0;
 
-    /*
-     * set ctx->transactionID in CMP header
-     * if ctx->transactionID is NULL, a random one is created with 128 bit
-     * according to section 5.1.1:
-     *
-     * It is RECOMMENDED that the clients fill the transactionID field with
-     * 128 bits of (pseudo-) random data for the start of a transaction to
-     * reduce the probability of having the transactionID in use at the server.
-     */
-    if (ctx->transactionID == NULL
-            && !set1_aostr_else_random(&ctx->transactionID, NULL,
-                                       OSSL_CMP_TRANSACTIONID_LENGTH))
-        return 0;
-    if (!ossl_cmp_asn1_octet_string_set1(&hdr->transactionID,
-                                         ctx->transactionID))
+    if (!ossl_cmp_hdr_set_transactionID(ctx, hdr))
         return 0;
 
     /*-
index 9acafba..62d7dbd 100644 (file)
@@ -790,7 +790,7 @@ int ossl_cmp_ctx_set1_recipNonce(OSSL_CMP_CTX *ctx,
 /* from cmp_status.c */
 int ossl_cmp_pkisi_get_status(const OSSL_CMP_PKISI *si);
 const char *ossl_cmp_PKIStatus_to_string(int status);
-OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusString(const OSSL_CMP_PKISI *si);
+OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusString(const OSSL_CMP_PKISI *s);
 int ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si);
 int ossl_cmp_pkisi_check_pkifailureinfo(const OSSL_CMP_PKISI *si, int index);
 
@@ -814,6 +814,7 @@ int ossl_cmp_hdr_set_implicitConfirm(OSSL_CMP_PKIHEADER *hdr);
 int ossl_cmp_hdr_has_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr);
 # define OSSL_CMP_TRANSACTIONID_LENGTH 16
 # define OSSL_CMP_SENDERNONCE_LENGTH 16
+int ossl_cmp_hdr_set_transactionID(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr);
 int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr);
 
 /* from cmp_msg.c */
@@ -885,13 +886,13 @@ OSSL_CMP_MSG *ossl_cmp_pollRep_new(OSSL_CMP_CTX *ctx, int crid,
                                    int64_t poll_after);
 OSSL_CMP_PKISI *
 ossl_cmp_revrepcontent_get_pkisi(OSSL_CMP_REVREPCONTENT *rrep, int rsid);
-OSSL_CRMF_CERTID *ossl_cmp_revrepcontent_get_CertId(OSSL_CMP_REVREPCONTENT *rrep,
+OSSL_CRMF_CERTID *ossl_cmp_revrepcontent_get_CertId(OSSL_CMP_REVREPCONTENT *rc,
                                                     int rsid);
 OSSL_CMP_POLLREP *
 ossl_cmp_pollrepcontent_get0_pollrep(const OSSL_CMP_POLLREPCONTENT *prc,
                                      int rid);
 OSSL_CMP_CERTRESPONSE *
-ossl_cmp_certrepmessage_get0_certresponse(const OSSL_CMP_CERTREPMESSAGE *crepmsg,
+ossl_cmp_certrepmessage_get0_certresponse(const OSSL_CMP_CERTREPMESSAGE *crm,
                                           int rid);
 X509 *ossl_cmp_certresponse_get1_certificate(EVP_PKEY *privkey,
                                              const OSSL_CMP_CERTRESPONSE *crep);
@@ -916,6 +917,6 @@ int ossl_cmp_verify_popo(const OSSL_CMP_MSG *msg, int accept_RAVerified);
 int ossl_cmp_exchange_certConf(OSSL_CMP_CTX *ctx, int fail_info,
                                const char *txt);
 int ossl_cmp_exchange_error(OSSL_CMP_CTX *ctx, int status, int fail_info,
-                            const char *txt, int errorCode, const char *details);
+                            const char *txt, int errorCode, const char *detail);
 
 #endif /* !defined(OSSL_CRYPTO_CMP_LOCAL_H) */
index dc11b54..0534cae 100644 (file)
@@ -584,9 +584,9 @@ int ossl_cmp_msg_gen_push1_ITAVs(OSSL_CMP_MSG *msg,
         return 0;
 
     for (i = 0; i < sk_OSSL_CMP_ITAV_num(itavs); i++) {
-        if ((itav = OSSL_CMP_ITAV_dup(sk_OSSL_CMP_ITAV_value(itavs, i))) == NULL)
-            return 0;
-        if (!ossl_cmp_msg_gen_push0_ITAV(msg, itav)) {
+        itav = OSSL_CMP_ITAV_dup(sk_OSSL_CMP_ITAV_value(itavs, i));
+        if (itav == NULL
+                || !ossl_cmp_msg_gen_push0_ITAV(msg, itav)) {
             OSSL_CMP_ITAV_free(itav);
             return 0;
         }
@@ -982,6 +982,18 @@ X509 *ossl_cmp_certresponse_get1_certificate(EVP_PKEY *privkey,
     return crt;
 }
 
+int OSSL_CMP_MSG_update_transactionID(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
+{
+    if (ctx == NULL || msg == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+    if (!ossl_cmp_hdr_set_transactionID(ctx, msg->header))
+        return 0;
+    return msg->header->protectionAlg == NULL
+            || ossl_cmp_msg_protect(ctx, msg);
+}
+
 OSSL_CMP_MSG *ossl_cmp_msg_load(const char *file)
 {
     OSSL_CMP_MSG *msg = NULL;
index 3e0c22b..0b87acd 100644 (file)
@@ -145,21 +145,18 @@ int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
             && (msg->extraCerts = sk_X509_new_null()) == NULL)
         return 0;
 
-    if (ctx->clCert != NULL) {
-        /* Make sure that our own cert gets sent, in the first position */
-        if (!X509_up_ref(ctx->clCert))
+    if (ctx->clCert != NULL && ctx->pkey != NULL) {
+        /* make sure that our own cert is included in the first position */
+        if (!ossl_cmp_sk_X509_add1_cert(msg->extraCerts, ctx->clCert, 1, 1))
             return 0;
-        if (!sk_X509_push(msg->extraCerts, ctx->clCert)) {
-            X509_free(ctx->clCert);
-            return 0;
-        }
-        /* if we have untrusted store, try to add intermediate certs */
+        /* if we have untrusted certs, try to add intermediate certs */
         if (ctx->untrusted_certs != NULL) {
             STACK_OF(X509) *chain =
                 ossl_cmp_build_cert_chain(ctx->untrusted_certs, ctx->clCert);
             int res = ossl_cmp_sk_X509_add1_certs(msg->extraCerts, chain,
                                                   1 /* no self-issued */,
                                                   1 /* no duplicates */, 0);
+
             sk_X509_pop_free(chain, X509_free);
             if (res == 0)
                 return 0;
@@ -227,6 +224,15 @@ int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
     if (!ossl_assert(ctx != NULL && msg != NULL))
         return 0;
 
+    /*
+     * For the case of re-protection remove pre-existing protection.
+     * TODO: Consider also removing any pre-existing extraCerts.
+     */
+    X509_ALGOR_free(msg->header->protectionAlg);
+    msg->header->protectionAlg = NULL;
+    ASN1_BIT_STRING_free(msg->protection);
+    msg->protection = NULL;
+
     if (ctx->unprotectedSend)
         return 1;
 
@@ -238,84 +244,70 @@ int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg)
                 && !ossl_cmp_hdr_set1_senderKID(msg->header,
                                                 ctx->referenceValue))
             goto err;
-
-        /*
-         * add any additional certificates from ctx->extraCertsOut
-         * while not needed to validate the signing cert, the option to do
-         * this might be handy for certain use cases
-         */
-        if (!ossl_cmp_msg_add_extraCerts(ctx, msg))
-            goto err;
-
-        if ((msg->protection =
-             ossl_cmp_calc_protection(msg, ctx->secretValue, NULL)) == NULL)
-            goto err;
-    } else {
+    } else if (ctx->clCert != NULL && ctx->pkey != NULL) {
         /*
          * use MSG_SIG_ALG according to 5.1.3.3 if client Certificate and
          * private key is given
          */
-        if (ctx->clCert != NULL && ctx->pkey != NULL) {
-            const ASN1_OCTET_STRING *subjKeyIDStr = NULL;
-            int algNID = 0;
-            ASN1_OBJECT *alg = NULL;
-
-            /* make sure that key and certificate match */
-            if (!X509_check_private_key(ctx->clCert, ctx->pkey)) {
-                CMPerr(0, CMP_R_CERT_AND_KEY_DO_NOT_MATCH);
-                goto err;
-            }
-
-            if (msg->header->protectionAlg == NULL)
-                if ((msg->header->protectionAlg = X509_ALGOR_new()) == NULL)
-                    goto err;
+        const ASN1_OCTET_STRING *subjKeyIDStr = NULL;
+        int algNID = 0;
+        ASN1_OBJECT *alg = NULL;
 
-            if (!OBJ_find_sigid_by_algs(&algNID, ctx->digest,
-                                        EVP_PKEY_id(ctx->pkey))) {
-                CMPerr(0, CMP_R_UNSUPPORTED_KEY_TYPE);
-                goto err;
-            }
-            if ((alg = OBJ_nid2obj(algNID)) == NULL)
-                goto err;
-            if (!X509_ALGOR_set0(msg->header->protectionAlg,
-                                 alg, V_ASN1_UNDEF, NULL)) {
-                ASN1_OBJECT_free(alg);
-                goto err;
-            }
-
-            /*
-             * set senderKID to keyIdentifier of the used certificate according
-             * to section 5.1.1
-             */
-            subjKeyIDStr = X509_get0_subject_key_id(ctx->clCert);
-            if (subjKeyIDStr == NULL)
-                subjKeyIDStr = ctx->referenceValue; /* fallback */
-            if (subjKeyIDStr != NULL
-                    && !ossl_cmp_hdr_set1_senderKID(msg->header, subjKeyIDStr))
-                goto err;
+        /* make sure that key and certificate match */
+        if (!X509_check_private_key(ctx->clCert, ctx->pkey)) {
+            CMPerr(0, CMP_R_CERT_AND_KEY_DO_NOT_MATCH);
+            goto err;
+        }
 
-            /*
-             * Add ctx->clCert followed, if possible, by its chain built
-             * from ctx->untrusted_certs, and then ctx->extraCertsOut
-             */
-            if (!ossl_cmp_msg_add_extraCerts(ctx, msg))
+        if (msg->header->protectionAlg == NULL)
+            if ((msg->header->protectionAlg = X509_ALGOR_new()) == NULL)
                 goto err;
 
-            if ((msg->protection =
-                 ossl_cmp_calc_protection(msg, NULL, ctx->pkey)) == NULL)
-                goto err;
-        } else {
-            CMPerr(0, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION);
+        if (!OBJ_find_sigid_by_algs(&algNID, ctx->digest,
+                                    EVP_PKEY_id(ctx->pkey))) {
+            CMPerr(0, CMP_R_UNSUPPORTED_KEY_TYPE);
             goto err;
         }
+        if ((alg = OBJ_nid2obj(algNID)) == NULL)
+            goto err;
+        if (!X509_ALGOR_set0(msg->header->protectionAlg, alg,
+                             V_ASN1_UNDEF, NULL)) {
+            ASN1_OBJECT_free(alg);
+            goto err;
+        }
+
+        /*
+         * set senderKID to keyIdentifier of the used certificate according
+         * to section 5.1.1
+         */
+        subjKeyIDStr = X509_get0_subject_key_id(ctx->clCert);
+        if (subjKeyIDStr == NULL)
+            subjKeyIDStr = ctx->referenceValue; /* fallback */
+        if (subjKeyIDStr != NULL
+                && !ossl_cmp_hdr_set1_senderKID(msg->header, subjKeyIDStr))
+            goto err;
+    } else {
+        CMPerr(0, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION);
+        goto err;
     }
+    if ((msg->protection =
+         ossl_cmp_calc_protection(msg, ctx->secretValue, ctx->pkey)) == NULL)
+        goto err;
+
+    /*
+     * If present, add ctx->clCert followed by its chain as far as possible.
+     * Finally add any additional certificates from ctx->extraCertsOut;
+     * even if not needed to validate the protection
+     * the option to do this might be handy for certain use cases.
+     */
+    if (!ossl_cmp_msg_add_extraCerts(ctx, msg))
+        goto err;
 
     /*
      * As required by RFC 4210 section 5.1.1., if the sender name is not known
      * to the client it set to NULL-DN. In this case for identification at least
      * the senderKID must be set, where we took the referenceValue as fallback.
      */
-
     if (ossl_cmp_general_name_is_NULL_DN(msg->header->sender)
             && msg->header->senderKID == NULL)
         CMPerr(0, CMP_R_MISSING_SENDER_IDENTIFICATION);
index 8bd3b56..b805dc8 100644 (file)
@@ -221,7 +221,8 @@ static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
         if (si == NULL)
             goto err;
         /* set OSSL_CMP_OPT_IMPLICIT_CONFIRM if and only if transaction ends */
-        if (!OSSL_CMP_CTX_set_option(srv_ctx->ctx, OSSL_CMP_OPT_IMPLICIT_CONFIRM,
+        if (!OSSL_CMP_CTX_set_option(srv_ctx->ctx,
+                                     OSSL_CMP_OPT_IMPLICIT_CONFIRM,
                                      ossl_cmp_hdr_has_implicitConfirm(hdr)
                                          && srv_ctx->grantImplicitConfirm
                                          /* do not set if polling starts: */
index a931d3c..7c5e10b 100644 (file)
@@ -15,9 +15,9 @@ ossl_cmp_msg_add_extraCerts
 
 =head1 DESCRIPTION
 
-ossl_cmp_msg_protect() protects the given message B<msg> using an algorithm
+ossl_cmp_msg_protect() (re-)protects the given message B<msg> using an algorithm
 depending on the available context information given in the B<ctx>.
-If there is a secretValue it selects PBMAC. Else if there is a clCert
+If there is a secretValue it selects PBMAC, else if there is a clCert
 it selects Signature and uses B<ossl_cmp_msg_add_extraCerts()>.
 It also sets the protectionAlg field in the message header accordingly.
 
index a99391a..cf7f6aa 100644 (file)
@@ -85,6 +85,7 @@ B<openssl> B<cmp>
 [B<-batch>]
 [B<-repeat> I<number>]
 [B<-reqin>] I<filenames>
+[B<-reqin_new_tid>]
 [B<-reqout>] I<filenames>
 [B<-rspin>] I<filenames>
 [B<-rspout>] I<filenames>
@@ -798,6 +799,13 @@ Multiple filenames may be given, separated by commas and/or whitespace
 (where in the latter case the whole argument must be enclosed in "...").
 As many files are read as needed for a complete transaction.
 
+=item B<-reqin_new_tid>
+
+Use a fresh transactionID for CMP request messages read using B<-reqin>,
+which requires re-protecting them as far as they were protected before.
+This may be needed in case the sequence of requests is reused
+and the CMP server complains that the transaction ID has already been used.
+
 =item B<-reqout> I<filenames>
 
 Save sequence of CMP requests to file(s).
index bd51eb5..3ab76c1 100644 (file)
@@ -3,6 +3,7 @@
 =head1 NAME
 
 OSSL_CMP_MSG_get0_header,
+OSSL_CMP_MSG_update_transactionID,
 d2i_OSSL_CMP_MSG_bio,
 i2d_OSSL_CMP_MSG_bio
 - function(s) manipulating CMP messages
@@ -12,17 +13,22 @@ i2d_OSSL_CMP_MSG_bio
   #include <openssl/cmp.h>
 
   OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg);
+  int OSSL_CMP_MSG_update_transactionID(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
   OSSL_CMP_MSG *d2i_OSSL_CMP_MSG_bio(BIO *bio, OSSL_CMP_MSG **msg);
   int i2d_OSSL_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg);
 
 =head1 DESCRIPTION
 
-OSSL_CMP_MSG_get0_header returns the header of the given CMP message.
+OSSL_CMP_MSG_get0_header() returns the header of the given CMP message.
 
-d2i_OSSL_CMP_MSG_bio parses an ASN.1-encoded OSSL_CMP_MSG from the BIO I<bio>.
+OSSL_CMP_MSG_update_transactionID() updates the transactionID field
+in the header of the given message according to the CMP_CTX.
+This requires re-protecting the message (if it was protected).
+
+d2i_OSSL_CMP_MSG_bio() parses an ASN.1-encoded OSSL_CMP_MSG from the BIO I<bio>.
 It assigns a pointer to the new structure to I<*msg> if I<msg> is not NULL.
 
-i2d_OSSL_CMP_MSG_bio writes the OSSL_CMP_MSG I<msg> in ASN.1 encoding
+i2d_OSSL_CMP_MSG_bio() writes the OSSL_CMP_MSG I<msg> in ASN.1 encoding
 to BIO I<bio>.
 
 =head1 NOTES
@@ -36,7 +42,8 @@ or NULL if the respective entry does not exist and on error.
 
 d2i_OSSL_CMP_MSG_bio() returns the parsed message or NULL on error.
 
-i2d_OSSL_CMP_MSG_bio() returns 1 on success or 0 on error.
+i2d_OSSL_CMP_MSG_bio() and OSSL_CMP_MSG_update_transactionID()
+return 1 on success, 0 on error.
 
 =head1 HISTORY
 
index 66e3f40..5741606 100644 (file)
@@ -310,7 +310,8 @@ int OSSL_CMP_CTX_set0_newPkey(OSSL_CMP_CTX *ctx, int priv, EVP_PKEY *pkey);
 EVP_PKEY *OSSL_CMP_CTX_get0_newPkey(const OSSL_CMP_CTX *ctx, int priv);
 int OSSL_CMP_CTX_set1_issuer(OSSL_CMP_CTX *ctx, const X509_NAME *name);
 int OSSL_CMP_CTX_set1_subjectName(OSSL_CMP_CTX *ctx, const X509_NAME *name);
-int OSSL_CMP_CTX_push1_subjectAltName(OSSL_CMP_CTX *ctx, const GENERAL_NAME *name);
+int OSSL_CMP_CTX_push1_subjectAltName(OSSL_CMP_CTX *ctx,
+                                      const GENERAL_NAME *name);
 int OSSL_CMP_CTX_set0_reqExtensions(OSSL_CMP_CTX *ctx, X509_EXTENSIONS *exts);
 int OSSL_CMP_CTX_reqExtensions_have_SAN(OSSL_CMP_CTX *ctx);
 int OSSL_CMP_CTX_push0_policy(OSSL_CMP_CTX *ctx, POLICYINFO *pinfo);
@@ -346,11 +347,13 @@ OSSL_CMP_PKISI *
 OSSL_CMP_STATUSINFO_new(int status, int fail_info, const char *text);
 
 /* from cmp_hdr.c */
-ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const OSSL_CMP_PKIHEADER *hdr);
+ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const
+                                                   OSSL_CMP_PKIHEADER *hdr);
 ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr);
 
 /* from cmp_msg.c */
 OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg);
+int OSSL_CMP_MSG_update_transactionID(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
 OSSL_CMP_MSG *d2i_OSSL_CMP_MSG_bio(BIO *bio, OSSL_CMP_MSG **msg);
 int i2d_OSSL_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg);
 
@@ -387,7 +390,7 @@ typedef void (*OSSL_CMP_SRV_error_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
                                         const OSSL_CMP_MSG *req,
                                         const OSSL_CMP_PKISI *statusInfo,
                                         const ASN1_INTEGER *errorCode,
-                                        const OSSL_CMP_PKIFREETEXT *errorDetails);
+                                        const OSSL_CMP_PKIFREETEXT *errDetails);
 typedef int (*OSSL_CMP_SRV_certConf_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx,
                                           const OSSL_CMP_MSG *req,
                                           int certReqId,
@@ -418,10 +421,10 @@ X509 *OSSL_CMP_exec_IR_ses(OSSL_CMP_CTX *ctx);
 X509 *OSSL_CMP_exec_CR_ses(OSSL_CMP_CTX *ctx);
 X509 *OSSL_CMP_exec_P10CR_ses(OSSL_CMP_CTX *ctx);
 X509 *OSSL_CMP_exec_KUR_ses(OSSL_CMP_CTX *ctx);
-# define OSSL_CMP_IR    OSSL_CMP_PKIBODY_IR
-# define OSSL_CMP_CR    OSSL_CMP_PKIBODY_CR
-# define OSSL_CMP_P10CR OSSL_CMP_PKIBODY_P10CR
-# define OSSL_CMP_KUR   OSSL_CMP_PKIBODY_KUR
+#  define OSSL_CMP_IR    OSSL_CMP_PKIBODY_IR
+#  define OSSL_CMP_CR    OSSL_CMP_PKIBODY_CR
+#  define OSSL_CMP_P10CR OSSL_CMP_PKIBODY_P10CR
+#  define OSSL_CMP_KUR   OSSL_CMP_PKIBODY_KUR
 int OSSL_CMP_try_certreq(OSSL_CMP_CTX *ctx, int req_type, int *checkAfter);
 int OSSL_CMP_certConf_cb(OSSL_CMP_CTX *ctx, X509 *cert, int fail_info,
                          const char **text);
index 590157f..dd69168 100644 (file)
@@ -4902,6 +4902,7 @@ i2d_X509_PUBKEY_bio                     ? 3_0_0   EXIST::FUNCTION:
 RSA_get0_pss_params                     ?      3_0_0   EXIST::FUNCTION:DEPRECATEDIN_3_0,RSA
 X509_cmp_timeframe                      ?      3_0_0   EXIST::FUNCTION:
 OSSL_CMP_MSG_get0_header                ?      3_0_0   EXIST::FUNCTION:CMP
+OSSL_CMP_MSG_update_transactionID       ?      3_0_0   EXIST::FUNCTION:CMP
 BIO_f_prefix                            ?      3_0_0   EXIST::FUNCTION:
 EVP_PKEY_CTX_new_from_name              ?      3_0_0   EXIST::FUNCTION:
 EVP_PKEY_CTX_new_from_pkey              ?      3_0_0   EXIST::FUNCTION: