Commit 70c89a2c33 for openssl.org
commit 70c89a2c33b3524fdb32ee9609e526e555f11078
Author: Dr. David von Oheimb <dev@ddvo.net>
Date: Thu Oct 23 21:44:37 2025 +0200
OSSL_CMP_SRV_process_request(): complete transaction detection and context re-initialization
This motivated factoring out new functions: assuming_new_transaction()
and transaction_reinit(). It also includes a minor fix: so far, receiving
an error message from the client was taken as an indication for a new
transaction, which does not make much sense; so, this case has been dropped
in assuming_new_transaction().
Reviewed-by: Andrew Dinh <andrewd@openssl.org>
Reviewed-by: Eugene Syromiatnikov <esyr@openssl.org>
MergeDate: Thu Aug 27 07:25:01 2026
(Merged from https://github.com/openssl/openssl/pull/28988)
diff --git a/crypto/cmp/cmp_server.c b/crypto/cmp/cmp_server.c
index 8a321ecbd9..41de2790ae 100644
--- a/crypto/cmp/cmp_server.c
+++ b/crypto/cmp/cmp_server.c
@@ -55,7 +55,6 @@ OSSL_CMP_SRV_CTX *OSSL_CMP_SRV_CTX_new(OSSL_LIB_CTX *libctx, const char *propq)
if ((ctx->ctx = OSSL_CMP_CTX_new(libctx, propq)) == NULL)
goto err;
ctx->certReqId = OSSL_CMP_CERTREQID_INVALID;
- ctx->polling = 0;
/* all other elements are initialized to 0 or NULL, respectively */
return ctx;
@@ -571,6 +570,60 @@ static int unprotected_exception(const OSSL_CMP_CTX *ctx,
return 0;
}
+static int assuming_new_transaction(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req)
+{
+ int body_type = OSSL_CMP_MSG_get_bodytype(req);
+ ASN1_OCTET_STRING *tid;
+
+ if (ctx->transactionID == NULL) /* no currently active transaction */
+ return 1;
+
+ tid = OSSL_CMP_HDR_get0_transactionID(OSSL_CMP_MSG_get0_header(req));
+ if (tid != NULL && ASN1_OCTET_STRING_cmp(tid, ctx->transactionID) != 0) {
+ char *ctx_str = i2s_ASN1_OCTET_STRING(NULL, ctx->transactionID);
+ char *tid_str = i2s_ASN1_OCTET_STRING(NULL, tid);
+
+ ossl_cmp_log2(WARN, ctx, "Assuming that last transaction with ID=%s got aborted, new ID=%s",
+ ctx_str != NULL ? ctx_str : "(null)",
+ tid_str != NULL ? tid_str : "(null)");
+ OPENSSL_free(tid_str);
+ OPENSSL_free(ctx_str);
+ return 1;
+ }
+
+ switch (body_type) {
+ case OSSL_CMP_PKIBODY_IR:
+ case OSSL_CMP_PKIBODY_CR:
+ case OSSL_CMP_PKIBODY_P10CR:
+ case OSSL_CMP_PKIBODY_KUR:
+ case OSSL_CMP_PKIBODY_RR:
+ case OSSL_CMP_PKIBODY_GENM:
+ ossl_cmp_log1(WARN, ctx, "Assuming new transaction due to received body type %s",
+ ossl_cmp_bodytype_to_string(body_type));
+ return 1;
+ default:
+ return 0;
+ }
+}
+
+/* Prepare for next transaction */
+static int transaction_reinit(OSSL_CMP_SRV_CTX *srv_ctx)
+{
+ int ret = 1;
+
+ srv_ctx->ctx->status = OSSL_CMP_PKISTATUS_unspecified; /* transaction closed */
+ srv_ctx->certReqId = OSSL_CMP_CERTREQID_INVALID;
+ srv_ctx->polling = 0;
+
+ if (srv_ctx->clean_transaction != NULL)
+ ret = srv_ctx->clean_transaction(srv_ctx, srv_ctx->ctx->transactionID);
+ if (!OSSL_CMP_CTX_set1_transactionID(srv_ctx->ctx, NULL))
+ ret = 0;
+ if (!OSSL_CMP_CTX_set1_senderNonce(srv_ctx->ctx, NULL))
+ ret = 0;
+ return ret;
+}
+
/*
* returns created message and NULL on internal error
*/
@@ -613,36 +666,18 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx,
goto err;
}
- switch (req_type) {
- case OSSL_CMP_PKIBODY_IR:
- case OSSL_CMP_PKIBODY_CR:
- case OSSL_CMP_PKIBODY_P10CR:
- case OSSL_CMP_PKIBODY_KUR:
- case OSSL_CMP_PKIBODY_RR:
- case OSSL_CMP_PKIBODY_GENM:
- case OSSL_CMP_PKIBODY_ERROR:
- if (ctx->transactionID != NULL) {
- char *tid = i2s_ASN1_OCTET_STRING(NULL, ctx->transactionID);
-
- if (tid != NULL)
- ossl_cmp_log1(WARN, ctx,
- "Assuming that last transaction with ID=%s got aborted",
- tid);
- OPENSSL_free(tid);
- }
- /* start of a new transaction, reset transactionID and senderNonce */
- if (!OSSL_CMP_CTX_set1_transactionID(ctx, NULL)
- || !OSSL_CMP_CTX_set1_senderNonce(ctx, NULL))
- goto err;
-
- if (srv_ctx->clean_transaction != NULL
- && !srv_ctx->clean_transaction(srv_ctx, NULL)) {
+ if (assuming_new_transaction(ctx, req)) {
+ /*
+ * Start of a new transaction, resetting transactionID and senderNonce.
+ * Must in this case reset transactionID beforehand such that the clean()
+ * callback function gets a NULL transactionID argument, as documented.
+ */
+ (void)OSSL_CMP_CTX_set1_transactionID(ctx, NULL);
+ if (!transaction_reinit(srv_ctx)) {
ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
goto err;
}
-
- break;
- default:
+ } else {
/* transactionID should be already initialized */
if (ctx->transactionID == NULL) {
#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION
@@ -735,13 +770,9 @@ err:
case OSSL_CMP_PKIBODY_PKICONF:
case OSSL_CMP_PKIBODY_GENP:
/* Other terminating response message types are not supported */
- srv_ctx->certReqId = OSSL_CMP_CERTREQID_INVALID;
- /* Prepare for next transaction, ignoring any errors here: */
- if (srv_ctx->clean_transaction != NULL)
- (void)srv_ctx->clean_transaction(srv_ctx, ctx->transactionID);
- (void)OSSL_CMP_CTX_set1_transactionID(ctx, NULL);
- (void)OSSL_CMP_CTX_set1_senderNonce(ctx, NULL);
- ctx->status = OSSL_CMP_PKISTATUS_unspecified; /* transaction closed */
+
+ /* Prepare for next transaction, ignoring any errors here */
+ (void)transaction_reinit(srv_ctx);
default: /* not closing transaction in other cases */
break;
diff --git a/doc/man3/OSSL_CMP_SRV_CTX_new.pod b/doc/man3/OSSL_CMP_SRV_CTX_new.pod
index e82c46b800..2052e2963a 100644
--- a/doc/man3/OSSL_CMP_SRV_CTX_new.pod
+++ b/doc/man3/OSSL_CMP_SRV_CTX_new.pod
@@ -112,6 +112,9 @@ transaction (which can be a certificate confirmation or a poll request message).
The function should not be called by multiple threads sharing
the same I<srv_ctx> without explicitly serialising the calls;
calling it in parallel leads to undefined behavior.
+When an earlier call did not yet finish the respective transaction,
+calling it in an interleaved way with a new request belonging to a different
+transaction will abort the earlier transaction and begin the new one.
OSSL_CMP_CTX_server_perform() is an interface to
OSSL_CMP_SRV_process_request() that can be used by a CMP client