diff --git a/apps/cmp.c b/apps/cmp.c index 6f2fea4f55..fd350563f0 100644 --- a/apps/cmp.c +++ b/apps/cmp.c @@ -87,6 +87,9 @@ static char *opt_srvcert = NULL; static char *opt_expect_sender = NULL; static int opt_ignore_keyusage = 0; static int opt_unprotected_errors = 0; +#ifdef OPENSSL_CMP_APP_ALLOW_UNSAFE +static int opt_ta_in_ip_extracerts = 0; +#endif static int opt_no_cache_extracerts = 0; static char *opt_srvcertout = NULL; static char *opt_extracertsout = NULL; @@ -253,7 +256,11 @@ typedef enum OPTION_choice { OPT_TRUSTED, OPT_UNTRUSTED, OPT_SRVCERT, OPT_EXPECT_SENDER, - OPT_IGNORE_KEYUSAGE, OPT_UNPROTECTED_ERRORS, OPT_NO_CACHE_EXTRACERTS, + OPT_IGNORE_KEYUSAGE, OPT_UNPROTECTED_ERRORS, +#ifdef OPENSSL_CMP_APP_ALLOW_UNSAFE + OPT_TA_IN_IP_EXTRACERTS, +#endif + OPT_NO_CACHE_EXTRACERTS, OPT_SRVCERTOUT, OPT_EXTRACERTSOUT, OPT_CACERTSOUT, OPT_OLDWITHOLD, OPT_NEWWITHNEW, OPT_NEWWITHOLD, OPT_OLDWITHNEW, OPT_CRLCERT, OPT_OLDCRL, OPT_CRLOUT, @@ -441,6 +448,14 @@ const OPTIONS cmp_options[] = { "certificate responses (ip/cp/kup), revocation responses (rp), and PKIConf"}, {OPT_MORE_STR, 0, 0, "WARNING: This setting leads to behavior allowing violation of RFC 4210"}, +#ifdef OPENSSL_CMP_APP_ALLOW_UNSAFE + {"ta_in_ip_extracerts", OPT_TA_IN_IP_EXTRACERTS, '-', + "Permit using self-issued certificates from the extraCerts in an IP message"}, + {OPT_MORE_STR, 0, 0, + "as trust anchors under conditions defined by 3GPP TS 33.310"}, + {OPT_MORE_STR, 0, 0, + "WARNING: This setting leads to behavior allowing violation of RFC 9810"}, +#endif {"no_cache_extracerts", OPT_NO_CACHE_EXTRACERTS, '-', "Do not keep certificates received in the extraCerts CMP message field"}, { "srvcertout", OPT_SRVCERTOUT, 's', @@ -666,6 +681,9 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */ {&opt_trusted}, {&opt_untrusted}, {&opt_srvcert}, {&opt_expect_sender}, {(char **)&opt_ignore_keyusage}, {(char **)&opt_unprotected_errors}, +#ifdef OPENSSL_CMP_APP_ALLOW_UNSAFE + {(char **)&opt_ta_in_ip_extracerts}, +#endif {(char **)&opt_no_cache_extracerts}, {&opt_srvcertout}, {&opt_extracertsout}, {&opt_cacertsout}, {&opt_oldwithold}, {&opt_newwithnew}, {&opt_newwithold}, {&opt_oldwithnew}, @@ -1340,6 +1358,10 @@ static int setup_verification_ctx(OSSL_CMP_CTX *ctx) if (opt_unprotected_errors) (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_UNPROTECTED_ERRORS, 1); +#ifdef OPENSSL_CMP_APP_ALLOW_UNSAFE + if (opt_ta_in_ip_extracerts) + (void)OSSL_CMP_CTX_set_option(ctx, OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR, 1); +#endif if (opt_out_trusted != NULL) { /* for use in OSSL_CMP_certConf_cb() */ X509_VERIFY_PARAM *out_vpm = NULL; @@ -2921,6 +2943,11 @@ static int get_opts(int argc, char **argv) case OPT_UNPROTECTED_ERRORS: opt_unprotected_errors = 1; break; +#ifdef OPENSSL_CMP_APP_ALLOW_UNSAFE + case OPT_TA_IN_IP_EXTRACERTS: + opt_ta_in_ip_extracerts = 1; + break; +#endif case OPT_NO_CACHE_EXTRACERTS: opt_no_cache_extracerts = 1; break; diff --git a/crypto/cmp/cmp_vfy.c b/crypto/cmp/cmp_vfy.c index c4890f514b..1d6d55af65 100644 --- a/crypto/cmp/cmp_vfy.c +++ b/crypto/cmp/cmp_vfy.c @@ -311,21 +311,31 @@ static int check_cert_path(const OSSL_CMP_CTX *ctx, X509_STORE *store, /* * Exceptional handling for 3GPP TS 33.310 [3G/LTE Network Domain Security * (NDS); Authentication Framework (AF)], only to use for IP messages - * and if the ctx option is explicitly set: use self-issued certificates - * from extraCerts as trust anchor to validate sender cert - - * provided it also can validate the newly enrolled certificate + * and if the ctx option is explicitly set: use self-issued certificates from + * extraCerts as trust anchors when validating the CMP message protection cert + * in this and any subsequent responses from the server in the same transaction, + * but only if these extraCerts can also be used as trust anchors for validating + * the newly enrolled certificate received in the IP message. */ static int check_cert_path_3gpp(const OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, X509 *scrt) { int valid = 0; X509_STORE *store; + STACK_OF(X509) *extraCerts; if (!ctx->permitTAInExtraCertsForIR) return 0; + /* + * Initially, use extraCerts from the IP message. + * For subsequent msgs (pollRep or PKIConf) in the same transaction, + * use extraCertsIn remembered from earlier message (typically, the IP message). + * The extraCertsIn field will be cleared by OSSL_CMP_CTX_reinit(). + */ + extraCerts = ctx->extraCertsIn == NULL ? msg->extraCerts : ctx->extraCertsIn; if ((store = X509_STORE_new()) == NULL - || !ossl_cmp_X509_STORE_add1_certs(store, msg->extraCerts, + || !ossl_cmp_X509_STORE_add1_certs(store, extraCerts, 1 /* self-issued only */)) goto err; @@ -334,7 +344,7 @@ static int check_cert_path_3gpp(const OSSL_CMP_CTX *ctx, if (!valid) { ossl_cmp_warn(ctx, "also exceptional 3GPP mode cert path validation failed"); - } else { + } else if (OSSL_CMP_MSG_get_bodytype(msg) == OSSL_CMP_PKIBODY_IP) { /* * verify that the newly enrolled certificate (which assumed rid == * OSSL_CMP_CERTREQID) can also be validated with the same trusted store @@ -416,8 +426,7 @@ static int check_msg_all_certs(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, { int ret = 0; - if (ctx->permitTAInExtraCertsForIR - && OSSL_CMP_MSG_get_bodytype(msg) == OSSL_CMP_PKIBODY_IP) + if (ctx->permitTAInExtraCertsForIR) ossl_cmp_info(ctx, mode_3gpp ? "normal mode failed; trying now 3GPP mode trusting extraCerts" : "trying first normal mode using trust store"); @@ -544,10 +553,11 @@ static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) * (in this order) and is path is validated against ctx->trusted. * On success cache the found cert using ossl_cmp_ctx_set1_validatedSrvCert(). * - * If ctx->permitTAInExtraCertsForIR is true and when validating a CMP IP msg, - * the trust anchor for validating the IP msg may be taken from msg->extraCerts - * if a self-issued certificate is found there that can be used to - * validate the enrolled certificate returned in the IP. + * If ctx->permitTAInExtraCertsForIR is true, when validating a CMP IP message, + * trust anchors for validating the IP message (and any subsequent responses + * by the server in the same transaction) may be taken from msg->extraCerts + * if self-issued certificates are found there that can also be used + * to validate the newly enrolled certificate returned in the IP msg. * This is according to the need given in 3GPP TS 33.310. * * Returns 1 on success, 0 on error or validation failed. diff --git a/doc/man1/openssl-cmp.pod.in b/doc/man1/openssl-cmp.pod.in index 9d5af2f423..efcd2eaa1f 100644 --- a/doc/man1/openssl-cmp.pod.in +++ b/doc/man1/openssl-cmp.pod.in @@ -70,6 +70,7 @@ Server authentication options: [B<-expect_sender> I] [B<-ignore_keyusage>] [B<-unprotected_errors>] +[B<-ta_in_ip_extracerts>] [B<-no_cache_extracerts>] [B<-srvcertout> I] [B<-extracertsout> I] @@ -714,6 +715,23 @@ with a signature key." =back +=item B<-ta_in_ip_extracerts> + +This is a quirk option added to support 3GPP TS 33.310, +available only if OpenSSL has been built with B. +B This leads to behavior violating RFCs 4210 and 9810. + +It allows using self-issued certificates from the extraCerts in an IP message +as trust anchors when validating the CMP message protection certificate +in this and any subsequent responses from the server in the same transaction, +but only if these extraCerts can also be used as trust anchors for validating +the newly enrolled certificate received in the IP message. + +Note that using this option is dangerous as the to-be-trusted certificates +obtained this way have not been authenticated (at least not at CMP level). +Taking them over as initial trust anchors +implements a form of trust-on-first-use (TOFU). + =item B<-no_cache_extracerts> Do not cache certificates in the extraCerts field of CMP messages received. @@ -1529,6 +1547,8 @@ and B<-rsp_crl> options were added in OpenSSL 3.4. B<-centralkeygen>, B<-newkeyout>, B<-rsp_key> and B<-rsp_keypass> were added in OpenSSL 3.5. +The B<-ta_in_ip_extracerts> quirk option was added in OpenSSL 3.6. + =head1 COPYRIGHT Copyright 2007-2025 The OpenSSL Project Authors. All Rights Reserved. diff --git a/doc/man3/OSSL_CMP_CTX_new.pod b/doc/man3/OSSL_CMP_CTX_new.pod index ab7aaa453b..a529b7cd01 100644 --- a/doc/man3/OSSL_CMP_CTX_new.pod +++ b/doc/man3/OSSL_CMP_CTX_new.pod @@ -343,13 +343,18 @@ Else, 'digitalSignature' must be allowed by CMP signer certificates. =item B -Allow retrieving a trust anchor from extraCerts and using that -to validate the certificate chain of an IP message. This is a quirk option added to support 3GPP TS 33.310. +It leads to behavior violating RFCs 4210 and 9810. +It allows using self-issued certificates from the extraCerts in an IP message +as trust anchors when validating the CMP message protection certificate +in this and any subsequent responses from the server in the same transaction, +but only if these extraCerts can also be used as trust anchors for validating +the newly enrolled certificate received in the IP message. -Note that using this option is dangerous as the certificate obtained -this way has not been authenticated (at least not at CMP level). -Taking it over as a trust anchor implements trust-on-first-use (TOFU). +Note that using this option is dangerous as the to-be-trusted certificates +obtained this way have not been authenticated (at least not at CMP level). +Taking them over as initial trust anchors +implements a form of trust-on-first-use (TOFU). =item B