summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--CHANGES.md5
-rw-r--r--apps/cmp.c44
-rw-r--r--apps/lib/cmp_mock_srv.c36
-rw-r--r--crypto/cmp/cmp_asn.c54
-rw-r--r--crypto/cmp/cmp_ctx.c2
-rw-r--r--crypto/cmp/cmp_err.c2
-rw-r--r--crypto/cmp/cmp_hdr.c10
-rw-r--r--crypto/cmp/cmp_local.h2
-rw-r--r--crypto/err/openssl.txt1
-rw-r--r--doc/man1/openssl-cmp.pod.in10
-rw-r--r--doc/man3/OSSL_CMP_CTX_new.pod13
-rw-r--r--doc/man3/OSSL_CMP_HDR_get0_transactionID.pod10
-rw-r--r--doc/man3/OSSL_CMP_ITAV_set0.pod35
-rw-r--r--include/openssl/cmp.h.in8
-rw-r--r--include/openssl/cmperr.h1
-rw-r--r--test/recipes/80-test_cmp_http_data/test_commands.csv5
-rw-r--r--util/libcrypto.num4
17 files changed, 213 insertions, 29 deletions
diff --git a/CHANGES.md b/CHANGES.md
index 93365619fa..f1c8bce1b3 100644
--- a/CHANGES.md
+++ b/CHANGES.md
@@ -33,6 +33,11 @@ OpenSSL 3.3
*James Muir*
+ * Added several new features of CMPv3 defined in RFC 9480 and RFC 9483:
+ - `certProfile` request message header and respective `-profile` CLI option
+
+ *David von Oheimb*
+
* The build of exporters (such as `.pc` files for pkg-config) cleaned up to
be less hard coded in the build file templates, and to allow easier
addition of more exporters. With that, an exporter for CMake is also
diff --git a/apps/cmp.c b/apps/cmp.c
index dd5a69af7c..67f281e0aa 100644
--- a/apps/cmp.c
+++ b/apps/cmp.c
@@ -112,6 +112,7 @@ static int opt_cmd = -1;
static char *opt_geninfo = NULL;
static char *opt_infotype_s = NULL;
static int opt_infotype = NID_undef;
+static char *opt_profile = NULL;
/* certificate enrollment */
static char *opt_newkey = NULL;
@@ -210,7 +211,7 @@ typedef enum OPTION_choice {
OPT_COMMON,
OPT_CONFIG, OPT_SECTION, OPT_VERBOSITY,
- OPT_CMD, OPT_INFOTYPE, OPT_GENINFO,
+ OPT_CMD, OPT_INFOTYPE, OPT_PROFILE, OPT_GENINFO,
OPT_NEWKEY, OPT_NEWKEYPASS, OPT_SUBJECT,
OPT_DAYS, OPT_REQEXTS,
@@ -291,6 +292,8 @@ const OPTIONS cmp_options[] = {
"InfoType name for requesting specific info in genm, with specific support"},
{OPT_MORE_STR, 0, 0,
"for 'caCerts' and 'rootCaCert'"},
+ {"profile", OPT_PROFILE, 's',
+ "Certificate profile name to place in generalInfo field of request PKIHeader"},
{"geninfo", OPT_GENINFO, 's',
"generalInfo integer values to place in request PKIHeader with given OID"},
{OPT_MORE_STR, 0, 0,
@@ -587,7 +590,7 @@ typedef union {
static varref cmp_vars[] = { /* must be in same order as enumerated above! */
{&opt_config}, {&opt_section}, {(char **)&opt_verbosity},
- {&opt_cmd_s}, {&opt_infotype_s}, {&opt_geninfo},
+ {&opt_cmd_s}, {&opt_infotype_s}, {&opt_profile}, {&opt_geninfo},
{&opt_newkey}, {&opt_newkeypass}, {&opt_subject},
{(char **)&opt_days}, {&opt_reqexts},
@@ -1837,6 +1840,37 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine)
return 0;
}
+static int add_certProfile(OSSL_CMP_CTX *ctx, const char *name)
+{
+ OSSL_CMP_ITAV *itav = NULL;
+ STACK_OF(ASN1_UTF8STRING) *sk;
+ ASN1_UTF8STRING *utf8string;
+
+ if (ctx == NULL || name == NULL)
+ return 0;
+
+ if ((sk = sk_ASN1_UTF8STRING_new_reserve(NULL, 1)) == NULL)
+ return 0;
+ if ((utf8string = ASN1_UTF8STRING_new()) == NULL)
+ goto err;
+ if (!ASN1_STRING_set(utf8string, name, (int)strlen(name))) {
+ ASN1_STRING_free(utf8string);
+ goto err;
+ }
+ /* Due to sk_ASN1_UTF8STRING_new_reserve(NULL, 1), this surely succeeds: */
+ (void)sk_ASN1_UTF8STRING_push(sk, utf8string);
+ if ((itav = OSSL_CMP_ITAV_new0_certProfile(sk)) == NULL)
+ goto err;
+ if (OSSL_CMP_CTX_push0_geninfo_ITAV(ctx, itav))
+ return 1;
+ OSSL_CMP_ITAV_free(itav);
+ return 0;
+
+ err:
+ sk_ASN1_UTF8STRING_pop_free(sk, ASN1_UTF8STRING_free);
+ return 0;
+}
+
static int handle_opt_geninfo(OSSL_CMP_CTX *ctx)
{
long value;
@@ -2078,6 +2112,8 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine)
if (opt_geninfo != NULL && !handle_opt_geninfo(ctx))
goto err;
+ if (opt_profile != NULL && !add_certProfile(ctx, opt_profile))
+ goto err;
/* not printing earlier, to minimize confusion in case setup fails before */
if (opt_rspin != NULL)
@@ -2603,6 +2639,9 @@ static int get_opts(int argc, char **argv)
case OPT_INFOTYPE:
opt_infotype_s = opt_str();
break;
+ case OPT_PROFILE:
+ opt_profile = opt_str();
+ break;
case OPT_GENINFO:
opt_geninfo = opt_str();
break;
@@ -3131,6 +3170,7 @@ int cmp_main(int argc, char **argv)
cmp_ctx = OSSL_CMP_CTX_new(app_get0_libctx(), app_get0_propq());
if (cmp_ctx == NULL)
goto err;
+
OSSL_CMP_CTX_set_log_verbosity(cmp_ctx, opt_verbosity);
if (!OSSL_CMP_CTX_set_log_cb(cmp_ctx, print_to_bio_out)) {
CMP_err1("cannot set up error reporting and logging for %s", prog);
diff --git a/apps/lib/cmp_mock_srv.c b/apps/lib/cmp_mock_srv.c
index a0450446c1..d58937ea78 100644
--- a/apps/lib/cmp_mock_srv.c
+++ b/apps/lib/cmp_mock_srv.c
@@ -241,6 +241,42 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
/* give final response after polling */
ctx->curr_pollCount = 0;
+ /* accept cert profile for cr messages only with the configured name */
+ if (OSSL_CMP_MSG_get_bodytype(cert_req) == OSSL_CMP_CR) {
+ STACK_OF(OSSL_CMP_ITAV) *itavs =
+ OSSL_CMP_HDR_get0_geninfo_ITAVs(OSSL_CMP_MSG_get0_header(cert_req));
+ int i;
+
+ for (i = 0; i < sk_OSSL_CMP_ITAV_num(itavs); i++) {
+ OSSL_CMP_ITAV *itav = sk_OSSL_CMP_ITAV_value(itavs, i);
+ ASN1_OBJECT *obj = OSSL_CMP_ITAV_get0_type(itav);
+ STACK_OF(ASN1_UTF8STRING) *strs;
+ ASN1_UTF8STRING *str;
+ const char *data;
+
+ if (OBJ_obj2nid(obj) == NID_id_it_certProfile) {
+ if (!OSSL_CMP_ITAV_get0_certProfile(itav, &strs))
+ return NULL;
+ if (sk_ASN1_UTF8STRING_num(strs) < 1) {
+ ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_CERTPROFILE);
+ return NULL;
+ }
+ str = sk_ASN1_UTF8STRING_value(strs, 0);
+ if (str == NULL
+ || (data =
+ (const char *)ASN1_STRING_get0_data(str)) == NULL) {
+ ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT);
+ return NULL;
+ }
+ if (strcmp(data, "profile1") != 0) {
+ ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_CERTPROFILE);
+ return NULL;
+ }
+ break;
+ }
+ }
+ }
+
/* accept cert update request only for the reference cert, if given */
if (bodytype == OSSL_CMP_KUR
&& crm != NULL /* thus not p10cr */ && ctx->refCert != NULL) {
diff --git a/crypto/cmp/cmp_asn.c b/crypto/cmp/cmp_asn.c
index 0133dc5f80..3049d4f080 100644
--- a/crypto/cmp/cmp_asn.c
+++ b/crypto/cmp/cmp_asn.c
@@ -58,11 +58,7 @@ IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_CAKEYUPDANNCONTENT)
ASN1_SEQUENCE(OSSL_CMP_ERRORMSGCONTENT) = {
ASN1_SIMPLE(OSSL_CMP_ERRORMSGCONTENT, pKIStatusInfo, OSSL_CMP_PKISI),
ASN1_OPT(OSSL_CMP_ERRORMSGCONTENT, errorCode, ASN1_INTEGER),
- /*
- * OSSL_CMP_PKIFREETEXT is effectively a sequence of ASN1_UTF8STRING
- * so it is used directly
- *
- */
+ /* OSSL_CMP_PKIFREETEXT is a ASN1_UTF8STRING sequence, so used directly */
ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ERRORMSGCONTENT, errorDetails,
ASN1_UTF8STRING)
} ASN1_SEQUENCE_END(OSSL_CMP_ERRORMSGCONTENT)
@@ -121,6 +117,9 @@ ASN1_ADB(OSSL_CMP_ITAV) = {
ADB_ENTRY(NID_id_it_rootCaKeyUpdate,
ASN1_OPT(OSSL_CMP_ITAV, infoValue.rootCaKeyUpdate,
OSSL_CMP_ROOTCAKEYUPDATE)),
+ ADB_ENTRY(NID_id_it_certProfile,
+ ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ITAV, infoValue.certProfile,
+ ASN1_UTF8STRING)),
} ASN1_ADB_END(OSSL_CMP_ITAV, 0, infoType, 0,
&infotypeandvalue_default_tt, NULL);
@@ -190,13 +189,40 @@ int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **itav_sk_p,
return 1;
err:
- if (created != 0) {
+ if (created) {
sk_OSSL_CMP_ITAV_free(*itav_sk_p);
*itav_sk_p = NULL;
}
return 0;
}
+OSSL_CMP_ITAV
+*OSSL_CMP_ITAV_new0_certProfile(STACK_OF(ASN1_UTF8STRING) *certProfile)
+{
+ OSSL_CMP_ITAV *itav;
+
+ if ((itav = OSSL_CMP_ITAV_new()) == NULL)
+ return NULL;
+ itav->infoType = OBJ_nid2obj(NID_id_it_certProfile);
+ itav->infoValue.certProfile = certProfile;
+ return itav;
+}
+
+int OSSL_CMP_ITAV_get0_certProfile(const OSSL_CMP_ITAV *itav,
+ STACK_OF(ASN1_UTF8STRING) **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_certProfile) {
+ ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT);
+ return 0;
+ }
+ *out = itav->infoValue.certProfile;
+ return 1;
+}
+
OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_caCerts(const STACK_OF(X509) *caCerts)
{
OSSL_CMP_ITAV *itav = OSSL_CMP_ITAV_new();
@@ -327,7 +353,7 @@ int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a)
}
static int ossl_cmp_msg_cb(int operation, ASN1_VALUE **pval,
- const ASN1_ITEM *it, void *exarg)
+ ossl_unused const ASN1_ITEM *it, void *exarg)
{
OSSL_CMP_MSG *msg = (OSSL_CMP_MSG *)*pval;
@@ -417,14 +443,9 @@ ASN1_ITEM_TEMPLATE_END(OSSL_CMP_PKISTATUS)
ASN1_SEQUENCE(OSSL_CMP_PKISI) = {
ASN1_SIMPLE(OSSL_CMP_PKISI, status, OSSL_CMP_PKISTATUS),
- /*
- * CMP_PKIFREETEXT is effectively a sequence of ASN1_UTF8STRING
- * so it is used directly
- */
+ /* OSSL_CMP_PKIFREETEXT is a ASN1_UTF8STRING sequence, so used directly */
ASN1_SEQUENCE_OF_OPT(OSSL_CMP_PKISI, statusString, ASN1_UTF8STRING),
- /*
- * OSSL_CMP_PKIFAILUREINFO is effectively ASN1_BIT_STRING so used directly
- */
+ /* OSSL_CMP_PKIFAILUREINFO is effectively ASN1_BIT_STRING, used directly */
ASN1_OPT(OSSL_CMP_PKISI, failInfo, ASN1_BIT_STRING)
} ASN1_SEQUENCE_END(OSSL_CMP_PKISI)
IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_PKISI)
@@ -541,10 +562,7 @@ ASN1_SEQUENCE(OSSL_CMP_PKIHEADER) = {
ASN1_EXP_OPT(OSSL_CMP_PKIHEADER, transactionID, ASN1_OCTET_STRING, 4),
ASN1_EXP_OPT(OSSL_CMP_PKIHEADER, senderNonce, ASN1_OCTET_STRING, 5),
ASN1_EXP_OPT(OSSL_CMP_PKIHEADER, recipNonce, ASN1_OCTET_STRING, 6),
- /*
- * OSSL_CMP_PKIFREETEXT is effectively a sequence of ASN1_UTF8STRING
- * so it is used directly
- */
+ /* OSSL_CMP_PKIFREETEXT is a ASN1_UTF8STRING sequence, so used directly */
ASN1_EXP_SEQUENCE_OF_OPT(OSSL_CMP_PKIHEADER, freeText, ASN1_UTF8STRING, 7),
ASN1_EXP_SEQUENCE_OF_OPT(OSSL_CMP_PKIHEADER, generalInfo,
OSSL_CMP_ITAV, 8)
diff --git a/crypto/cmp/cmp_ctx.c b/crypto/cmp/cmp_ctx.c
index 947d2ceb8f..5e542200e9 100644
--- a/crypto/cmp/cmp_ctx.c
+++ b/crypto/cmp/cmp_ctx.c
@@ -534,6 +534,8 @@ int OSSL_CMP_CTX_reset_geninfo_ITAVs(OSSL_CMP_CTX *ctx)
return 1;
}
+DEFINE_OSSL_CMP_CTX_get0(geninfo_ITAVs, STACK_OF(OSSL_CMP_ITAV))
+
/* Add an itav for the body of outgoing general messages */
int OSSL_CMP_CTX_push0_genm_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav)
{
diff --git a/crypto/cmp/cmp_err.c b/crypto/cmp/cmp_err.c
index 3853e52605..c4d5c97f9e 100644
--- a/crypto/cmp/cmp_err.c
+++ b/crypto/cmp/cmp_err.c
@@ -144,6 +144,8 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
"transactionid unmatched"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_TRANSFER_ERROR), "transfer error"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNCLEAN_CTX), "unclean ctx"},
+ {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_CERTPROFILE),
+ "unexpected certprofile"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKIBODY), "unexpected pkibody"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKISTATUS),
"unexpected pkistatus"},
diff --git a/crypto/cmp/cmp_hdr.c b/crypto/cmp/cmp_hdr.c
index 5fabf1aa33..4358b38873 100644
--- a/crypto/cmp/cmp_hdr.c
+++ b/crypto/cmp/cmp_hdr.c
@@ -72,6 +72,16 @@ ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr)
return hdr->recipNonce;
}
+STACK_OF(OSSL_CMP_ITAV)
+ *OSSL_CMP_HDR_get0_geninfo_ITAVs(const OSSL_CMP_PKIHEADER *hdr)
+{
+ if (hdr == NULL) {
+ ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
+ return NULL;
+ }
+ return hdr->generalInfo;
+}
+
/* a NULL-DN as an empty sequence of RDNs */
int ossl_cmp_general_name_is_NULL_DN(GENERAL_NAME *name)
{
diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h
index 29aa84cd2a..b8da48ac43 100644
--- a/crypto/cmp/cmp_local.h
+++ b/crypto/cmp/cmp_local.h
@@ -254,6 +254,8 @@ struct ossl_cmp_itav_st {
OSSL_CMP_MSGS *origPKIMessage;
/* NID_id_it_suppLangTags - Supported Language Tags */
STACK_OF(ASN1_UTF8STRING) *suppLangTagsValue;
+ /* NID_id_it_certProfile - Certificate Profile */
+ STACK_OF(ASN1_UTF8STRING) *certProfile;
/* NID_id_it_caCerts - CA Certificates */
STACK_OF(X509) *caCerts;
/* NID_id_it_rootCaCert - Root CA Certificate */
diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt
index 5f60bd52d2..8e6d9ddcae 100644
--- a/crypto/err/openssl.txt
+++ b/crypto/err/openssl.txt
@@ -272,6 +272,7 @@ CMP_R_TOTAL_TIMEOUT:184:total timeout
CMP_R_TRANSACTIONID_UNMATCHED:152:transactionid unmatched
CMP_R_TRANSFER_ERROR:159:transfer error
CMP_R_UNCLEAN_CTX:191:unclean ctx
+CMP_R_UNEXPECTED_CERTPROFILE:196:unexpected certprofile
CMP_R_UNEXPECTED_PKIBODY:133:unexpected pkibody
CMP_R_UNEXPECTED_PKISTATUS:185:unexpected pkistatus
CMP_R_UNEXPECTED_PVNO:153:unexpected pvno
diff --git a/doc/man1/openssl-cmp.pod.in b/doc/man1/openssl-cmp.pod.in
index 051c749d08..ee54697c9c 100644
--- a/doc/man1/openssl-cmp.pod.in
+++ b/doc/man1/openssl-cmp.pod.in
@@ -17,6 +17,7 @@ Generic message options:
[B<-cmd> I<ir|cr|kur|p10cr|rr|genm>]
[B<-infotype> I<name>]
+[B<-profile> I<name>]
[B<-geninfo> I<OID:int:N>]
Certificate enrollment options:
@@ -246,6 +247,11 @@ 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> and C<rootCaCert>.
+=item B<-profile> I<name>
+
+Name of a certificate profile to place in
+the PKIHeader generalInfo field of request messages.
+
=item B<-geninfo> I<OID:int:N>
generalInfo integer values to place in request PKIHeader with given OID,
@@ -1390,7 +1396,9 @@ L<openssl-req(1)>, L<openssl-x509(1)>, L<x509v3_config(5)>
The B<cmp> application was added in OpenSSL 3.0.
-The B<-engine option> was deprecated in OpenSSL 3.0.
+The B<-engine> option was deprecated in OpenSSL 3.0.
+
+The B<-profile> option was added in OpenSSL 3.3.
=head1 COPYRIGHT
diff --git a/doc/man3/OSSL_CMP_CTX_new.pod b/doc/man3/OSSL_CMP_CTX_new.pod
index 8109970171..d038f2f61c 100644
--- a/doc/man3/OSSL_CMP_CTX_new.pod
+++ b/doc/man3/OSSL_CMP_CTX_new.pod
@@ -39,6 +39,7 @@ OSSL_CMP_CTX_set1_secretValue,
OSSL_CMP_CTX_set1_recipient,
OSSL_CMP_CTX_push0_geninfo_ITAV,
OSSL_CMP_CTX_reset_geninfo_ITAVs,
+OSSL_CMP_CTX_get0_geninfo_ITAVs,
OSSL_CMP_CTX_set1_extraCertsOut,
OSSL_CMP_CTX_set0_newPkey,
OSSL_CMP_CTX_get0_newPkey,
@@ -127,6 +128,8 @@ OSSL_CMP_CTX_set1_senderNonce
int OSSL_CMP_CTX_set1_recipient(OSSL_CMP_CTX *ctx, const X509_NAME *name);
int OSSL_CMP_CTX_push0_geninfo_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav);
int OSSL_CMP_CTX_reset_geninfo_ITAVs(OSSL_CMP_CTX *ctx);
+ STACK_OF(OSSL_CMP_ITAV)
+ *OSSL_CMP_CTX_get0_geninfo_ITAVs(const OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_set1_extraCertsOut(OSSL_CMP_CTX *ctx,
STACK_OF(X509) *extraCertsOut);
@@ -540,12 +543,16 @@ the issuer of the CMP signer certificate,
as far as any of those is present, else the NULL-DN as last resort.
OSSL_CMP_CTX_push0_geninfo_ITAV() adds I<itav> to the stack in the I<ctx> to be
-added to the GeneralInfo field of the CMP PKIMessage header of a request
+added to the generalInfo field of the CMP PKIMessage header of a request
message sent with this context.
OSSL_CMP_CTX_reset_geninfo_ITAVs()
clears any ITAVs that were added by OSSL_CMP_CTX_push0_geninfo_ITAV().
+OSSL_CMP_CTX_get0_geninfo_ITAVs() returns the list of ITAVs set in I<ctx>
+for inclusion in the generalInfo field of the CMP PKIMessage header of requests
+or NULL if not set.
+
OSSL_CMP_CTX_set1_extraCertsOut() sets the stack of extraCerts that will be
sent to remote.
@@ -737,6 +744,7 @@ OSSL_CMP_CTX_get_http_cb_arg(),
OSSL_CMP_CTX_get_transfer_cb_arg(),
OSSL_CMP_CTX_get0_trusted(),
OSSL_CMP_CTX_get0_untrusted(),
+OSSL_CMP_CTX_get0_geninfo_ITAVs(),
OSSL_CMP_CTX_get0_newPkey(),
OSSL_CMP_CTX_get_certConf_cb_arg(),
OSSL_CMP_CTX_get0_statusString(),
@@ -841,10 +849,11 @@ in OpenSSL 3.2.
OSSL_CMP_CTX_reset_geninfo_ITAVs() was added in OpenSSL 3.0.8.
+OSSL_CMP_CTX_set1_serialNumber(),
OSSL_CMP_CTX_get0_libctx(), OSSL_CMP_CTX_get0_propq(), and
OSSL_CMP_CTX_get0_validatedSrvCert() were added in OpenSSL 3.2.
-OSSL_CMP_CTX_set1_serialNumber() was added in OpenSSL 3.2.
+OSSL_CMP_CTX_get0_geninfo_ITAVs() was added in OpenSSL 3.3.
=head1 COPYRIGHT
diff --git a/doc/man3/OSSL_CMP_HDR_get0_transactionID.pod b/doc/man3/OSSL_CMP_HDR_get0_transactionID.pod
index 36bdf1917f..6e79e9a0e3 100644
--- a/doc/man3/OSSL_CMP_HDR_get0_transactionID.pod
+++ b/doc/man3/OSSL_CMP_HDR_get0_transactionID.pod
@@ -3,7 +3,8 @@
=head1 NAME
OSSL_CMP_HDR_get0_transactionID,
-OSSL_CMP_HDR_get0_recipNonce
+OSSL_CMP_HDR_get0_recipNonce,
+OSSL_CMP_HDR_get0_geninfo_ITAVs
- functions manipulating CMP message headers
=head1 SYNOPSIS
@@ -14,6 +15,8 @@ OSSL_CMP_HDR_get0_recipNonce
OSSL_CMP_PKIHEADER *hdr);
ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const
OSSL_CMP_PKIHEADER *hdr);
+ STACK_OF(OSSL_CMP_ITAV)
+ *OSSL_CMP_HDR_get0_geninfo_ITAVs(const OSSL_CMP_PKIHEADER *hdr);
=head1 DESCRIPTION
@@ -22,6 +25,9 @@ PKIHeader.
OSSL_CMP_HDR_get0_recipNonce returns the recipient nonce of the given PKIHeader.
+OSSL_CMP_HDR_get0_geninfo_ITAVs() returns the list of ITAVs
+in the generalInfo field of the given PKIHeader.
+
=head1 NOTES
CMP is defined in RFC 4210.
@@ -35,6 +41,8 @@ or NULL if the respective entry does not exist and on error.
The OpenSSL CMP support was added in OpenSSL 3.0.
+OSSL_CMP_HDR_get0_geninfo_ITAVs() was added in OpenSSL 3.3.
+
=head1 COPYRIGHT
Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man3/OSSL_CMP_ITAV_set0.pod b/doc/man3/OSSL_CMP_ITAV_set0.pod
index 5dd9bcb266..13d7868a6d 100644
--- a/doc/man3/OSSL_CMP_ITAV_set0.pod
+++ b/doc/man3/OSSL_CMP_ITAV_set0.pod
@@ -6,7 +6,9 @@ OSSL_CMP_ITAV_create,
OSSL_CMP_ITAV_set0,
OSSL_CMP_ITAV_get0_type,
OSSL_CMP_ITAV_get0_value,
-OSSL_CMP_ITAV_push0_stack_item
+OSSL_CMP_ITAV_push0_stack_item,
+OSSL_CMP_ITAV_new0_certProfile,
+OSSL_CMP_ITAV_get0_certProfile
- OSSL_CMP_ITAV utility functions
=head1 SYNOPSIS
@@ -20,6 +22,10 @@ OSSL_CMP_ITAV_push0_stack_item
ASN1_TYPE *OSSL_CMP_ITAV_get0_value(const OSSL_CMP_ITAV *itav);
int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **itav_sk_p,
OSSL_CMP_ITAV *itav);
+ OSSL_CMP_ITAV
+ *OSSL_CMP_ITAV_new0_certProfile(STACK_OF(ASN1_UTF8STRING) *certProfile);
+ int OSSL_CMP_ITAV_get0_certProfile(const OSSL_CMP_ITAV *itav,
+ STACK_OF(ASN1_UTF8STRING) **out);
=head1 DESCRIPTION
@@ -43,21 +49,37 @@ the I<itav> as generic B<ASN1_TYPE> pointer.
OSSL_CMP_ITAV_push0_stack_item() pushes I<itav> to the stack pointed to
by I<*itav_sk_p>. It creates a new stack if I<*itav_sk_p> points to NULL.
+OSSL_CMP_ITAV_new0_certProfile() creates a new B<OSSL_CMP_ITAV> structure
+of type B<certProfile> that includes the optionally given list of profile names.
+On success, ownership of the list is with the new B<OSSL_CMP_ITAV> structure.
+
+OSSL_CMP_ITAV_get0_certProfile() on success assigns to I<*out>
+an internal pointer to the
+list of certificate profile names contained in the infoValue field of I<itav>.
+The pointer may be NULL if no profile name is included.
+It is an error if the infoType of I<itav> is not B<certProfile>.
+
=head1 NOTES
-CMP is defined in RFC 4210 (and CRMF in RFC 4211).
+CMP is defined in RFC 4210 and RFC 9480 (and CRMF in RFC 4211).
+
+OIDs to use as types in B<OSSL_CMP_ITAV> can be found at
+L<https://datatracker.ietf.org/doc/html/rfc9480#section-4.2.2>.
+The respective OpenSSL NIDs, such as B<NID_id_it_certProfile>,
+are defined in the F<< <openssl/obj_mac.h> >> header file.
=head1 RETURN VALUES
-OSSL_CMP_ITAV_create() returns a pointer to the ITAV structure on success,
-or NULL on error.
+OSSL_CMP_ITAV_create() and OSSL_CMP_ITAV_new0_certProfile()
+return a pointer to an ITAV structure on success, or NULL on error.
OSSL_CMP_ITAV_set0() does not return a value.
OSSL_CMP_ITAV_get0_type() and OSSL_CMP_ITAV_get0_value()
return the respective pointer or NULL if their input is NULL.
-OSSL_CMP_ITAV_push0_stack_item() returns 1 on success, 0 on error.
+OSSL_CMP_ITAV_push0_stack_item() and OSSL_CMP_ITAV_get0_certProfile()
+return 1 on success, 0 on error.
=head1 EXAMPLES
@@ -96,6 +118,9 @@ L<OSSL_CMP_CTX_new(3)>, L<OSSL_CMP_CTX_free(3)>, L<ASN1_TYPE_set(3)>
The OpenSSL CMP support was added in OpenSSL 3.0.
+OSSL_CMP_ITAV_new0_certProfile() and OSSL_CMP_ITAV_get0_certProfile()
+were added in OpenSSL 3.3.
+
=head1 COPYRIGHT
Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/include/openssl/cmp.h.in b/include/openssl/cmp.h.in
index 5bd8beb57a..fa4fe000ba 100644
--- a/include/openssl/cmp.h.in
+++ b/include/openssl/cmp.h.in
@@ -261,6 +261,10 @@ int OSSL_CMP_ITAV_push0_stack_item(STACK_OF(OSSL_CMP_ITAV) **itav_sk_p,
OSSL_CMP_ITAV *itav);
void OSSL_CMP_ITAV_free(OSSL_CMP_ITAV *itav);
+OSSL_CMP_ITAV *OSSL_CMP_ITAV_new0_certProfile(STACK_OF(ASN1_UTF8STRING)
+ *certProfile);
+int OSSL_CMP_ITAV_get0_certProfile(const OSSL_CMP_ITAV *itav,
+ STACK_OF(ASN1_UTF8STRING) **out);
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);
@@ -351,6 +355,8 @@ int OSSL_CMP_CTX_set1_secretValue(OSSL_CMP_CTX *ctx,
int OSSL_CMP_CTX_set1_recipient(OSSL_CMP_CTX *ctx, const X509_NAME *name);
int OSSL_CMP_CTX_push0_geninfo_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav);
int OSSL_CMP_CTX_reset_geninfo_ITAVs(OSSL_CMP_CTX *ctx);
+STACK_OF(OSSL_CMP_ITAV)
+ *OSSL_CMP_CTX_get0_geninfo_ITAVs(const OSSL_CMP_CTX *ctx);
int OSSL_CMP_CTX_set1_extraCertsOut(OSSL_CMP_CTX *ctx,
STACK_OF(X509) *extraCertsOut);
/* certificate template: */
@@ -403,6 +409,8 @@ OSSL_CMP_STATUSINFO_new(int status, int fail_info, const char *text);
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);
+STACK_OF(OSSL_CMP_ITAV)
+ *OSSL_CMP_HDR_get0_geninfo_ITAVs(const OSSL_CMP_PKIHEADER *hdr);
/* from cmp_msg.c */
OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg);
diff --git a/include/openssl/cmperr.h b/include/openssl/cmperr.h
index 57a6effbe3..dec9e0be45 100644
--- a/include/openssl/cmperr.h
+++ b/include/openssl/cmperr.h
@@ -98,6 +98,7 @@
# define CMP_R_TRANSACTIONID_UNMATCHED 152
# define CMP_R_TRANSFER_ERROR 159
# define CMP_R_UNCLEAN_CTX 191
+# define CMP_R_UNEXPECTED_CERTPROFILE 196
# define CMP_R_UNEXPECTED_PKIBODY 133
# define CMP_R_UNEXPECTED_PKISTATUS 185
# define CMP_R_UNEXPECTED_PVNO 153
diff --git a/test/recipes/80-test_cmp_http_data/test_commands.csv b/test/recipes/80-test_cmp_http_data/test_commands.csv
index 5ab2ca3fd7..869bab7c99 100644
--- a/test/recipes/80-test_cmp_http_data/test_commands.csv
+++ b/test/recipes/80-test_cmp_http_data/test_commands.csv
@@ -77,6 +77,11 @@ expected,description, -section,val, -cmd,val,val2, -cacertsout,val,val2, -infoty
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,profile, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,profile1,BLANK,,BLANK,
+0,profile wrong value, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,profile2,BLANK,,BLANK,
+0,profile missing argument, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,,,,,
+0,profile extra argument, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,profile1,profile2,,,
+,,,,,,,,,,,,,,,,,,,
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,,,,,
0,geninfo bad syntax: leading '.', -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -geninfo,.1.2.3:int:987,BLANK,,BLANK,
diff --git a/util/libcrypto.num b/util/libcrypto.num
index c9941a383b..60f320c33a 100644
--- a/util/libcrypto.num
+++ b/util/libcrypto.num
@@ -5536,4 +5536,8 @@ X509_STORE_CTX_set_get_crl 5663 3_2_0 EXIST::FUNCTION:
X509_STORE_CTX_set_current_reasons 5664 3_2_0 EXIST::FUNCTION:
OSSL_STORE_delete 5665 3_2_0 EXIST::FUNCTION:
BIO_ADDR_copy 5666 3_2_0 EXIST::FUNCTION:SOCK
+OSSL_CMP_CTX_get0_geninfo_ITAVs ? 3_3_0 EXIST::FUNCTION:CMP
+OSSL_CMP_HDR_get0_geninfo_ITAVs ? 3_3_0 EXIST::FUNCTION:CMP
+OSSL_CMP_ITAV_new0_certProfile ? 3_3_0 EXIST::FUNCTION:CMP
+OSSL_CMP_ITAV_get0_certProfile ? 3_3_0 EXIST::FUNCTION:CMP
EVP_DigestSqueeze ? 3_3_0 EXIST::FUNCTION: