diff options
| author | Enji Cooper <ngie@FreeBSD.org> | 2025-05-07 21:18:24 +0000 |
|---|---|---|
| committer | Enji Cooper <ngie@FreeBSD.org> | 2025-05-07 22:37:22 +0000 |
| commit | 29536654cc41bf41b92dc836c47496dc6fe0b00c (patch) | |
| tree | 368a3c5b14e610bb5f6b71657f61a41e373eaf97 /crypto/cmp | |
| parent | 1c34280346af8284acdc0eae39496811d37df25d (diff) | |
Diffstat (limited to 'crypto/cmp')
| -rw-r--r-- | crypto/cmp/build.info | 11 | ||||
| -rw-r--r-- | crypto/cmp/cmp_asn.c | 695 | ||||
| -rw-r--r-- | crypto/cmp/cmp_client.c | 227 | ||||
| -rw-r--r-- | crypto/cmp/cmp_ctx.c | 475 | ||||
| -rw-r--r-- | crypto/cmp/cmp_err.c | 29 | ||||
| -rw-r--r-- | crypto/cmp/cmp_hdr.c | 50 | ||||
| -rw-r--r-- | crypto/cmp/cmp_http.c | 46 | ||||
| -rw-r--r-- | crypto/cmp/cmp_local.h | 112 | ||||
| -rw-r--r-- | crypto/cmp/cmp_msg.c | 269 | ||||
| -rw-r--r-- | crypto/cmp/cmp_protect.c | 115 | ||||
| -rw-r--r-- | crypto/cmp/cmp_server.c | 259 | ||||
| -rw-r--r-- | crypto/cmp/cmp_status.c | 10 | ||||
| -rw-r--r-- | crypto/cmp/cmp_util.c | 8 | ||||
| -rw-r--r-- | crypto/cmp/cmp_vfy.c | 268 |
14 files changed, 1797 insertions, 777 deletions
diff --git a/crypto/cmp/build.info b/crypto/cmp/build.info index a2a57c14ec10..907d78d25ffb 100644 --- a/crypto/cmp/build.info +++ b/crypto/cmp/build.info @@ -1,4 +1,11 @@ LIBS=../../libcrypto -SOURCE[../../libcrypto]= cmp_asn.c cmp_ctx.c cmp_err.c cmp_util.c \ +$OPENSSLSRC=\ + cmp_asn.c cmp_ctx.c cmp_err.c cmp_util.c \ cmp_status.c cmp_hdr.c cmp_protect.c cmp_msg.c cmp_vfy.c \ - cmp_server.c cmp_client.c cmp_http.c + cmp_server.c cmp_client.c cmp_genm.c + +IF[{- !$disabled{'http'} -}] + $OPENSSLSRC=$OPENSSLSRC cmp_http.c +ENDIF + +SOURCE[../../libcrypto]=$OPENSSLSRC diff --git a/crypto/cmp/cmp_asn.c b/crypto/cmp/cmp_asn.c index a8de73ad979b..a32632026743 100644 --- a/crypto/cmp/cmp_asn.c +++ b/crypto/cmp/cmp_asn.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2025 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -12,6 +12,7 @@ #include <openssl/asn1t.h> #include "cmp_local.h" +#include "internal/crmf.h" /* explicit #includes not strictly needed since implied by the above: */ #include <openssl/cmp.h> @@ -28,7 +29,6 @@ ASN1_SEQUENCE(OSSL_CMP_REVANNCONTENT) = { } ASN1_SEQUENCE_END(OSSL_CMP_REVANNCONTENT) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_REVANNCONTENT) - ASN1_SEQUENCE(OSSL_CMP_CHALLENGE) = { ASN1_OPT(OSSL_CMP_CHALLENGE, owf, X509_ALGOR), ASN1_SIMPLE(OSSL_CMP_CHALLENGE, witness, ASN1_OCTET_STRING), @@ -36,19 +36,16 @@ ASN1_SEQUENCE(OSSL_CMP_CHALLENGE) = { } ASN1_SEQUENCE_END(OSSL_CMP_CHALLENGE) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_CHALLENGE) - ASN1_ITEM_TEMPLATE(OSSL_CMP_POPODECKEYCHALLCONTENT) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, OSSL_CMP_POPODECKEYCHALLCONTENT, OSSL_CMP_CHALLENGE) ASN1_ITEM_TEMPLATE_END(OSSL_CMP_POPODECKEYCHALLCONTENT) - ASN1_ITEM_TEMPLATE(OSSL_CMP_POPODECKEYRESPCONTENT) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, OSSL_CMP_POPODECKEYRESPCONTENT, ASN1_INTEGER) ASN1_ITEM_TEMPLATE_END(OSSL_CMP_POPODECKEYRESPCONTENT) - ASN1_SEQUENCE(OSSL_CMP_CAKEYUPDANNCONTENT) = { /* OSSL_CMP_CMPCERTIFICATE is effectively X509 so it is used directly */ ASN1_SIMPLE(OSSL_CMP_CAKEYUPDANNCONTENT, oldWithNew, X509), @@ -59,15 +56,10 @@ ASN1_SEQUENCE(OSSL_CMP_CAKEYUPDANNCONTENT) = { } ASN1_SEQUENCE_END(OSSL_CMP_CAKEYUPDANNCONTENT) 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) @@ -119,10 +111,27 @@ ASN1_ADB(OSSL_CMP_ITAV) = { ADB_ENTRY(NID_id_it_suppLangTags, ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ITAV, infoValue.suppLangTagsValue, 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)), + ADB_ENTRY(NID_id_it_certReqTemplate, + ASN1_OPT(OSSL_CMP_ITAV, infoValue.certReqTemplate, + OSSL_CMP_CERTREQTEMPLATE)), + ADB_ENTRY(NID_id_it_certProfile, + ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ITAV, infoValue.certProfile, + ASN1_UTF8STRING)), + ADB_ENTRY(NID_id_it_crlStatusList, + ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ITAV, infoValue.crlStatusList, + OSSL_CMP_CRLSTATUS)), + ADB_ENTRY(NID_id_it_crls, + ASN1_SEQUENCE_OF_OPT(OSSL_CMP_ITAV, infoValue.crls, X509_CRL)) } ASN1_ADB_END(OSSL_CMP_ITAV, 0, infoType, 0, &infotypeandvalue_default_tt, NULL); - ASN1_SEQUENCE(OSSL_CMP_ITAV) = { ASN1_SIMPLE(OSSL_CMP_ITAV, infoType, ASN1_OBJECT), ASN1_ADB_OBJECT(OSSL_CMP_ITAV) @@ -130,6 +139,41 @@ 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) + +ASN1_ITEM_TEMPLATE(OSSL_CMP_ATAVS) = + ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, + OSSL_CMP_ATAVS, OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +ASN1_ITEM_TEMPLATE_END(OSSL_CMP_ATAVS) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_ATAVS) + +ASN1_SEQUENCE(OSSL_CMP_CERTREQTEMPLATE) = { + ASN1_SIMPLE(OSSL_CMP_CERTREQTEMPLATE, certTemplate, OSSL_CRMF_CERTTEMPLATE), + ASN1_SEQUENCE_OF_OPT(OSSL_CMP_CERTREQTEMPLATE, keySpec, + OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +} ASN1_SEQUENCE_END(OSSL_CMP_CERTREQTEMPLATE) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_CERTREQTEMPLATE) + +ASN1_CHOICE(OSSL_CMP_CRLSOURCE) = { + ASN1_EXP(OSSL_CMP_CRLSOURCE, value.dpn, DIST_POINT_NAME, 0), + ASN1_EXP(OSSL_CMP_CRLSOURCE, value.issuer, GENERAL_NAMES, 1), +} ASN1_CHOICE_END(OSSL_CMP_CRLSOURCE) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_CRLSOURCE) +#define OSSL_CMP_CRLSOURCE_DPN 0 +#define OSSL_CMP_CRLSOURCE_ISSUER 1 + +ASN1_SEQUENCE(OSSL_CMP_CRLSTATUS) = { + ASN1_SIMPLE(OSSL_CMP_CRLSTATUS, source, OSSL_CMP_CRLSOURCE), + ASN1_OPT(OSSL_CMP_CRLSTATUS, thisUpdate, ASN1_TIME) +} ASN1_SEQUENCE_END(OSSL_CMP_CRLSTATUS) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_CRLSTATUS) + OSSL_CMP_ITAV *OSSL_CMP_ITAV_create(ASN1_OBJECT *type, ASN1_TYPE *value) { OSSL_CMP_ITAV *itav; @@ -181,13 +225,609 @@ 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(); + + if (itav == NULL) + return NULL; + if (sk_X509_num(caCerts) > 0 + && (itav->infoValue.caCerts = + sk_X509_deep_copy(caCerts, X509_dup, X509_free)) == NULL) { + OSSL_CMP_ITAV_free(itav); + return NULL; + } + itav->infoType = OBJ_nid2obj(NID_id_it_caCerts); + return itav; +} + +int OSSL_CMP_ITAV_get0_caCerts(const OSSL_CMP_ITAV *itav, STACK_OF(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_caCerts) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + *out = sk_X509_num(itav->infoValue.caCerts) > 0 + ? itav->infoValue.caCerts : NULL; + 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 = NULL; + + if (newWithNew != NULL) { + upd = OSSL_CMP_ROOTCAKEYUPDATE_new(); + if (upd == NULL) + return NULL; + + if ((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 != NULL ? upd->newWithNew : NULL; + if (newWithOld != NULL) + *newWithOld = upd != NULL ? upd->newWithOld : NULL; + if (oldWithNew != NULL) + *oldWithNew = upd != NULL ? upd->oldWithNew : NULL; + return 1; +} + +OSSL_CMP_ITAV +*OSSL_CMP_ITAV_new0_certReqTemplate(OSSL_CRMF_CERTTEMPLATE *certTemplate, + OSSL_CMP_ATAVS *keySpec) +{ + OSSL_CMP_ITAV *itav; + OSSL_CMP_CERTREQTEMPLATE *tmpl; + + if (certTemplate == NULL && keySpec != NULL) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return NULL; + } + if ((itav = OSSL_CMP_ITAV_new()) == NULL) + return NULL; + itav->infoType = OBJ_nid2obj(NID_id_it_certReqTemplate); + if (certTemplate == NULL) + return itav; + + if ((tmpl = OSSL_CMP_CERTREQTEMPLATE_new()) == NULL) { + OSSL_CMP_ITAV_free(itav); + return NULL; + } + itav->infoValue.certReqTemplate = tmpl; + tmpl->certTemplate = certTemplate; + tmpl->keySpec = keySpec; + return itav; +} + +int OSSL_CMP_ITAV_get1_certReqTemplate(const OSSL_CMP_ITAV *itav, + OSSL_CRMF_CERTTEMPLATE **certTemplate, + OSSL_CMP_ATAVS **keySpec) +{ + OSSL_CMP_CERTREQTEMPLATE *tpl; + + if (itav == NULL || certTemplate == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + + *certTemplate = NULL; + if (keySpec != NULL) + *keySpec = NULL; + + if (OBJ_obj2nid(itav->infoType) != NID_id_it_certReqTemplate) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + tpl = itav->infoValue.certReqTemplate; + if (tpl == NULL) /* no requirements available */ + return 1; + + if ((*certTemplate = OSSL_CRMF_CERTTEMPLATE_dup(tpl->certTemplate)) == NULL) + return 0; + if (keySpec != NULL && tpl->keySpec != NULL) { + int i, n = sk_OSSL_CMP_ATAV_num(tpl->keySpec); + + *keySpec = sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_new_reserve(NULL, n); + if (*keySpec == NULL) + goto err; + for (i = 0; i < n; i++) { + OSSL_CMP_ATAV *atav = sk_OSSL_CMP_ATAV_value(tpl->keySpec, i); + ASN1_OBJECT *type = OSSL_CMP_ATAV_get0_type(atav /* may be NULL */); + int nid; + const char *name; + + if (type == NULL) { + ERR_raise_data(ERR_LIB_CMP, CMP_R_INVALID_KEYSPEC, + "keySpec with index %d in certReqTemplate does not exist", + i); + goto err; + } + nid = OBJ_obj2nid(type); + + if (nid != NID_id_regCtrl_algId + && nid != NID_id_regCtrl_rsaKeyLen) { + name = OBJ_nid2ln(nid); + if (name == NULL) + name = OBJ_nid2sn(nid); + if (name == NULL) + name = "<undef>"; + ERR_raise_data(ERR_LIB_CMP, CMP_R_INVALID_KEYSPEC, + "keySpec with index %d in certReqTemplate has invalid type %s", + i, name); + goto err; + } + OSSL_CMP_ATAV_push1(keySpec, atav); + } + } + return 1; + + err: + OSSL_CRMF_CERTTEMPLATE_free(*certTemplate); + *certTemplate = NULL; + sk_OSSL_CMP_ATAV_pop_free(*keySpec, OSSL_CMP_ATAV_free); + if (keySpec != NULL) + *keySpec = NULL; + return 0; +} + +OSSL_CMP_ATAV *OSSL_CMP_ATAV_create(ASN1_OBJECT *type, ASN1_TYPE *value) +{ + OSSL_CMP_ATAV *atav; + + if ((atav = OSSL_CRMF_ATTRIBUTETYPEANDVALUE_new()) == NULL) + return NULL; + OSSL_CMP_ATAV_set0(atav, type, value); + return atav; +} + +void OSSL_CMP_ATAV_set0(OSSL_CMP_ATAV *atav, ASN1_OBJECT *type, + ASN1_TYPE *value) +{ + atav->type = type; + atav->value.other = value; +} + +ASN1_OBJECT *OSSL_CMP_ATAV_get0_type(const OSSL_CMP_ATAV *atav) +{ + if (atav == NULL) + return NULL; + return atav->type; +} + +OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_algId(const X509_ALGOR *alg) +{ + X509_ALGOR *dup; + OSSL_CMP_ATAV *res; + + if (alg == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return NULL; + } + if ((dup = X509_ALGOR_dup(alg)) == NULL) + return NULL; + res = OSSL_CMP_ATAV_create(OBJ_nid2obj(NID_id_regCtrl_algId), + (ASN1_TYPE *)dup); + if (res == NULL) + X509_ALGOR_free(dup); + return res; +} + +X509_ALGOR *OSSL_CMP_ATAV_get0_algId(const OSSL_CMP_ATAV *atav) +{ + if (atav == NULL || OBJ_obj2nid(atav->type) != NID_id_regCtrl_algId) + return NULL; + return atav->value.algId; +} + +OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_rsaKeyLen(int len) +{ + ASN1_INTEGER *aint; + OSSL_CMP_ATAV *res = NULL; + + if (len <= 0) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return NULL; + } + if ((aint = ASN1_INTEGER_new()) == NULL) + return NULL; + if (!ASN1_INTEGER_set(aint, len) + || (res = OSSL_CMP_ATAV_create(OBJ_nid2obj(NID_id_regCtrl_rsaKeyLen), + (ASN1_TYPE *)aint)) == NULL) + ASN1_INTEGER_free(aint); + return res; +} + +int OSSL_CMP_ATAV_get_rsaKeyLen(const OSSL_CMP_ATAV *atav) +{ + int64_t val; + + if (atav == NULL || OBJ_obj2nid(atav->type) != NID_id_regCtrl_rsaKeyLen + || !ASN1_INTEGER_get_int64(&val, atav->value.rsaKeyLen)) + return -1; + if (val <= 0 || val > INT_MAX) + return -2; + return (int)val; +} + +ASN1_TYPE *OSSL_CMP_ATAV_get0_value(const OSSL_CMP_ATAV *atav) +{ + if (atav == NULL) + return NULL; + return atav->value.other; +} + +int OSSL_CMP_ATAV_push1(OSSL_CMP_ATAVS **sk_p, const OSSL_CMP_ATAV *atav) +{ + int created = 0; + OSSL_CMP_ATAV *dup; + + if (sk_p == NULL || atav == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + goto err; + } + + if (*sk_p == NULL) { + if ((*sk_p = sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_new_null()) == NULL) + goto err; + created = 1; + } + + if ((dup = OSSL_CRMF_ATTRIBUTETYPEANDVALUE_dup((OSSL_CRMF_ATTRIBUTETYPEANDVALUE *)atav)) == NULL) + goto err; + if (sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_push(*sk_p, dup)) + return 1; + OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free(dup); + + err: + if (created) { + sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free(*sk_p); + *sk_p = NULL; + } + return 0; +} + +OSSL_CMP_ITAV +*OSSL_CMP_ITAV_new0_crlStatusList(STACK_OF(OSSL_CMP_CRLSTATUS) *crlStatusList) +{ + OSSL_CMP_ITAV *itav; + + if ((itav = OSSL_CMP_ITAV_new()) == NULL) + return NULL; + itav->infoType = OBJ_nid2obj(NID_id_it_crlStatusList); + itav->infoValue.crlStatusList = crlStatusList; + return itav; +} + +int OSSL_CMP_ITAV_get0_crlStatusList(const OSSL_CMP_ITAV *itav, + STACK_OF(OSSL_CMP_CRLSTATUS) **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_crlStatusList) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + *out = itav->infoValue.crlStatusList; + return 1; +} + +OSSL_CMP_CRLSTATUS *OSSL_CMP_CRLSTATUS_new1(const DIST_POINT_NAME *dpn, + const GENERAL_NAMES *issuer, + const ASN1_TIME *thisUpdate) +{ + OSSL_CMP_CRLSOURCE *crlsource; + OSSL_CMP_CRLSTATUS *crlstatus; + + if (dpn == NULL && issuer == NULL) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_NULL_PARAMETER); + return NULL; + } + if (dpn != NULL && issuer != NULL) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return NULL; + } + + if ((crlstatus = OSSL_CMP_CRLSTATUS_new()) == NULL) + return NULL; + crlsource = crlstatus->source; + + if (dpn != NULL) { + crlsource->type = OSSL_CMP_CRLSOURCE_DPN; + if ((crlsource->value.dpn = DIST_POINT_NAME_dup(dpn)) == NULL) + goto err; + } else { + crlsource->type = OSSL_CMP_CRLSOURCE_ISSUER; + if ((crlsource->value.issuer = + sk_GENERAL_NAME_deep_copy(issuer, GENERAL_NAME_dup, + GENERAL_NAME_free)) == NULL) + goto err; + } + + if (thisUpdate != NULL + && (crlstatus->thisUpdate = ASN1_TIME_dup(thisUpdate)) == NULL) + goto err; + return crlstatus; + + err: + OSSL_CMP_CRLSTATUS_free(crlstatus); + return NULL; +} + +static GENERAL_NAMES *gennames_new(const X509_NAME *nm) +{ + GENERAL_NAMES *names; + GENERAL_NAME *name = NULL; + + if ((names = sk_GENERAL_NAME_new_reserve(NULL, 1)) == NULL) + return NULL; + if (!GENERAL_NAME_set1_X509_NAME(&name, nm)) { + sk_GENERAL_NAME_free(names); + return NULL; + } + (void)sk_GENERAL_NAME_push(names, name); /* cannot fail */ + return names; +} + +static int gennames_allowed(GENERAL_NAMES *names, int only_DN) +{ + if (names == NULL) + return 0; + if (!only_DN) + return 1; + return sk_GENERAL_NAME_num(names) == 1 + && sk_GENERAL_NAME_value(names, 0)->type == GEN_DIRNAME; +} + +OSSL_CMP_CRLSTATUS *OSSL_CMP_CRLSTATUS_create(const X509_CRL *crl, + const X509 *cert, int only_DN) +{ + STACK_OF(DIST_POINT) *crldps = NULL; + ISSUING_DIST_POINT *idp = NULL; + DIST_POINT_NAME *dpn = NULL; + AUTHORITY_KEYID *akid = NULL; + GENERAL_NAMES *issuers = NULL; + const GENERAL_NAMES *CRLissuer = NULL; + const ASN1_TIME *last = crl == NULL ? NULL : X509_CRL_get0_lastUpdate(crl); + OSSL_CMP_CRLSTATUS *status = NULL; + int i, NID_akid = NID_authority_key_identifier; + + /* + * Note: + * X509{,_CRL}_get_ext_d2i(..., NID, ..., NULL) return the 1st extension with + * given NID that is available, if any. If there are more, this is an error. + */ + if (cert != NULL) { + crldps = X509_get_ext_d2i(cert, NID_crl_distribution_points, NULL, NULL); + /* if available, take the first suitable element */ + for (i = 0; i < sk_DIST_POINT_num(crldps); i++) { + DIST_POINT *dp = sk_DIST_POINT_value(crldps, i); + + if (dp == NULL) + continue; + if ((dpn = dp->distpoint) != NULL) { + CRLissuer = NULL; + break; + } + if (gennames_allowed(dp->CRLissuer, only_DN) && CRLissuer == NULL) + /* don't break because any dp->distpoint in list is preferred */ + CRLissuer = dp->CRLissuer; + } + } else { + if (crl == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return NULL; + } + idp = X509_CRL_get_ext_d2i(crl, + NID_issuing_distribution_point, NULL, NULL); + if (idp != NULL && idp->distpoint != NULL) + dpn = idp->distpoint; + } + + if (dpn == NULL && CRLissuer == NULL) { + if (cert != NULL) { + akid = X509_get_ext_d2i(cert, NID_akid, NULL, NULL); + if (akid != NULL && gennames_allowed(akid->issuer, only_DN)) + CRLissuer = akid->issuer; + else + CRLissuer = issuers = gennames_new(X509_get_issuer_name(cert)); + } + if (CRLissuer == NULL && crl != NULL) { + akid = X509_CRL_get_ext_d2i(crl, NID_akid, NULL, NULL); + if (akid != NULL && gennames_allowed(akid->issuer, only_DN)) + CRLissuer = akid->issuer; + else + CRLissuer = issuers = gennames_new(X509_CRL_get_issuer(crl)); + } + if (CRLissuer == NULL) + goto end; + } + + status = OSSL_CMP_CRLSTATUS_new1(dpn, CRLissuer, last); + end: + sk_DIST_POINT_pop_free(crldps, DIST_POINT_free); + ISSUING_DIST_POINT_free(idp); + AUTHORITY_KEYID_free(akid); + sk_GENERAL_NAME_pop_free(issuers, GENERAL_NAME_free); + return status; +} + +int OSSL_CMP_CRLSTATUS_get0(const OSSL_CMP_CRLSTATUS *crlstatus, + DIST_POINT_NAME **dpn, GENERAL_NAMES **issuer, + ASN1_TIME **thisUpdate) +{ + OSSL_CMP_CRLSOURCE *crlsource; + + if (crlstatus == NULL || dpn == NULL || issuer == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + if ((crlsource = crlstatus->source) == NULL) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + + if (crlsource->type == OSSL_CMP_CRLSOURCE_DPN) { + *dpn = crlsource->value.dpn; + *issuer = NULL; + } else if (crlsource->type == OSSL_CMP_CRLSOURCE_ISSUER) { + *dpn = NULL; + *issuer = crlsource->value.issuer; + } else { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + if (thisUpdate != NULL) + *thisUpdate = crlstatus->thisUpdate; + return 1; +} + +OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_crls(const X509_CRL *crl) +{ + OSSL_CMP_ITAV *itav; + X509_CRL *crl_copy = NULL; + STACK_OF(X509_CRL) *crls = NULL; + + if ((itav = OSSL_CMP_ITAV_new()) == NULL) + return NULL; + + if (crl != NULL) { + if ((crls = sk_X509_CRL_new_reserve(NULL, 1)) == NULL + || (crl_copy = X509_CRL_dup(crl)) == NULL + || !sk_X509_CRL_push(crls, crl_copy)) + goto err; + crl_copy = NULL; /* ownership transferred to crls */ + } + + itav->infoType = OBJ_nid2obj(NID_id_it_crls); + itav->infoValue.crls = crls; + return itav; + + err: + OPENSSL_free(crl_copy); + sk_X509_CRL_free(crls); + OSSL_CMP_ITAV_free(itav); + return NULL; +} + +int OSSL_CMP_ITAV_get0_crls(const OSSL_CMP_ITAV *itav, STACK_OF(X509_CRL) **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_crls) { + ERR_raise(ERR_LIB_CMP, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + *out = itav->infoValue.crls; + return 1; +} + /* get ASN.1 encoded integer, return -2 on error; -1 is valid for certReqId */ int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a) { @@ -209,7 +849,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; @@ -251,35 +891,31 @@ ASN1_CHOICE(OSSL_CMP_CERTORENCCERT) = { /* OSSL_CMP_CMPCERTIFICATE is effectively X509 so it is used directly */ ASN1_EXP(OSSL_CMP_CERTORENCCERT, value.certificate, X509, 0), ASN1_EXP(OSSL_CMP_CERTORENCCERT, value.encryptedCert, - OSSL_CRMF_ENCRYPTEDVALUE, 1), + OSSL_CRMF_ENCRYPTEDKEY, 1), } ASN1_CHOICE_END(OSSL_CMP_CERTORENCCERT) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_CERTORENCCERT) - ASN1_SEQUENCE(OSSL_CMP_CERTIFIEDKEYPAIR) = { ASN1_SIMPLE(OSSL_CMP_CERTIFIEDKEYPAIR, certOrEncCert, OSSL_CMP_CERTORENCCERT), ASN1_EXP_OPT(OSSL_CMP_CERTIFIEDKEYPAIR, privateKey, - OSSL_CRMF_ENCRYPTEDVALUE, 0), + OSSL_CRMF_ENCRYPTEDKEY, 0), ASN1_EXP_OPT(OSSL_CMP_CERTIFIEDKEYPAIR, publicationInfo, OSSL_CRMF_PKIPUBLICATIONINFO, 1) } ASN1_SEQUENCE_END(OSSL_CMP_CERTIFIEDKEYPAIR) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_CERTIFIEDKEYPAIR) - ASN1_SEQUENCE(OSSL_CMP_REVDETAILS) = { ASN1_SIMPLE(OSSL_CMP_REVDETAILS, certDetails, OSSL_CRMF_CERTTEMPLATE), ASN1_OPT(OSSL_CMP_REVDETAILS, crlEntryDetails, X509_EXTENSIONS) } ASN1_SEQUENCE_END(OSSL_CMP_REVDETAILS) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_REVDETAILS) - ASN1_ITEM_TEMPLATE(OSSL_CMP_REVREQCONTENT) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_SEQUENCE_OF, 0, OSSL_CMP_REVREQCONTENT, OSSL_CMP_REVDETAILS) ASN1_ITEM_TEMPLATE_END(OSSL_CMP_REVREQCONTENT) - ASN1_SEQUENCE(OSSL_CMP_REVREPCONTENT) = { ASN1_SEQUENCE_OF(OSSL_CMP_REVREPCONTENT, status, OSSL_CMP_PKISI), ASN1_EXP_SEQUENCE_OF_OPT(OSSL_CMP_REVREPCONTENT, revCerts, OSSL_CRMF_CERTID, @@ -288,7 +924,6 @@ ASN1_SEQUENCE(OSSL_CMP_REVREPCONTENT) = { } ASN1_SEQUENCE_END(OSSL_CMP_REVREPCONTENT) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_REVREPCONTENT) - ASN1_SEQUENCE(OSSL_CMP_KEYRECREPCONTENT) = { ASN1_SIMPLE(OSSL_CMP_KEYRECREPCONTENT, status, OSSL_CMP_PKISI), ASN1_EXP_OPT(OSSL_CMP_KEYRECREPCONTENT, newSigCert, X509, 0), @@ -298,21 +933,15 @@ ASN1_SEQUENCE(OSSL_CMP_KEYRECREPCONTENT) = { } ASN1_SEQUENCE_END(OSSL_CMP_KEYRECREPCONTENT) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_KEYRECREPCONTENT) - ASN1_ITEM_TEMPLATE(OSSL_CMP_PKISTATUS) = ASN1_EX_TEMPLATE_TYPE(ASN1_TFLG_UNIVERSAL, 0, status, ASN1_INTEGER) 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) @@ -321,7 +950,8 @@ IMPLEMENT_ASN1_DUP_FUNCTION(OSSL_CMP_PKISI) ASN1_SEQUENCE(OSSL_CMP_CERTSTATUS) = { ASN1_SIMPLE(OSSL_CMP_CERTSTATUS, certHash, ASN1_OCTET_STRING), ASN1_SIMPLE(OSSL_CMP_CERTSTATUS, certReqId, ASN1_INTEGER), - ASN1_OPT(OSSL_CMP_CERTSTATUS, statusInfo, OSSL_CMP_PKISI) + ASN1_OPT(OSSL_CMP_CERTSTATUS, statusInfo, OSSL_CMP_PKISI), + ASN1_EXP_OPT(OSSL_CMP_CERTSTATUS, hashAlg, X509_ALGOR, 0) } ASN1_SEQUENCE_END(OSSL_CMP_CERTSTATUS) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_CERTSTATUS) @@ -428,10 +1058,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_client.c b/crypto/cmp/cmp_client.c index 4c8dbfdcd739..e129705e0e63 100644 --- a/crypto/cmp/cmp_client.c +++ b/crypto/cmp/cmp_client.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2025 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -11,7 +11,6 @@ #include "cmp_local.h" #include "internal/cryptlib.h" -#include "e_os.h" /* ossl_sleep() */ /* explicit #includes not strictly needed since implied by the above: */ #include <openssl/bio.h> @@ -32,7 +31,7 @@ static int unprotected_exception(const OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *rep, int invalid_protection, - int expected_type /* ignored here */) + ossl_unused int expected_type) { int rcvd_type = OSSL_CMP_MSG_get_bodytype(rep /* may be NULL */); const char *msg_type = NULL; @@ -117,6 +116,23 @@ static int save_statusInfo(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si) return 1; } +static int is_crep_with_waiting(const OSSL_CMP_MSG *resp, int rid) +{ + OSSL_CMP_CERTREPMESSAGE *crepmsg; + OSSL_CMP_CERTRESPONSE *crep; + int bt = OSSL_CMP_MSG_get_bodytype(resp); + + if (!IS_CREP(bt)) + return 0; + + crepmsg = resp->body->value.ip; /* same for cp and kup */ + crep = ossl_cmp_certrepmessage_get0_certresponse(crepmsg, rid); + + return (crep != NULL + && ossl_cmp_pkisi_get_status(crep->status) + == OSSL_CMP_PKISTATUS_waiting); +} + /*- * Perform the generic aspects of sending a request and receiving a response. * Returns 1 on success and provides the received PKIMESSAGE in *rep. @@ -138,8 +154,10 @@ static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req, int time_left; OSSL_CMP_transfer_cb_t transfer_cb = ctx->transfer_cb; +#ifndef OPENSSL_NO_HTTP if (transfer_cb == NULL) transfer_cb = OSSL_CMP_MSG_http_perform; +#endif *rep = NULL; if (ctx->total_timeout != 0 /* not waiting indefinitely */) { @@ -162,7 +180,8 @@ static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req, /* should print error queue since transfer_cb may call ERR_clear_error() */ OSSL_CMP_CTX_print_errors(ctx); - ossl_cmp_log1(INFO, ctx, "sending %s", req_type_str); + if (ctx->server != NULL) + ossl_cmp_log1(INFO, ctx, "sending %s", req_type_str); *rep = (*transfer_cb)(ctx, req); ctx->msg_timeout = bak_msg_timeout; @@ -182,7 +201,8 @@ static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req, * Still we use this preliminary value already for a progress report because * the following msg verification may also produce log entries and may fail. */ - ossl_cmp_log1(INFO, ctx, "received %s", ossl_cmp_bodytype_to_string(bt)); + ossl_cmp_log2(INFO, ctx, "received %s%s", ossl_cmp_bodytype_to_string(bt), + ossl_cmp_is_error_with_waiting(*rep) ? " (waiting)" : ""); /* copy received extraCerts to ctx->extraCertsIn so they can be retrieved */ if (bt != OSSL_CMP_PKIBODY_POLLREP && bt != OSSL_CMP_PKIBODY_PKICONF @@ -193,9 +213,17 @@ static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req, expected_type)) return 0; + /* + * rep can have the expected response type, which during polling is pollRep. + * When polling, also any other non-error response (the final response) + * is fine here. When not yet polling, delayed delivery may be initiated + * by the server returning an error message with 'waiting' status (or a + * response message of expected type ip/cp/kup with 'waiting' status). + */ if (bt == expected_type - /* as an answer to polling, there could be IP/CP/KUP: */ - || (IS_CREP(bt) && expected_type == OSSL_CMP_PKIBODY_POLLREP)) + || (expected_type == OSSL_CMP_PKIBODY_POLLREP + ? bt != OSSL_CMP_PKIBODY_ERROR + : ossl_cmp_is_error_with_waiting(*rep))) return 1; /* received message type is not one of the expected ones (e.g., error) */ @@ -237,7 +265,7 @@ static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req, /*- * When a 'waiting' PKIStatus has been received, this function is used to - * poll, which should yield a pollRep or finally a CertRepMessage in ip/cp/kup. + * poll, which should yield a pollRep or the final response. * On receiving a pollRep, which includes a checkAfter value, it return this * value if sleep == 0, else it sleeps as long as indicated and retries. * @@ -248,7 +276,8 @@ static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req, * Returns -1 on receiving pollRep if sleep == 0, setting the checkAfter value. * Returns 1 on success and provides the received PKIMESSAGE in *rep. * In this case the caller is responsible for freeing *rep. - * Returns 0 on error (which includes the case that timeout has been reached). + * Returns 0 on error (which includes the cases that timeout has been reached + * or a response with 'waiting' status has been received). */ static int poll_for_response(OSSL_CMP_CTX *ctx, int sleep, int rid, OSSL_CMP_MSG **rep, int *checkAfter) @@ -314,7 +343,7 @@ static int poll_for_response(OSSL_CMP_CTX *ctx, int sleep, int rid, str, check_after); if (ctx->total_timeout != 0) { /* timeout is not infinite */ - const int exp = 5; /* expected max time per msg round trip */ + const int exp = OSSL_CMP_EXPECTED_RESP_TIME; int64_t time_left = (int64_t)(ctx->end_time - exp - time(NULL)); if (time_left <= 0) { @@ -331,15 +360,25 @@ static int poll_for_response(OSSL_CMP_CTX *ctx, int sleep, int rid, OSSL_CMP_MSG_free(prep); prep = NULL; if (sleep) { - ossl_sleep((unsigned long)(1000 * check_after)); + OSSL_sleep((unsigned long)(1000 * check_after)); } else { if (checkAfter != NULL) *checkAfter = (int)check_after; return -1; /* exits the loop */ } + } else if (is_crep_with_waiting(prep, rid) + || ossl_cmp_is_error_with_waiting(prep)) { + /* received status must not be 'waiting' */ + (void)ossl_cmp_exchange_error(ctx, OSSL_CMP_PKISTATUS_rejection, + OSSL_CMP_CTX_FAILINFO_badRequest, + "polling already started", + 0 /* errorCode */, NULL); + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKISTATUS); + goto err; } else { - ossl_cmp_info(ctx, "received ip/cp/kup after polling"); - /* any other body type has been rejected by send_receive_check() */ + ossl_cmp_info(ctx, "received final response after polling"); + if (!ossl_cmp_ctx_set1_first_senderNonce(ctx, NULL)) + return 0; break; } } @@ -351,11 +390,63 @@ static int poll_for_response(OSSL_CMP_CTX *ctx, int sleep, int rid, return 1; err: + (void)ossl_cmp_ctx_set1_first_senderNonce(ctx, NULL); OSSL_CMP_MSG_free(preq); OSSL_CMP_MSG_free(prep); return 0; } +static int save_senderNonce_if_waiting(OSSL_CMP_CTX *ctx, + const OSSL_CMP_MSG *rep, int rid) +{ + /* + * Lightweight CMP Profile section 4.4 states: the senderNonce of the + * preceding request message because this value will be needed for checking + * the recipNonce of the final response to be received after polling. + */ + if ((is_crep_with_waiting(rep, rid) + || ossl_cmp_is_error_with_waiting(rep)) + && !ossl_cmp_ctx_set1_first_senderNonce(ctx, ctx->senderNonce)) + return 0; + + return 1; +} + +/* + * Send request and get response possibly with polling initiated by error msg. + * Polling for ip/cp/kup/ with 'waiting' status is handled by cert_response(). + */ +static int send_receive_also_delayed(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req, + OSSL_CMP_MSG **rep, int expected_type) +{ + + if (!send_receive_check(ctx, req, rep, expected_type)) + return 0; + + if (ossl_cmp_is_error_with_waiting(*rep)) { + if (!save_senderNonce_if_waiting(ctx, *rep, OSSL_CMP_CERTREQID_NONE)) + return 0; + /* not modifying ctx->status during certConf and error exchanges */ + if (expected_type != OSSL_CMP_PKIBODY_PKICONF + && !save_statusInfo(ctx, (*rep)->body->value.error->pKIStatusInfo)) + return 0; + + OSSL_CMP_MSG_free(*rep); + *rep = NULL; + + if (poll_for_response(ctx, 1 /* can sleep */, OSSL_CMP_CERTREQID_NONE, + rep, NULL /* checkAfter */) <= 0) { + ERR_raise(ERR_LIB_CMP, CMP_R_POLLING_FAILED); + return 0; + } + } + if (OSSL_CMP_MSG_get_bodytype(*rep) != expected_type) { + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + return 0; + } + + return 1; +} /* * Send certConf for IR, CR or KUR sequences and check response, * not modifying ctx->status during the certConf exchange @@ -372,7 +463,8 @@ int ossl_cmp_exchange_certConf(OSSL_CMP_CTX *ctx, int certReqId, if (certConf == NULL) goto err; - res = send_receive_check(ctx, certConf, &PKIconf, OSSL_CMP_PKIBODY_PKICONF); + res = send_receive_also_delayed(ctx, certConf, &PKIconf, + OSSL_CMP_PKIBODY_PKICONF); err: OSSL_CMP_MSG_free(certConf); @@ -396,7 +488,8 @@ int ossl_cmp_exchange_error(OSSL_CMP_CTX *ctx, int status, int fail_info, if ((error = ossl_cmp_error_new(ctx, si, errorCode, details, 0)) == NULL) goto err; - res = send_receive_check(ctx, error, &PKIconf, OSSL_CMP_PKIBODY_PKICONF); + res = send_receive_also_delayed(ctx, error, + &PKIconf, OSSL_CMP_PKIBODY_PKICONF); err: OSSL_CMP_MSG_free(error); @@ -490,6 +583,7 @@ int OSSL_CMP_certConf_cb(OSSL_CMP_CTX *ctx, X509 *cert, int fail_info, { X509_STORE *out_trusted = OSSL_CMP_CTX_get_certConf_cb_arg(ctx); STACK_OF(X509) *chain = NULL; + (void)text; /* make (artificial) use of var to prevent compiler warning */ if (fail_info != 0) /* accept any error flagged by CMP core library */ @@ -516,7 +610,7 @@ int OSSL_CMP_certConf_cb(OSSL_CMP_CTX *ctx, X509 *cert, int fail_info, if (X509_verify_cert(csc) <= 0) goto err; - if (!ossl_x509_add_certs_new(&chain, X509_STORE_CTX_get0_chain(csc), + if (!ossl_x509_add_certs_new(&chain, X509_STORE_CTX_get0_chain(csc), X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP | X509_ADD_FLAG_NO_SS)) { sk_X509_free(chain); @@ -544,7 +638,7 @@ int OSSL_CMP_certConf_cb(OSSL_CMP_CTX *ctx, X509 *cert, int fail_info, "success building approximate chain for newly enrolled cert"); } (void)ossl_cmp_ctx_set1_newChain(ctx, chain); - sk_X509_pop_free(chain, X509_free); + OSSL_STACK_OF_X509_free(chain); return fail_info; } @@ -559,70 +653,104 @@ int OSSL_CMP_certConf_cb(OSSL_CMP_CTX *ctx, X509 *cert, int fail_info, */ static int cert_response(OSSL_CMP_CTX *ctx, int sleep, int rid, OSSL_CMP_MSG **resp, int *checkAfter, - int req_type, int expected_type) + ossl_unused int req_type, + ossl_unused int expected_type) { - EVP_PKEY *rkey = ossl_cmp_ctx_get0_newPubkey(ctx); + EVP_PKEY *rkey = NULL; int fail_info = 0; /* no failure */ const char *txt = NULL; - OSSL_CMP_CERTREPMESSAGE *crepmsg; - OSSL_CMP_CERTRESPONSE *crep; + OSSL_CMP_CERTREPMESSAGE *crepmsg = NULL; + OSSL_CMP_CERTRESPONSE *crep = NULL; OSSL_CMP_certConf_cb_t cb; X509 *cert; char *subj = NULL; int ret = 1; + int rcvd_type; + OSSL_CMP_PKISI *si; if (!ossl_assert(ctx != NULL)) return 0; retry: - crepmsg = (*resp)->body->value.ip; /* same for cp and kup */ - if (sk_OSSL_CMP_CERTRESPONSE_num(crepmsg->response) > 1) { - ERR_raise(ERR_LIB_CMP, CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED); - return 0; - } - crep = ossl_cmp_certrepmessage_get0_certresponse(crepmsg, rid); - if (crep == NULL) - return 0; - if (!save_statusInfo(ctx, crep->status)) - return 0; - if (rid == OSSL_CMP_CERTREQID_NONE) { /* used for OSSL_CMP_PKIBODY_P10CR */ - rid = ossl_cmp_asn1_get_int(crep->certReqId); - if (rid < OSSL_CMP_CERTREQID_NONE) { - ERR_raise(ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID); + rcvd_type = OSSL_CMP_MSG_get_bodytype(*resp); + if (IS_CREP(rcvd_type)) { + crepmsg = (*resp)->body->value.ip; /* same for cp and kup */ + if (sk_OSSL_CMP_CERTRESPONSE_num(crepmsg->response) > 1) { + ERR_raise(ERR_LIB_CMP, CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED); return 0; } + crep = ossl_cmp_certrepmessage_get0_certresponse(crepmsg, rid); + if (crep == NULL) + return 0; + si = crep->status; + + if (rid == OSSL_CMP_CERTREQID_NONE) { + /* for OSSL_CMP_PKIBODY_P10CR learn CertReqId from response */ + rid = ossl_cmp_asn1_get_int(crep->certReqId); + if (rid < OSSL_CMP_CERTREQID_NONE) { + ERR_raise(ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID); + return 0; + } + } + } else if (rcvd_type == OSSL_CMP_PKIBODY_ERROR) { + si = (*resp)->body->value.error->pKIStatusInfo; + } else { + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + return 0; } - if (ossl_cmp_pkisi_get_status(crep->status) == OSSL_CMP_PKISTATUS_waiting) { + if (!save_statusInfo(ctx, si)) + return 0; + + if (ossl_cmp_pkisi_get_status(si) == OSSL_CMP_PKISTATUS_waiting) { + /* + * Here we allow both and error message with waiting indication + * as well as a certificate response with waiting indication, where + * its flavor (ip, cp, or kup) may not strictly match ir/cr/p10cr/kur. + */ OSSL_CMP_MSG_free(*resp); *resp = NULL; if ((ret = poll_for_response(ctx, sleep, rid, resp, checkAfter)) != 0) { if (ret == -1) /* at this point implies sleep == 0 */ return ret; /* waiting */ - goto retry; /* got ip/cp/kup, which may still indicate 'waiting' */ + goto retry; /* got some response other than pollRep */ } else { ERR_raise(ERR_LIB_CMP, CMP_R_POLLING_FAILED); return 0; } } + /* at this point, we have received ip/cp/kup/error without waiting */ + if (rcvd_type == OSSL_CMP_PKIBODY_ERROR) { + ERR_raise(ERR_LIB_CMP, CMP_R_RECEIVED_ERROR); + return 0; + } + /* here we are strict on the flavor of ip/cp/kup: must match request */ + if (rcvd_type != expected_type) { + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + return 0; + } + cert = get1_cert_status(ctx, (*resp)->body->type, crep); if (cert == NULL) { ERR_add_error_data(1, "; cannot extract certificate from response"); return 0; } - if (!ossl_cmp_ctx_set0_newCert(ctx, cert)) + if (!ossl_cmp_ctx_set0_newCert(ctx, cert)) { + X509_free(cert); return 0; + } /* * if the CMP server returned certificates in the caPubs field, copy them * to the context so that they can be retrieved if necessary */ - if (crepmsg->caPubs != NULL + if (crepmsg != NULL && crepmsg->caPubs != NULL && !ossl_cmp_ctx_set1_caPubs(ctx, crepmsg->caPubs)) return 0; subj = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0); + rkey = ossl_cmp_ctx_get0_newPubkey(ctx); if (rkey != NULL /* X509_check_private_key() also works if rkey is just public key */ && !(X509_check_private_key(ctx->newCert, rkey))) { @@ -649,6 +777,10 @@ static int cert_response(OSSL_CMP_CTX *ctx, int sleep, int rid, if (fail_info != 0) /* immediately log error before any certConf exchange */ ossl_cmp_log1(ERROR, ctx, "rejecting newly enrolled cert with subject: %s", subj); + /* + * certConf exchange should better be moved to do_certreq_seq() such that + * also more low-level errors with CertReqMessages get reported to server + */ if (!ctx->disableConfirm && !ossl_cmp_hdr_has_implicitConfirm((*resp)->header)) { if (!ossl_cmp_exchange_certConf(ctx, rid, fail_info, txt)) @@ -705,6 +837,9 @@ int OSSL_CMP_try_certreq(OSSL_CMP_CTX *ctx, int req_type, if (ctx->status != OSSL_CMP_PKISTATUS_waiting) { /* not polling already */ if (!initial_certreq(ctx, req_type, crm, &rep, rep_type)) goto err; + + if (!save_senderNonce_if_waiting(ctx, rep, rid)) + return 0; } else { if (req_type < 0) return ossl_cmp_exchange_error(ctx, OSSL_CMP_PKISTATUS_rejection, @@ -732,7 +867,6 @@ int OSSL_CMP_try_certreq(OSSL_CMP_CTX *ctx, int req_type, X509 *OSSL_CMP_exec_certreq(OSSL_CMP_CTX *ctx, int req_type, const OSSL_CRMF_MSG *crm) { - OSSL_CMP_MSG *rep = NULL; int is_p10 = req_type == OSSL_CMP_PKIBODY_P10CR; int rid = is_p10 ? OSSL_CMP_CERTREQID_NONE : OSSL_CMP_CERTREQID; @@ -747,6 +881,9 @@ X509 *OSSL_CMP_exec_certreq(OSSL_CMP_CTX *ctx, int req_type, if (!initial_certreq(ctx, req_type, crm, &rep, rep_type)) goto err; + if (!save_senderNonce_if_waiting(ctx, rep, rid)) + return 0; + if (cert_response(ctx, 1 /* sleep */, rid, &rep, NULL, req_type, rep_type) <= 0) goto err; @@ -773,7 +910,8 @@ int OSSL_CMP_exec_RR_ses(OSSL_CMP_CTX *ctx) return 0; } ctx->status = OSSL_CMP_PKISTATUS_request; - if (ctx->oldCert == NULL && ctx->p10CSR == NULL) { + if (ctx->oldCert == NULL && ctx->p10CSR == NULL + && (ctx->serialNumber == NULL || ctx->issuer == NULL)) { ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_REFERENCE_CERT); return 0; } @@ -783,7 +921,7 @@ int OSSL_CMP_exec_RR_ses(OSSL_CMP_CTX *ctx) goto end; ctx->status = OSSL_CMP_PKISTATUS_trans; - if (!send_receive_check(ctx, rr, &rp, OSSL_CMP_PKIBODY_RP)) + if (!send_receive_also_delayed(ctx, rr, &rp, OSSL_CMP_PKIBODY_RP)) goto end; rrep = rp->body->value.rp; @@ -840,7 +978,8 @@ int OSSL_CMP_exec_RR_ses(OSSL_CMP_CTX *ctx) OSSL_CRMF_CERTTEMPLATE *tmpl = sk_OSSL_CMP_REVDETAILS_value(rr->body->value.rr, rsid)->certDetails; const X509_NAME *issuer = OSSL_CRMF_CERTTEMPLATE_get0_issuer(tmpl); - const ASN1_INTEGER *serial = OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(tmpl); + const ASN1_INTEGER *serial = + OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(tmpl); if (sk_OSSL_CRMF_CERTID_num(rrep->revCerts) != num_RevDetails) { ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_RP_COMPONENT_COUNT); @@ -903,7 +1042,7 @@ STACK_OF(OSSL_CMP_ITAV) *OSSL_CMP_exec_GENM_ses(OSSL_CMP_CTX *ctx) goto err; ctx->status = OSSL_CMP_PKISTATUS_trans; - if (!send_receive_check(ctx, genm, &genp, OSSL_CMP_PKIBODY_GENP)) + if (!send_receive_also_delayed(ctx, genm, &genp, OSSL_CMP_PKIBODY_GENP)) goto err; ctx->status = OSSL_CMP_PKISTATUS_accepted; diff --git a/crypto/cmp/cmp_ctx.c b/crypto/cmp/cmp_ctx.c index 9d9bd357daf7..7b78ab16036b 100644 --- a/crypto/cmp/cmp_ctx.c +++ b/crypto/cmp/cmp_ctx.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2024 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -20,16 +20,35 @@ #include <openssl/crmf.h> #include <openssl/err.h> +#define DEFINE_OSSL_CMP_CTX_get0(FIELD, TYPE) \ + DEFINE_OSSL_CMP_CTX_get0_NAME(FIELD, FIELD, TYPE) +#define DEFINE_OSSL_CMP_CTX_get0_NAME(NAME, FIELD, TYPE) \ +TYPE *OSSL_CMP_CTX_get0_##NAME(const OSSL_CMP_CTX *ctx) \ +{ \ + if (ctx == NULL) { \ + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); \ + return NULL; \ + } \ + return ctx->FIELD; \ +} + /* * Get current certificate store containing trusted root CA certs */ -X509_STORE *OSSL_CMP_CTX_get0_trustedStore(const OSSL_CMP_CTX *ctx) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return NULL; - } - return ctx->trusted; +DEFINE_OSSL_CMP_CTX_get0_NAME(trusted, trusted, X509_STORE) + +#define DEFINE_OSSL_set0(PREFIX, FIELD, TYPE) \ + DEFINE_OSSL_set0_NAME(PREFIX, FIELD, FIELD, TYPE) +#define DEFINE_OSSL_set0_NAME(PREFIX, NAME, FIELD, TYPE) \ +int PREFIX##_set0##_##NAME(OSSL_CMP_CTX *ctx, TYPE *val) \ +{ \ + if (ctx == NULL) { \ + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); \ + return 0; \ + } \ + TYPE##_free(ctx->FIELD); \ + ctx->FIELD = val; \ + return 1; \ } /* @@ -37,26 +56,13 @@ X509_STORE *OSSL_CMP_CTX_get0_trustedStore(const OSSL_CMP_CTX *ctx) * and a cert verification callback function used for CMP server authentication. * Any already existing store entry is freed. Given NULL, the entry is reset. */ -int OSSL_CMP_CTX_set0_trustedStore(OSSL_CMP_CTX *ctx, X509_STORE *store) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - X509_STORE_free(ctx->trusted); - ctx->trusted = store; - return 1; -} +DEFINE_OSSL_set0_NAME(OSSL_CMP_CTX, trusted, trusted, X509_STORE) + +DEFINE_OSSL_CMP_CTX_get0(libctx, OSSL_LIB_CTX) +DEFINE_OSSL_CMP_CTX_get0(propq, const char) /* Get current list of non-trusted intermediate certs */ -STACK_OF(X509) *OSSL_CMP_CTX_get0_untrusted(const OSSL_CMP_CTX *ctx) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return NULL; - } - return ctx->untrusted; -} +DEFINE_OSSL_CMP_CTX_get0(untrusted, STACK_OF(X509)) /* * Set untrusted certificates for path construction in authentication of @@ -73,11 +79,11 @@ int OSSL_CMP_CTX_set1_untrusted(OSSL_CMP_CTX *ctx, STACK_OF(X509) *certs) if (!ossl_x509_add_certs_new(&untrusted, certs, X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP)) goto err; - sk_X509_pop_free(ctx->untrusted, X509_free); + OSSL_STACK_OF_X509_free(ctx->untrusted); ctx->untrusted = untrusted; return 1; err: - sk_X509_pop_free(untrusted, X509_free); + OSSL_STACK_OF_X509_free(untrusted); return 0; } @@ -108,7 +114,7 @@ OSSL_CMP_CTX *OSSL_CMP_CTX_new(OSSL_LIB_CTX *libctx, const char *propq) ctx->libctx = libctx; if (propq != NULL && (ctx->propq = OPENSSL_strdup(propq)) == NULL) - goto oom; + goto err; ctx->log_verbosity = OSSL_CMP_LOG_INFO; @@ -117,9 +123,12 @@ OSSL_CMP_CTX *OSSL_CMP_CTX_new(OSSL_LIB_CTX *libctx, const char *propq) ctx->keep_alive = 1; ctx->msg_timeout = -1; + ctx->tls_used = -1; /* default for backward compatibility */ - if ((ctx->untrusted = sk_X509_new_null()) == NULL) - goto oom; + if ((ctx->untrusted = sk_X509_new_null()) == NULL) { + ERR_raise(ERR_LIB_X509, ERR_R_CRYPTO_LIB); + goto err; + } ctx->pbm_slen = 16; if (!cmp_ctx_set_md(ctx, &ctx->pbm_owf, NID_sha256)) @@ -135,8 +144,6 @@ OSSL_CMP_CTX *OSSL_CMP_CTX_new(OSSL_LIB_CTX *libctx, const char *propq) /* all other elements are initialized to 0 or NULL, respectively */ return ctx; - oom: - ERR_raise(ERR_LIB_X509, ERR_R_MALLOC_FAILURE); err: OSSL_CMP_CTX_free(ctx); return NULL; @@ -157,11 +164,13 @@ int OSSL_CMP_CTX_reinit(OSSL_CMP_CTX *ctx) return 0; } +#ifndef OPENSSL_NO_HTTP if (ctx->http_ctx != NULL) { (void)OSSL_HTTP_close(ctx->http_ctx, 1); ossl_cmp_debug(ctx, "disconnected from CMP server"); ctx->http_ctx = NULL; } +#endif ctx->status = OSSL_CMP_PKISTATUS_unspecified; ctx->failInfoCode = -1; @@ -173,7 +182,8 @@ int OSSL_CMP_CTX_reinit(OSSL_CMP_CTX *ctx) && ossl_cmp_ctx_set1_newChain(ctx, NULL) && ossl_cmp_ctx_set1_caPubs(ctx, NULL) && ossl_cmp_ctx_set1_extraCertsIn(ctx, NULL) - && ossl_cmp_ctx_set0_validatedSrvCert(ctx, NULL) + && ossl_cmp_ctx_set1_validatedSrvCert(ctx, NULL) + && ossl_cmp_ctx_set1_first_senderNonce(ctx, NULL) && OSSL_CMP_CTX_set1_transactionID(ctx, NULL) && OSSL_CMP_CTX_set1_senderNonce(ctx, NULL) && ossl_cmp_ctx_set1_recipNonce(ctx, NULL); @@ -185,10 +195,12 @@ void OSSL_CMP_CTX_free(OSSL_CMP_CTX *ctx) if (ctx == NULL) return; +#ifndef OPENSSL_NO_HTTP if (ctx->http_ctx != NULL) { (void)OSSL_HTTP_close(ctx->http_ctx, 1); ossl_cmp_debug(ctx, "disconnected from CMP server"); } +#endif OPENSSL_free(ctx->propq); OPENSSL_free(ctx->serverPath); OPENSSL_free(ctx->server); @@ -199,10 +211,10 @@ void OSSL_CMP_CTX_free(OSSL_CMP_CTX *ctx) X509_free(ctx->validatedSrvCert); X509_NAME_free(ctx->expected_sender); X509_STORE_free(ctx->trusted); - sk_X509_pop_free(ctx->untrusted, X509_free); + OSSL_STACK_OF_X509_free(ctx->untrusted); X509_free(ctx->cert); - sk_X509_pop_free(ctx->chain, X509_free); + OSSL_STACK_OF_X509_free(ctx->chain); EVP_PKEY_free(ctx->pkey); ASN1_OCTET_STRING_free(ctx->referenceValue); if (ctx->secretValue != NULL) @@ -215,120 +227,83 @@ void OSSL_CMP_CTX_free(OSSL_CMP_CTX *ctx) ASN1_OCTET_STRING_free(ctx->transactionID); ASN1_OCTET_STRING_free(ctx->senderNonce); ASN1_OCTET_STRING_free(ctx->recipNonce); - sk_OSSL_CMP_ITAV_pop_free(ctx->geninfo_ITAVs, OSSL_CMP_ITAV_free); - sk_X509_pop_free(ctx->extraCertsOut, X509_free); + ASN1_OCTET_STRING_free(ctx->first_senderNonce); + OSSL_CMP_ITAVs_free(ctx->geninfo_ITAVs); + OSSL_STACK_OF_X509_free(ctx->extraCertsOut); EVP_PKEY_free(ctx->newPkey); X509_NAME_free(ctx->issuer); + ASN1_INTEGER_free(ctx->serialNumber); X509_NAME_free(ctx->subjectName); sk_GENERAL_NAME_pop_free(ctx->subjectAltNames, GENERAL_NAME_free); - sk_X509_EXTENSION_pop_free(ctx->reqExtensions, X509_EXTENSION_free); + X509_EXTENSIONS_free(ctx->reqExtensions); sk_POLICYINFO_pop_free(ctx->policies, POLICYINFO_free); X509_free(ctx->oldCert); X509_REQ_free(ctx->p10CSR); - sk_OSSL_CMP_ITAV_pop_free(ctx->genm_ITAVs, OSSL_CMP_ITAV_free); + OSSL_CMP_ITAVs_free(ctx->genm_ITAVs); - sk_ASN1_UTF8STRING_pop_free(ctx->statusString, ASN1_UTF8STRING_free); + OSSL_CMP_PKIFREETEXT_free(ctx->statusString); X509_free(ctx->newCert); - sk_X509_pop_free(ctx->newChain, X509_free); - sk_X509_pop_free(ctx->caPubs, X509_free); - sk_X509_pop_free(ctx->extraCertsIn, X509_free); + OSSL_STACK_OF_X509_free(ctx->newChain); + OSSL_STACK_OF_X509_free(ctx->caPubs); + OSSL_STACK_OF_X509_free(ctx->extraCertsIn); OPENSSL_free(ctx); } -int ossl_cmp_ctx_set_status(OSSL_CMP_CTX *ctx, int status) -{ - if (!ossl_assert(ctx != NULL)) - return 0; - ctx->status = status; - return 1; +#define DEFINE_OSSL_set(PREFIX, FIELD, TYPE) \ +int PREFIX##_set_##FIELD(OSSL_CMP_CTX *ctx, TYPE val) \ +{ \ + if (ctx == NULL) { \ + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); \ + return 0; \ + } \ + ctx->FIELD = val; \ + return 1; \ +} + +DEFINE_OSSL_set(ossl_cmp_ctx, status, int) + +#define DEFINE_OSSL_get(PREFIX, FIELD, TYPE, ERR_RET) \ +TYPE PREFIX##_get_##FIELD(const OSSL_CMP_CTX *ctx) \ +{ \ + if (ctx == NULL) { \ + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); \ + return ERR_RET; \ + } \ + return ctx->FIELD; \ } /* * Returns the PKIStatus from the last CertRepMessage * or Revocation Response or error message, -1 on error */ -int OSSL_CMP_CTX_get_status(const OSSL_CMP_CTX *ctx) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return -1; - } - return ctx->status; -} +DEFINE_OSSL_get(OSSL_CMP_CTX, status, int, -1) /* * Returns the statusString from the last CertRepMessage * or Revocation Response or error message, NULL on error */ -OSSL_CMP_PKIFREETEXT *OSSL_CMP_CTX_get0_statusString(const OSSL_CMP_CTX *ctx) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return NULL; - } - return ctx->statusString; -} +DEFINE_OSSL_CMP_CTX_get0(statusString, OSSL_CMP_PKIFREETEXT) -int ossl_cmp_ctx_set0_statusString(OSSL_CMP_CTX *ctx, - OSSL_CMP_PKIFREETEXT *text) -{ - if (!ossl_assert(ctx != NULL)) - return 0; - sk_ASN1_UTF8STRING_pop_free(ctx->statusString, ASN1_UTF8STRING_free); - ctx->statusString = text; - return 1; -} - -int ossl_cmp_ctx_set0_validatedSrvCert(OSSL_CMP_CTX *ctx, X509 *cert) -{ - if (!ossl_assert(ctx != NULL)) - return 0; - X509_free(ctx->validatedSrvCert); - ctx->validatedSrvCert = cert; - return 1; -} +DEFINE_OSSL_set0(ossl_cmp_ctx, statusString, OSSL_CMP_PKIFREETEXT) /* Set callback function for checking if the cert is ok or should be rejected */ -int OSSL_CMP_CTX_set_certConf_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_certConf_cb_t cb) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - ctx->certConf_cb = cb; - return 1; -} +DEFINE_OSSL_set(OSSL_CMP_CTX, certConf_cb, OSSL_CMP_certConf_cb_t) /* * Set argument, respectively a pointer to a structure containing arguments, * optionally to be used by the certConf callback. */ -int OSSL_CMP_CTX_set_certConf_cb_arg(OSSL_CMP_CTX *ctx, void *arg) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - ctx->certConf_cb_arg = arg; - return 1; -} +DEFINE_OSSL_set(OSSL_CMP_CTX, certConf_cb_arg, void *) /* * Get argument, respectively the pointer to a structure containing arguments, * optionally to be used by certConf callback. * Returns callback argument set previously (NULL if not set or on error) */ -void *OSSL_CMP_CTX_get_certConf_cb_arg(const OSSL_CMP_CTX *ctx) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return NULL; - } - return ctx->certConf_cb_arg; -} +DEFINE_OSSL_get(OSSL_CMP_CTX, certConf_cb_arg, void *, NULL) #ifndef OPENSSL_NO_TRACE static size_t ossl_cmp_log_trace_cb(const char *buf, size_t cnt, @@ -452,8 +427,8 @@ int OSSL_CMP_CTX_set1_referenceValue(OSSL_CMP_CTX *ctx, ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); return 0; } - return ossl_cmp_asn1_octet_string_set1_bytes(&ctx->referenceValue, ref, - len); + return + ossl_cmp_asn1_octet_string_set1_bytes(&ctx->referenceValue, ref, len); } /* Set or clear the password to be used for protecting messages with PBMAC */ @@ -461,6 +436,7 @@ int OSSL_CMP_CTX_set1_secretValue(OSSL_CMP_CTX *ctx, const unsigned char *sec, int len) { ASN1_OCTET_STRING *secretValue = NULL; + if (ctx == NULL) { ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); return 0; @@ -475,74 +451,51 @@ int OSSL_CMP_CTX_set1_secretValue(OSSL_CMP_CTX *ctx, return 1; } +#define DEFINE_OSSL_CMP_CTX_get1_certs(FIELD) \ +STACK_OF(X509) *OSSL_CMP_CTX_get1_##FIELD(const OSSL_CMP_CTX *ctx) \ +{ \ + if (ctx == NULL) { \ + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); \ + return NULL; \ + } \ + return X509_chain_up_ref(ctx->FIELD); \ +} + /* Returns the cert chain computed by OSSL_CMP_certConf_cb(), NULL on error */ -STACK_OF(X509) *OSSL_CMP_CTX_get1_newChain(const OSSL_CMP_CTX *ctx) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return NULL; - } - return X509_chain_up_ref(ctx->newChain); +DEFINE_OSSL_CMP_CTX_get1_certs(newChain) + +#define DEFINE_OSSL_set1_certs(PREFIX, FIELD) \ +int PREFIX##_set1_##FIELD(OSSL_CMP_CTX *ctx, STACK_OF(X509) *certs) \ +{ \ + if (ctx == NULL) { \ + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); \ + return 0; \ + } \ + OSSL_STACK_OF_X509_free(ctx->FIELD); \ + ctx->FIELD = NULL; \ + return certs == NULL || (ctx->FIELD = X509_chain_up_ref(certs)) != NULL; \ } /* * Copies any given stack of inbound X509 certificates to newChain * of the OSSL_CMP_CTX structure so that they may be retrieved later. */ -int ossl_cmp_ctx_set1_newChain(OSSL_CMP_CTX *ctx, STACK_OF(X509) *newChain) -{ - if (!ossl_assert(ctx != NULL)) - return 0; - - sk_X509_pop_free(ctx->newChain, X509_free); - ctx->newChain = NULL; - return newChain == NULL || - (ctx->newChain = X509_chain_up_ref(newChain)) != NULL; -} +DEFINE_OSSL_set1_certs(ossl_cmp_ctx, newChain) /* Returns the stack of extraCerts received in CertRepMessage, NULL on error */ -STACK_OF(X509) *OSSL_CMP_CTX_get1_extraCertsIn(const OSSL_CMP_CTX *ctx) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return NULL; - } - return X509_chain_up_ref(ctx->extraCertsIn); -} +DEFINE_OSSL_CMP_CTX_get1_certs(extraCertsIn) /* * Copies any given stack of inbound X509 certificates to extraCertsIn * of the OSSL_CMP_CTX structure so that they may be retrieved later. */ -int ossl_cmp_ctx_set1_extraCertsIn(OSSL_CMP_CTX *ctx, - STACK_OF(X509) *extraCertsIn) -{ - if (!ossl_assert(ctx != NULL)) - return 0; - - sk_X509_pop_free(ctx->extraCertsIn, X509_free); - ctx->extraCertsIn = NULL; - return extraCertsIn == NULL - || (ctx->extraCertsIn = X509_chain_up_ref(extraCertsIn)) != NULL; -} +DEFINE_OSSL_set1_certs(ossl_cmp_ctx, extraCertsIn) /* * Copies any given stack as the new stack of X509 * certificates to send out in the extraCerts field. */ -int OSSL_CMP_CTX_set1_extraCertsOut(OSSL_CMP_CTX *ctx, - STACK_OF(X509) *extraCertsOut) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - - sk_X509_pop_free(ctx->extraCertsOut, X509_free); - ctx->extraCertsOut = NULL; - return extraCertsOut == NULL - || (ctx->extraCertsOut = X509_chain_up_ref(extraCertsOut)) != NULL; -} +DEFINE_OSSL_set1_certs(OSSL_CMP_CTX, extraCertsOut) /* * Add the given policy info object @@ -583,6 +536,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) { @@ -598,28 +553,13 @@ int OSSL_CMP_CTX_push0_genm_ITAV(OSSL_CMP_CTX *ctx, OSSL_CMP_ITAV *itav) * were received in the caPubs field of the last CertRepMessage. * Returns NULL on error */ -STACK_OF(X509) *OSSL_CMP_CTX_get1_caPubs(const OSSL_CMP_CTX *ctx) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return NULL; - } - return X509_chain_up_ref(ctx->caPubs); -} +DEFINE_OSSL_CMP_CTX_get1_certs(caPubs) /* * Copies any given stack of certificates to the given * OSSL_CMP_CTX structure so that they may be retrieved later. */ -int ossl_cmp_ctx_set1_caPubs(OSSL_CMP_CTX *ctx, STACK_OF(X509) *caPubs) -{ - if (!ossl_assert(ctx != NULL)) - return 0; - - sk_X509_pop_free(ctx->caPubs, X509_free); - ctx->caPubs = NULL; - return caPubs == NULL || (ctx->caPubs = X509_chain_up_ref(caPubs)) != NULL; -} +DEFINE_OSSL_set1_certs(ossl_cmp_ctx, caPubs) #define char_dup OPENSSL_strdup #define char_free OPENSSL_free @@ -642,8 +582,9 @@ int OSSL_CMP_CTX_set1_##FIELD(OSSL_CMP_CTX *ctx, const TYPE *val) \ #define X509_invalid(cert) (!ossl_x509v3_cache_extensions(cert)) #define EVP_PKEY_invalid(key) 0 -#define DEFINE_OSSL_CMP_CTX_set1_up_ref(FIELD, TYPE) \ -int OSSL_CMP_CTX_set1_##FIELD(OSSL_CMP_CTX *ctx, TYPE *val) \ + +#define DEFINE_OSSL_set1_up_ref(PREFIX, FIELD, TYPE) \ +int PREFIX##_set1_##FIELD(OSSL_CMP_CTX *ctx, TYPE *val) \ { \ if (ctx == NULL) { \ ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); \ @@ -662,12 +603,14 @@ int OSSL_CMP_CTX_set1_##FIELD(OSSL_CMP_CTX *ctx, TYPE *val) \ return 1; \ } +DEFINE_OSSL_set1_up_ref(ossl_cmp_ctx, validatedSrvCert, X509) + /* * Pins the server certificate to be directly trusted (even if it is expired) * for verifying response messages. * Cert pointer is not consumed. It may be NULL to clear the entry. */ -DEFINE_OSSL_CMP_CTX_set1_up_ref(srvCert, X509) +DEFINE_OSSL_set1_up_ref(OSSL_CMP_CTX, srvCert, X509) /* Set the X509 name of the recipient to be placed in the PKIHeader */ DEFINE_OSSL_CMP_CTX_set1(recipient, X509_NAME) @@ -678,6 +621,8 @@ DEFINE_OSSL_CMP_CTX_set1(expected_sender, X509_NAME) /* Set the X509 name of the issuer to be placed in the certTemplate */ DEFINE_OSSL_CMP_CTX_set1(issuer, X509_NAME) +/* Set the ASN1_INTEGER serial to be placed in the certTemplate for rr */ +DEFINE_OSSL_CMP_CTX_set1(serialNumber, ASN1_INTEGER) /* * Set the subject name that will be placed in the certificate * request. This will be the subject name on the received certificate. @@ -697,7 +642,7 @@ int OSSL_CMP_CTX_set0_reqExtensions(OSSL_CMP_CTX *ctx, X509_EXTENSIONS *exts) ERR_raise(ERR_LIB_CMP, CMP_R_MULTIPLE_SAN_SOURCES); return 0; } - sk_X509_EXTENSION_pop_free(ctx->reqExtensions, X509_EXTENSION_free); + X509_EXTENSIONS_free(ctx->reqExtensions); ctx->reqExtensions = exts; return 1; } @@ -750,7 +695,7 @@ int OSSL_CMP_CTX_push1_subjectAltName(OSSL_CMP_CTX *ctx, * Set our own client certificate, used for example in KUR and when * doing the IR with existing certificate. */ -DEFINE_OSSL_CMP_CTX_set1_up_ref(cert, X509) +DEFINE_OSSL_set1_up_ref(OSSL_CMP_CTX, cert, X509) int OSSL_CMP_CTX_build_cert_chain(OSSL_CMP_CTX *ctx, X509_STORE *own_trusted, STACK_OF(X509) *candidates) @@ -784,7 +729,7 @@ int OSSL_CMP_CTX_build_cert_chain(OSSL_CMP_CTX *ctx, X509_STORE *own_trusted, * Also used as reference cert (defaulting to cert) for deriving subject DN * and SANs. Its issuer is used as default recipient in the CMP message header. */ -DEFINE_OSSL_CMP_CTX_set1_up_ref(oldCert, X509) +DEFINE_OSSL_set1_up_ref(OSSL_CMP_CTX, oldCert, X509) /* Set the PKCS#10 CSR to be sent in P10CR */ DEFINE_OSSL_CMP_CTX_set1(p10CSR, X509_REQ) @@ -793,31 +738,19 @@ DEFINE_OSSL_CMP_CTX_set1(p10CSR, X509_REQ) * Set the (newly received in IP/KUP/CP) certificate in the context. * This only permits for one cert to be enrolled at a time. */ -int ossl_cmp_ctx_set0_newCert(OSSL_CMP_CTX *ctx, X509 *cert) -{ - if (!ossl_assert(ctx != NULL)) - return 0; +DEFINE_OSSL_set0(ossl_cmp_ctx, newCert, X509) - X509_free(ctx->newCert); - ctx->newCert = cert; - return 1; -} +/* Get successfully validated server cert, if any, of current transaction */ +DEFINE_OSSL_CMP_CTX_get0(validatedSrvCert, X509) /* * Get the (newly received in IP/KUP/CP) client certificate from the context * This only permits for one client cert to be received... */ -X509 *OSSL_CMP_CTX_get0_newCert(const OSSL_CMP_CTX *ctx) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return NULL; - } - return ctx->newCert; -} +DEFINE_OSSL_CMP_CTX_get0(newCert, X509) /* Set the client's current private key */ -DEFINE_OSSL_CMP_CTX_set1_up_ref(pkey, EVP_PKEY) +DEFINE_OSSL_set1_up_ref(OSSL_CMP_CTX, pkey, EVP_PKEY) /* Set new key pair. Used e.g. when doing Key Update */ int OSSL_CMP_CTX_set0_newPkey(OSSL_CMP_CTX *ctx, int priv, EVP_PKEY *pkey) @@ -864,151 +797,77 @@ EVP_PKEY *ossl_cmp_ctx_get0_newPubkey(const OSSL_CMP_CTX *ctx) return ctx->pkey; } -/* Set the given transactionID to the context */ -int OSSL_CMP_CTX_set1_transactionID(OSSL_CMP_CTX *ctx, - const ASN1_OCTET_STRING *id) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - return ossl_cmp_asn1_octet_string_set1(&ctx->transactionID, id); +#define DEFINE_set1_ASN1_OCTET_STRING(PREFIX, FIELD) \ +int PREFIX##_set1_##FIELD(OSSL_CMP_CTX *ctx, const ASN1_OCTET_STRING *id) \ +{ \ + if (ctx == NULL) { \ + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); \ + return 0; \ + } \ + return ossl_cmp_asn1_octet_string_set1(&ctx->FIELD, id); \ } +/* Set the given transactionID to the context */ +DEFINE_set1_ASN1_OCTET_STRING(OSSL_CMP_CTX, transactionID) + /* Set the nonce to be used for the recipNonce in the message created next */ -int ossl_cmp_ctx_set1_recipNonce(OSSL_CMP_CTX *ctx, - const ASN1_OCTET_STRING *nonce) -{ - if (!ossl_assert(ctx != NULL)) - return 0; - return ossl_cmp_asn1_octet_string_set1(&ctx->recipNonce, nonce); -} +DEFINE_set1_ASN1_OCTET_STRING(ossl_cmp_ctx, recipNonce) /* Stores the given nonce as the last senderNonce sent out */ -int OSSL_CMP_CTX_set1_senderNonce(OSSL_CMP_CTX *ctx, - const ASN1_OCTET_STRING *nonce) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - return ossl_cmp_asn1_octet_string_set1(&ctx->senderNonce, nonce); -} +DEFINE_set1_ASN1_OCTET_STRING(OSSL_CMP_CTX, senderNonce) + +/* store the first req sender nonce for verifying delayed delivery */ +DEFINE_set1_ASN1_OCTET_STRING(ossl_cmp_ctx, first_senderNonce) /* Set the proxy server to use for HTTP(S) connections */ DEFINE_OSSL_CMP_CTX_set1(proxy, char) -/* Set the (HTTP) host name of the CMP server */ +/* Set the (HTTP) hostname of the CMP server */ DEFINE_OSSL_CMP_CTX_set1(server, char) /* Set the server exclusion list of the HTTP proxy server */ DEFINE_OSSL_CMP_CTX_set1(no_proxy, char) +#ifndef OPENSSL_NO_HTTP /* Set the http connect/disconnect callback function to be used for HTTP(S) */ -int OSSL_CMP_CTX_set_http_cb(OSSL_CMP_CTX *ctx, OSSL_HTTP_bio_cb_t cb) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - ctx->http_cb = cb; - return 1; -} +DEFINE_OSSL_set(OSSL_CMP_CTX, http_cb, OSSL_HTTP_bio_cb_t) /* Set argument optionally to be used by the http connect/disconnect callback */ -int OSSL_CMP_CTX_set_http_cb_arg(OSSL_CMP_CTX *ctx, void *arg) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - ctx->http_cb_arg = arg; - return 1; -} +DEFINE_OSSL_set(OSSL_CMP_CTX, http_cb_arg, void *) /* * Get argument optionally to be used by the http connect/disconnect callback * Returns callback argument set previously (NULL if not set or on error) */ -void *OSSL_CMP_CTX_get_http_cb_arg(const OSSL_CMP_CTX *ctx) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return NULL; - } - return ctx->http_cb_arg; -} +DEFINE_OSSL_get(OSSL_CMP_CTX, http_cb_arg, void *, NULL) +#endif /* Set callback function for sending CMP request and receiving response */ -int OSSL_CMP_CTX_set_transfer_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_transfer_cb_t cb) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - ctx->transfer_cb = cb; - return 1; -} +DEFINE_OSSL_set(OSSL_CMP_CTX, transfer_cb, OSSL_CMP_transfer_cb_t) /* Set argument optionally to be used by the transfer callback */ -int OSSL_CMP_CTX_set_transfer_cb_arg(OSSL_CMP_CTX *ctx, void *arg) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - ctx->transfer_cb_arg = arg; - return 1; -} +DEFINE_OSSL_set(OSSL_CMP_CTX, transfer_cb_arg, void *) /* * Get argument optionally to be used by the transfer callback. * Returns callback argument set previously (NULL if not set or on error) */ -void *OSSL_CMP_CTX_get_transfer_cb_arg(const OSSL_CMP_CTX *ctx) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return NULL; - } - return ctx->transfer_cb_arg; -} +DEFINE_OSSL_get(OSSL_CMP_CTX, transfer_cb_arg, void *, NULL) /** Set the HTTP server port to be used */ -int OSSL_CMP_CTX_set_serverPort(OSSL_CMP_CTX *ctx, int port) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return 0; - } - ctx->serverPort = port; - return 1; -} +DEFINE_OSSL_set(OSSL_CMP_CTX, serverPort, int) /* Set the HTTP path to be used on the server (e.g "pkix/") */ DEFINE_OSSL_CMP_CTX_set1(serverPath, char) /* Set the failInfo error code as bit encoding in OSSL_CMP_CTX */ -int ossl_cmp_ctx_set_failInfoCode(OSSL_CMP_CTX *ctx, int fail_info) -{ - if (!ossl_assert(ctx != NULL)) - return 0; - ctx->failInfoCode = fail_info; - return 1; -} +DEFINE_OSSL_set(ossl_cmp_ctx, failInfoCode, int) /* * Get the failInfo error code in OSSL_CMP_CTX as bit encoding. * Returns bit string as integer on success, -1 on error */ -int OSSL_CMP_CTX_get_failInfoCode(const OSSL_CMP_CTX *ctx) -{ - if (ctx == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); - return -1; - } - return ctx->failInfoCode; -} +DEFINE_OSSL_get(OSSL_CMP_CTX, failInfoCode, int, -1) /* Set a Boolean or integer option of the context to the "val" arg */ int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val) @@ -1056,6 +915,9 @@ int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val) case OSSL_CMP_OPT_UNPROTECTED_ERRORS: ctx->unprotectedErrors = val; break; + case OSSL_CMP_OPT_NO_CACHE_EXTRACERTS: + ctx->noCacheExtraCerts = val; + break; case OSSL_CMP_OPT_VALIDITY_DAYS: ctx->days = val; break; @@ -1098,6 +960,9 @@ int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val) case OSSL_CMP_OPT_TOTAL_TIMEOUT: ctx->total_timeout = val; break; + case OSSL_CMP_OPT_USE_TLS: + ctx->tls_used = val; + break; case OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR: ctx->permitTAInExtraCertsForIR = val; break; @@ -1138,6 +1003,8 @@ int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt) return ctx->unprotectedSend; case OSSL_CMP_OPT_UNPROTECTED_ERRORS: return ctx->unprotectedErrors; + case OSSL_CMP_OPT_NO_CACHE_EXTRACERTS: + return ctx->noCacheExtraCerts; case OSSL_CMP_OPT_VALIDITY_DAYS: return ctx->days; case OSSL_CMP_OPT_SUBJECTALTNAME_NODEFAULT: @@ -1162,6 +1029,8 @@ int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt) return ctx->msg_timeout; case OSSL_CMP_OPT_TOTAL_TIMEOUT: return ctx->total_timeout; + case OSSL_CMP_OPT_USE_TLS: + return ctx->tls_used; case OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR: return ctx->permitTAInExtraCertsForIR; case OSSL_CMP_OPT_REVOCATION_REASON: diff --git a/crypto/cmp/cmp_err.c b/crypto/cmp/cmp_err.c index dfc6dfbedee9..6d87d7b463dd 100644 --- a/crypto/cmp/cmp_err.c +++ b/crypto/cmp/cmp_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2025 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -76,16 +76,31 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { "error validating protection"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_VALIDATING_SIGNATURE), "error validating signature"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_EXPECTED_POLLREQ), "expected pollreq"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILED_BUILDING_OWN_CHAIN), "failed building own chain"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILED_EXTRACTING_CENTRAL_GEN_KEY), + "failed extracting central gen key"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILED_EXTRACTING_PUBKEY), "failed extracting pubkey"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILURE_OBTAINING_RANDOM), "failure obtaining random"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAIL_INFO_OUT_OF_RANGE), "fail info out of range"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_GENERATE_CERTREQTEMPLATE), + "generate certreqtemplate"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_GENERATE_CRLSTATUS), + "error creating crlstatus"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_GETTING_GENP), "getting genp"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_GET_ITAV), "get itav"}, {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_KEYSPEC), "invalid keyspec"}, {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_CENTRAL_GEN_KEY), + "missing central gen key"}, {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"}, @@ -139,18 +154,30 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_TRANSACTIONID_UNMATCHED), "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_CENTRAL_GEN_KEY), + "unexpected central gen key"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_CERTPROFILE), + "unexpected certprofile"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_CRLSTATUSLIST), + "unexpected crlstatuslist"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKIBODY), "unexpected pkibody"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKISTATUS), "unexpected pkistatus"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_POLLREQ), "unexpected pollreq"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PVNO), "unexpected pvno"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_SENDER), "unexpected sender"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNKNOWN_ALGORITHM_ID), "unknown algorithm id"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNKNOWN_CERT_TYPE), "unknown cert type"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNKNOWN_CRL_ISSUER), "unknown crl issuer"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNKNOWN_PKISTATUS), "unknown pkistatus"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_ALGORITHM), "unsupported algorithm"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_KEY_TYPE), "unsupported key type"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_PKIBODY), + "unsupported pkibody"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC), "unsupported protection alg dhbasedmac"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_VALUE_TOO_LARGE), "value too large"}, diff --git a/crypto/cmp/cmp_hdr.c b/crypto/cmp/cmp_hdr.c index 8c553af61a53..d00c9f76bb42 100644 --- a/crypto/cmp/cmp_hdr.c +++ b/crypto/cmp/cmp_hdr.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2024 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -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) { @@ -79,34 +89,6 @@ int ossl_cmp_general_name_is_NULL_DN(GENERAL_NAME *name) || (name->type == GEN_DIRNAME && IS_NULL_DN(name->d.directoryName)); } -/* assign to *tgt a copy of src (which may be NULL to indicate an empty DN) */ -static int set1_general_name(GENERAL_NAME **tgt, const X509_NAME *src) -{ - GENERAL_NAME *name; - - if (!ossl_assert(tgt != NULL)) - return 0; - if ((name = GENERAL_NAME_new()) == NULL) - goto err; - name->type = GEN_DIRNAME; - - if (src == NULL) { /* NULL-DN */ - if ((name->d.directoryName = X509_NAME_new()) == NULL) - goto err; - } else if (!X509_NAME_set(&name->d.directoryName, src)) { - goto err; - } - - GENERAL_NAME_free(*tgt); - *tgt = name; - - return 1; - - err: - GENERAL_NAME_free(name); - return 0; -} - /* * Set the sender name in PKIHeader. * when nm is NULL, sender is set to an empty string @@ -116,14 +98,14 @@ int ossl_cmp_hdr_set1_sender(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm) { if (!ossl_assert(hdr != NULL)) return 0; - return set1_general_name(&hdr->sender, nm); + return GENERAL_NAME_set1_X509_NAME(&hdr->sender, nm); } int ossl_cmp_hdr_set1_recipient(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm) { if (!ossl_assert(hdr != NULL)) return 0; - return set1_general_name(&hdr->recipient, nm); + return GENERAL_NAME_set1_X509_NAME(&hdr->recipient, nm); } int ossl_cmp_hdr_update_messageTime(OSSL_CMP_PKIHEADER *hdr) @@ -276,8 +258,7 @@ int ossl_cmp_hdr_set_transactionID(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr) if (!set_random(&ctx->transactionID, ctx, OSSL_CMP_TRANSACTIONID_LENGTH)) return 0; - tid = OPENSSL_buf2hexstr(ctx->transactionID->data, - ctx->transactionID->length); + tid = i2s_ASN1_OCTET_STRING(NULL, ctx->transactionID); if (tid != NULL) ossl_cmp_log1(DEBUG, ctx, "Starting new transaction with ID=%s", tid); @@ -302,11 +283,12 @@ int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr) return 0; /* - * If neither protection cert nor oldCert nor subject are given, + * If no protection cert nor oldCert nor CSR nor subject is given, * sender name is not known to the client and thus set to NULL-DN */ sender = ctx->cert != NULL ? X509_get_subject_name(ctx->cert) : ctx->oldCert != NULL ? X509_get_subject_name(ctx->oldCert) : + ctx->p10CSR != NULL ? X509_REQ_get_subject_name(ctx->p10CSR) : ctx->subjectName; if (!ossl_cmp_hdr_set1_sender(hdr, sender)) return 0; diff --git a/crypto/cmp/cmp_http.c b/crypto/cmp/cmp_http.c index d29bfa8674ad..c0226e562a32 100644 --- a/crypto/cmp/cmp_http.c +++ b/crypto/cmp/cmp_http.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2025 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -14,7 +14,6 @@ #include <openssl/asn1t.h> #include <openssl/http.h> -#include "internal/sockets.h" #include <openssl/cmp.h> #include "cmp_local.h" @@ -25,12 +24,11 @@ #include <stdlib.h> #include <openssl/bio.h> #include <openssl/buffer.h> -#include <openssl/cmp.h> #include <openssl/err.h> -static int keep_alive(int keep_alive, int body_type) +static int keep_alive(int keep_alive, int body_type, BIO **bios) { - if (keep_alive != 0 + if (keep_alive != 0 && bios == NULL /* * Ask for persistent connection only if may need more round trips. * Do so even with disableConfirm because polling might be needed. @@ -46,7 +44,6 @@ static int keep_alive(int keep_alive, int body_type) /* * Send the PKIMessage req and on success return the response, else NULL. - * Any previous error queue entries will likely be removed by ERR_clear_error(). */ OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req) @@ -57,6 +54,7 @@ OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx, int tls_used; const ASN1_ITEM *it = ASN1_ITEM_rptr(OSSL_CMP_MSG); BIO *req_mem, *rsp; + BIO **bios; /* optionally used as bio and rbio */ OSSL_CMP_MSG *res = NULL; if (ctx == NULL || req == NULL) { @@ -69,24 +67,40 @@ OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx, if ((req_mem = ASN1_item_i2d_mem_bio(it, (const ASN1_VALUE *)req)) == NULL) goto err; + bios = OSSL_CMP_CTX_get_transfer_cb_arg(ctx); if (ctx->serverPort != 0) BIO_snprintf(server_port, sizeof(server_port), "%d", ctx->serverPort); - tls_used = OSSL_CMP_CTX_get_http_cb_arg(ctx) != NULL; - if (ctx->http_ctx == NULL) - ossl_cmp_log3(DEBUG, ctx, "connecting to CMP server %s:%s%s", - ctx->server, server_port, tls_used ? " using TLS" : ""); + tls_used = ctx->tls_used >= 0 ? ctx->tls_used != 0 + : OSSL_CMP_CTX_get_http_cb_arg(ctx) != NULL; /* backward compat */ + if (ctx->http_ctx == NULL) { /* using existing connection or yet not set up own connection */ + const char *path = ctx->serverPath; + + if (path == NULL) + path = ""; + if (*path == '/') + path++; + if (bios == NULL) + ossl_cmp_log4(DEBUG, ctx, + "connecting to CMP server via http%s://%s:%s%s/%s", + tls_used ? "s" : "", ctx->server, server_port, path); + else + ossl_cmp_log3(DEBUG, ctx, + "using existing connection with CMP server %s%s and HTTP path /%s", + ctx->server, server_port, path); + } rsp = OSSL_HTTP_transfer(&ctx->http_ctx, ctx->server, server_port, ctx->serverPath, tls_used, ctx->proxy, ctx->no_proxy, - NULL /* bio */, NULL /* rbio */, + bios == NULL ? NULL : bios[0] /* bio */, + bios == NULL ? NULL : bios[1] /* rbio */, ctx->http_cb, OSSL_CMP_CTX_get_http_cb_arg(ctx), 0 /* buf_size */, headers, content_type_pkix, req_mem, content_type_pkix, 1 /* expect_asn1 */, OSSL_HTTP_DEFAULT_MAX_RESP_LEN, ctx->msg_timeout, - keep_alive(ctx->keep_alive, req->body->type)); + keep_alive(ctx->keep_alive, req->body->type, bios)); BIO_free(req_mem); res = (OSSL_CMP_MSG *)ASN1_item_d2i_bio(it, rsp, NULL); BIO_free(rsp); @@ -94,9 +108,11 @@ OSSL_CMP_MSG *OSSL_CMP_MSG_http_perform(OSSL_CMP_CTX *ctx, if (ctx->http_ctx == NULL) ossl_cmp_debug(ctx, "disconnected from CMP server"); /* - * Note that on normal successful end of the transaction the connection - * is not closed at this level, but this will be done by the CMP client - * application via OSSL_CMP_CTX_free() or OSSL_CMP_CTX_reinit(). + * Note that on normal successful end of the transaction the + * HTTP connection is not closed at this level if keep_alive(...) != 0. + * It should be closed by the CMP client application + * using OSSL_CMP_CTX_free() or OSSL_CMP_CTX_reinit(). + * Any pre-existing bio (== ctx->transfer_cb_arg) is not freed. */ if (res != NULL) ossl_cmp_debug(ctx, "finished reading response from CMP server"); diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h index 8eeb56d4e0f0..bbca4e0ac565 100644 --- a/crypto/cmp/cmp_local.h +++ b/crypto/cmp/cmp_local.h @@ -1,5 +1,5 @@ /* - * Copyright 2007-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2025 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -25,7 +25,7 @@ # include <openssl/x509v3.h> # include "crypto/x509.h" -#define IS_NULL_DN(name) (X509_NAME_get_entry(name, 0) == NULL) +# define IS_NULL_DN(name) (X509_NAME_get_entry(name, 0) == NULL) /* * this structure is used to store the context for CMP sessions @@ -49,10 +49,13 @@ struct ossl_cmp_ctx_st { int keep_alive; /* persistent connection: 0=no, 1=prefer, 2=require */ int msg_timeout; /* max seconds to wait for each CMP message round trip */ int total_timeout; /* max number of seconds an enrollment may take, incl. */ + int tls_used; /* whether to use TLS for client-side HTTP connections */ /* attempts polling for a response if a 'waiting' PKIStatus is received */ time_t end_time; /* session start time + totaltimeout */ +# ifndef OPENSSL_NO_HTTP OSSL_HTTP_bio_cb_t http_cb; void *http_cb_arg; /* allows to store optional argument to cb */ +# endif /* server authentication */ /* @@ -61,6 +64,7 @@ struct ossl_cmp_ctx_st { * certificate responses (ip/cp/kup), revocation responses (rp), and PKIConf */ int unprotectedErrors; + int noCacheExtraCerts; X509 *srvCert; /* certificate used to identify the server */ X509 *validatedSrvCert; /* caches any already validated server cert */ X509_NAME *expected_sender; /* expected sender in header of response */ @@ -78,7 +82,7 @@ struct ossl_cmp_ctx_st { X509 *cert; /* protection cert used to identify and sign for MSG_SIG_ALG */ STACK_OF(X509) *chain; /* (cached) chain of protection cert including it */ EVP_PKEY *pkey; /* the key pair corresponding to cert */ - ASN1_OCTET_STRING *referenceValue; /* optional user name for MSG_MAC_ALG */ + ASN1_OCTET_STRING *referenceValue; /* optional username for MSG_MAC_ALG */ ASN1_OCTET_STRING *secretValue; /* password/shared secret for MSG_MAC_ALG */ /* PBMParameters for MSG_MAC_ALG */ size_t pbm_slen; /* salt length, currently fixed to 16 */ @@ -92,6 +96,7 @@ struct ossl_cmp_ctx_st { ASN1_OCTET_STRING *transactionID; /* the current transaction ID */ ASN1_OCTET_STRING *senderNonce; /* last nonce sent */ ASN1_OCTET_STRING *recipNonce; /* last nonce received */ + ASN1_OCTET_STRING *first_senderNonce; /* sender nonce when starting to poll */ ASN1_UTF8STRING *freeText; /* optional string to include each msg */ STACK_OF(OSSL_CMP_ITAV) *geninfo_ITAVs; int implicitConfirm; /* set implicitConfirm in IR/KUR/CR messages */ @@ -101,7 +106,8 @@ struct ossl_cmp_ctx_st { /* certificate template */ EVP_PKEY *newPkey; /* explicit new private/public key for cert enrollment */ int newPkey_priv; /* flag indicating if newPkey contains private key */ - X509_NAME *issuer; /* issuer name to used in cert template */ + X509_NAME *issuer; /* issuer name to used in cert template, also in rr */ + ASN1_INTEGER *serialNumber; /* certificate serial number to use in rr */ int days; /* Number of days new certificates are asked to be valid for */ X509_NAME *subjectName; /* subject name to be used in cert template */ STACK_OF(GENERAL_NAME) *subjectAltNames; /* to add to the cert template */ @@ -118,7 +124,7 @@ struct ossl_cmp_ctx_st { int revocationReason; /* revocation reason code to be included in RR */ STACK_OF(OSSL_CMP_ITAV) *genm_ITAVs; /* content of general message */ - /* result returned in responses */ + /* result returned in responses, so far supporting only one certResponse */ int status; /* PKIStatus of last received IP/CP/KUP/RP/error or -1 */ OSSL_CMP_PKIFREETEXT *statusString; /* of last IP/CP/KUP/RP/error */ int failInfoCode; /* failInfoCode of last received IP/CP/KUP/error, or -1 */ @@ -202,6 +208,39 @@ 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) + +typedef struct ossl_cmp_certreqtemplate_st OSSL_CMP_CERTREQTEMPLATE; +DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CERTREQTEMPLATE) + +/*- + * CRLSource ::= CHOICE { + * dpn [0] DistributionPointName, + * issuer [1] GeneralNames } + */ + +typedef struct ossl_cmp_crlsource_st { + int type; + union { + DIST_POINT_NAME *dpn; + GENERAL_NAMES *issuer; + } value; +} OSSL_CMP_CRLSOURCE; +DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CRLSOURCE) + +/* + * CRLStatus ::= SEQUENCE { + * source CRLSource, + * thisUpdate Time OPTIONAL } + */ + +struct ossl_cmp_crlstatus_st { + OSSL_CMP_CRLSOURCE *source; + ASN1_TIME *thisUpdate; +}; /* OSSL_CMP_CRLSTATUS */ +DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CRLSTATUS) + /*- * declared already here as it will be used in OSSL_CMP_MSG (nested) and * infoType and infoValue @@ -247,6 +286,21 @@ 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 */ + X509 *rootCaCert; + /* NID_id_it_rootCaKeyUpdate - Root CA Certificate Update */ + OSSL_CMP_ROOTCAKEYUPDATE *rootCaKeyUpdate; + /* NID_id_it_certReqTemplate - Certificate Request Template */ + OSSL_CMP_CERTREQTEMPLATE *certReqTemplate; + /* NID_id_it_crlStatusList - CRL Update Retrieval */ + STACK_OF(OSSL_CMP_CRLSTATUS) *crlStatusList; + /* NID_id_it_crls - Certificate Status Lists */ + STACK_OF(X509_CRL) *crls; + /* this is to be used for so far undeclared objects */ ASN1_TYPE *other; } infoValue; @@ -257,7 +311,7 @@ typedef struct ossl_cmp_certorenccert_st { int type; union { X509 *certificate; - OSSL_CRMF_ENCRYPTEDVALUE *encryptedCert; + OSSL_CRMF_ENCRYPTEDKEY *encryptedCert; } value; } OSSL_CMP_CERTORENCCERT; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CERTORENCCERT) @@ -272,7 +326,7 @@ DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CERTORENCCERT) */ typedef struct ossl_cmp_certifiedkeypair_st { OSSL_CMP_CERTORENCCERT *certOrEncCert; - OSSL_CRMF_ENCRYPTEDVALUE *privateKey; + OSSL_CRMF_ENCRYPTEDKEY *privateKey; OSSL_CRMF_PKIPUBLICATIONINFO *publicationInfo; } OSSL_CMP_CERTIFIEDKEYPAIR; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CERTIFIEDKEYPAIR) @@ -369,13 +423,15 @@ DECLARE_ASN1_FUNCTIONS(OSSL_CMP_ERRORMSGCONTENT) * -- as is used to create and verify the certificate signature * certReqId INTEGER, * -- to match this confirmation with the corresponding req/rep - * statusInfo PKIStatusInfo OPTIONAL + * statusInfo PKIStatusInfo OPTIONAL, + * hashAlg [0] AlgorithmIdentifier OPTIONAL * } */ struct ossl_cmp_certstatus_st { ASN1_OCTET_STRING *certHash; ASN1_INTEGER *certReqId; OSSL_CMP_PKISI *statusInfo; + X509_ALGOR *hashAlg; /* 0 */ } /* OSSL_CMP_CERTSTATUS */; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CERTSTATUS) typedef STACK_OF(OSSL_CMP_CERTSTATUS) OSSL_CMP_CERTCONFIRMCONTENT; @@ -446,7 +502,7 @@ DECLARE_ASN1_FUNCTIONS(OSSL_CMP_POLLREPCONTENT) /*- * PKIHeader ::= SEQUENCE { - * pvno INTEGER { cmp1999(1), cmp2000(2) }, + * pvno INTEGER { cmp1999(1), cmp2000(2), cmp2021(3) }, * sender GeneralName, * -- identifies the sender * recipient GeneralName, @@ -708,6 +764,7 @@ DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PROTECTEDPART) * } -- or HMAC [RFC2104, RFC2202]) */ /*- + * Not supported: * id-DHBasedMac OBJECT IDENTIFIER ::= {1 2 840 113533 7 66 30} * DHBMParameter ::= SEQUENCE { * owf AlgorithmIdentifier, @@ -730,6 +787,32 @@ 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) + +/*- + * CertReqTemplateContent ::= SEQUENCE { + * certTemplate CertTemplate, + * keySpec Controls OPTIONAL + * } + */ +struct ossl_cmp_certreqtemplate_st { + OSSL_CRMF_CERTTEMPLATE *certTemplate; + OSSL_CMP_ATAVS *keySpec; +} /* OSSL_CMP_CERTREQTEMPLATE */; + /* from cmp_asn.c */ int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a); @@ -777,7 +860,7 @@ int ossl_cmp_print_log(OSSL_CMP_severity level, const OSSL_CMP_CTX *ctx, # define ossl_cmp_info(ctx, msg) ossl_cmp_log(INFO, ctx, msg) # define ossl_cmp_debug(ctx, msg) ossl_cmp_log(DEBUG, ctx, msg) # define ossl_cmp_trace(ctx, msg) ossl_cmp_log(TRACE, ctx, msg) -int ossl_cmp_ctx_set0_validatedSrvCert(OSSL_CMP_CTX *ctx, X509 *cert); +int ossl_cmp_ctx_set1_validatedSrvCert(OSSL_CMP_CTX *ctx, X509 *cert); int ossl_cmp_ctx_set_status(OSSL_CMP_CTX *ctx, int status); int ossl_cmp_ctx_set0_statusString(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIFREETEXT *text); @@ -790,6 +873,8 @@ int ossl_cmp_ctx_set1_extraCertsIn(OSSL_CMP_CTX *ctx, int ossl_cmp_ctx_set1_recipNonce(OSSL_CMP_CTX *ctx, const ASN1_OCTET_STRING *nonce); EVP_PKEY *ossl_cmp_ctx_get0_newPubkey(const OSSL_CMP_CTX *ctx); +int ossl_cmp_ctx_set1_first_senderNonce(OSSL_CMP_CTX *ctx, + const ASN1_OCTET_STRING *nonce); /* from cmp_status.c */ int ossl_cmp_pkisi_get_status(const OSSL_CMP_PKISI *si); @@ -867,7 +952,8 @@ OSSL_CMP_MSG *ossl_cmp_certreq_new(OSSL_CMP_CTX *ctx, int bodytype, const OSSL_CRMF_MSG *crm); OSSL_CMP_MSG *ossl_cmp_certrep_new(OSSL_CMP_CTX *ctx, int bodytype, int certReqId, const OSSL_CMP_PKISI *si, - X509 *cert, const X509 *encryption_recip, + X509 *cert, const EVP_PKEY *pkey, + const X509 *encryption_recip, STACK_OF(X509) *chain, STACK_OF(X509) *caPubs, int unprotectedErrors); OSSL_CMP_MSG *ossl_cmp_rr_new(OSSL_CMP_CTX *ctx); @@ -906,8 +992,10 @@ ossl_cmp_certrepmessage_get0_certresponse(const OSSL_CMP_CERTREPMESSAGE *crm, X509 *ossl_cmp_certresponse_get1_cert(const OSSL_CMP_CTX *ctx, const OSSL_CMP_CERTRESPONSE *crep); OSSL_CMP_MSG *ossl_cmp_msg_load(const char *file); +int ossl_cmp_is_error_with_waiting(const OSSL_CMP_MSG *msg); /* from cmp_protect.c */ +void ossl_cmp_set_own_chain(OSSL_CMP_CTX *ctx); int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg); ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg); @@ -925,6 +1013,8 @@ int ossl_cmp_verify_popo(const OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, int accept_RAVerified); /* from cmp_client.c */ +/* expected max time per msg round trip, used for last try during polling: */ +# define OSSL_CMP_EXPECTED_RESP_TIME 2 int ossl_cmp_exchange_certConf(OSSL_CMP_CTX *ctx, int certReqId, int fail_info, const char *txt); int ossl_cmp_exchange_error(OSSL_CMP_CTX *ctx, int status, int fail_info, diff --git a/crypto/cmp/cmp_msg.c b/crypto/cmp/cmp_msg.c index c8e467f3c21f..055f14c8f861 100644 --- a/crypto/cmp/cmp_msg.c +++ b/crypto/cmp/cmp_msg.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2025 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -19,6 +19,9 @@ #include <openssl/crmf.h> #include <openssl/err.h> #include <openssl/x509.h> +#include <openssl/pem.h> +#include <openssl/bio.h> +#include <internal/cms.h> OSSL_CMP_MSG *OSSL_CMP_MSG_new(OSSL_LIB_CTX *libctx, const char *propq) { @@ -59,7 +62,6 @@ int ossl_cmp_msg_set0_libctx(OSSL_CMP_MSG *msg, OSSL_LIB_CTX *libctx, return 1; } - OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg) { if (msg == NULL) { @@ -101,6 +103,34 @@ int OSSL_CMP_MSG_get_bodytype(const OSSL_CMP_MSG *msg) return msg->body->type; } +X509_PUBKEY *OSSL_CMP_MSG_get0_certreq_publickey(const OSSL_CMP_MSG *msg) +{ + const OSSL_CRMF_MSGS *reqs; + const OSSL_CRMF_MSG *crm; + const OSSL_CRMF_CERTTEMPLATE *tmpl; + X509_PUBKEY *pubkey; + + switch (OSSL_CMP_MSG_get_bodytype(msg)) { + case OSSL_CMP_PKIBODY_IR: + case OSSL_CMP_PKIBODY_CR: + case OSSL_CMP_PKIBODY_KUR: + reqs = msg->body->value.ir; /* value.ir is same for cr and kur */ + if ((crm = sk_OSSL_CRMF_MSG_value(reqs, 0)) == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_CERTREQMSG_NOT_FOUND); + return NULL; + } + if ((tmpl = OSSL_CRMF_MSG_get0_tmpl(crm)) == NULL + || (pubkey = OSSL_CRMF_CERTTEMPLATE_get0_publicKey(tmpl)) == NULL) { + ERR_raise(ERR_LIB_CMP, CRMF_R_POPO_MISSING_PUBLIC_KEY); + return NULL; + } + return pubkey; + default: + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + return NULL; + } +} + /* Add an extension to the referenced extension stack, which may be NULL */ static int add1_extension(X509_EXTENSIONS **pexts, int nid, int crit, void *ex) { @@ -118,34 +148,6 @@ static int add1_extension(X509_EXTENSIONS **pexts, int nid, int crit, void *ex) return res; } -/* Add extension list to the referenced extension stack, which may be NULL */ -static int add_extensions(STACK_OF(X509_EXTENSION) **target, - const STACK_OF(X509_EXTENSION) *exts) -{ - int i; - - if (target == NULL) - return 0; - - for (i = 0; i < sk_X509_EXTENSION_num(exts); i++) { - X509_EXTENSION *ext = sk_X509_EXTENSION_value(exts, i); - ASN1_OBJECT *obj = X509_EXTENSION_get_object(ext); - int idx = X509v3_get_ext_by_OBJ(*target, obj, -1); - - /* Does extension exist in target? */ - if (idx != -1) { - /* Delete all extensions of same type */ - do { - X509_EXTENSION_free(sk_X509_EXTENSION_delete(*target, idx)); - idx = X509v3_get_ext_by_OBJ(*target, obj, -1); - } while (idx != -1); - } - if (!X509v3_add_ext(target, ext, -1)) - return 0; - } - return 1; -} - /* Add a CRL revocation reason code to extension stack, which may be NULL */ static int add_crl_reason_extension(X509_EXTENSIONS **pexts, int reason_code) { @@ -272,6 +274,8 @@ static const X509_NAME *determine_subj(OSSL_CMP_CTX *ctx, int for_KUR, OSSL_CRMF_MSG *OSSL_CMP_CTX_setup_CRM(OSSL_CMP_CTX *ctx, int for_KUR, int rid) { OSSL_CRMF_MSG *crm = NULL; + int central_keygen = OSSL_CMP_CTX_get_option(ctx, OSSL_CMP_OPT_POPO_METHOD) + == OSSL_CRMF_POPO_NONE; X509 *refcert = ctx->oldCert != NULL ? ctx->oldCert : ctx->cert; /* refcert defaults to current client cert */ EVP_PKEY *rkey = ossl_cmp_ctx_get0_newPubkey(ctx); @@ -284,9 +288,10 @@ OSSL_CRMF_MSG *OSSL_CMP_CTX_setup_CRM(OSSL_CMP_CTX *ctx, int for_KUR, int rid) : X509_get_issuer_name(refcert); int crit = ctx->setSubjectAltNameCritical || subject == NULL; /* RFC5280: subjectAltName MUST be critical if subject is null */ + OSSL_CRMF_CERTTEMPLATE *tmpl; X509_EXTENSIONS *exts = NULL; - if (rkey == NULL) { + if (rkey == NULL && !central_keygen) { #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PUBLIC_KEY); return NULL; @@ -298,6 +303,7 @@ OSSL_CRMF_MSG *OSSL_CMP_CTX_setup_CRM(OSSL_CMP_CTX *ctx, int for_KUR, int rid) } if ((crm = OSSL_CRMF_MSG_new()) == NULL) return NULL; + tmpl = OSSL_CRMF_MSG_get0_tmpl(crm); if (!OSSL_CRMF_MSG_set_certReqId(crm, rid) /* * fill certTemplate, corresponding to CertificationRequestInfo @@ -307,6 +313,10 @@ OSSL_CRMF_MSG *OSSL_CMP_CTX_setup_CRM(OSSL_CMP_CTX *ctx, int for_KUR, int rid) || !OSSL_CRMF_CERTTEMPLATE_fill(OSSL_CRMF_MSG_get0_tmpl(crm), rkey, subject, issuer, NULL /* serial */)) goto err; + if (rkey != NULL && central_keygen) + X509_PUBKEY_set0_public_key(OSSL_CRMF_CERTTEMPLATE_get0_publicKey(tmpl), + NULL, 0); + if (ctx->days != 0) { time_t now = time(NULL); ASN1_TIME *notBefore = ASN1_TIME_adj(NULL, now, 0, 0); @@ -326,13 +336,13 @@ OSSL_CRMF_MSG *OSSL_CMP_CTX_setup_CRM(OSSL_CMP_CTX *ctx, int for_KUR, int rid) && (exts = X509_REQ_get_extensions(ctx->p10CSR)) == NULL) goto err; if (!ctx->SubjectAltName_nodefault && !HAS_SAN(ctx) && refcert != NULL - && (default_sans = X509V3_get_d2i(X509_get0_extensions(refcert), - NID_subject_alt_name, NULL, NULL)) - != NULL + && (default_sans = X509V3_get_d2i(X509_get0_extensions(refcert), + NID_subject_alt_name, NULL, NULL)) + != NULL && !add1_extension(&exts, NID_subject_alt_name, crit, default_sans)) goto err; - if (ctx->reqExtensions != NULL /* augment/override existing ones */ - && !add_extensions(&exts, ctx->reqExtensions)) + if (sk_X509_EXTENSION_num(ctx->reqExtensions) > 0 /* augment/override existing ones */ + && X509v3_add_extensions(&exts, ctx->reqExtensions) == NULL) goto err; if (sk_GENERAL_NAME_num(ctx->subjectAltNames) > 0 && !add1_extension(&exts, NID_subject_alt_name, @@ -442,9 +452,47 @@ OSSL_CMP_MSG *ossl_cmp_certreq_new(OSSL_CMP_CTX *ctx, int type, return NULL; } +#ifndef OPENSSL_NO_CMS +static OSSL_CRMF_ENCRYPTEDKEY *enc_privkey(OSSL_CMP_CTX *ctx, const EVP_PKEY *pkey) +{ + OSSL_CRMF_ENCRYPTEDKEY *ek = NULL; + CMS_EnvelopedData *envData = NULL; + BIO *privbio = NULL; + EVP_CIPHER *cipher = NULL; + X509 *recip = ctx->validatedSrvCert; /* this is the client cert */ + STACK_OF(X509) *encryption_recips = sk_X509_new_reserve(NULL, 1); + + if (encryption_recips == NULL + || !X509_add_cert(encryption_recips, recip, X509_ADD_FLAG_UP_REF)) + goto err; + + privbio = BIO_new(BIO_s_mem()); + if (privbio == NULL || i2d_PrivateKey_bio(privbio, pkey) <= 0) + goto err; + ossl_cmp_set_own_chain(ctx); + cipher = EVP_CIPHER_fetch(ctx->libctx, SN_aes_256_cbc, ctx->propq); + envData = ossl_cms_sign_encrypt(privbio, ctx->cert, ctx->chain, ctx->pkey, CMS_BINARY, + encryption_recips, cipher, CMS_BINARY, + ctx->libctx, ctx->propq); + EVP_CIPHER_free(cipher); + if (envData == NULL) + goto err; + ek = OSSL_CRMF_ENCRYPTEDKEY_init_envdata(envData); + + err: + sk_X509_pop_free(encryption_recips, X509_free); + BIO_free(privbio); + if (ek == NULL) + M_ASN1_free_of(envData, CMS_EnvelopedData); + + return ek; +} +#endif + OSSL_CMP_MSG *ossl_cmp_certrep_new(OSSL_CMP_CTX *ctx, int bodytype, int certReqId, const OSSL_CMP_PKISI *si, - X509 *cert, const X509 *encryption_recip, + X509 *cert, const EVP_PKEY *pkey, + const X509 *encryption_recip, STACK_OF(X509) *chain, STACK_OF(X509) *caPubs, int unprotectedErrors) { @@ -488,6 +536,16 @@ OSSL_CMP_MSG *ossl_cmp_certrep_new(OSSL_CMP_CTX *ctx, int bodytype, if (!X509_up_ref(cert)) goto err; resp->certifiedKeyPair->certOrEncCert->value.certificate = cert; + + if (pkey != NULL) { +#ifndef OPENSSL_NO_CMS + if ((resp->certifiedKeyPair->privateKey = enc_privkey(ctx, pkey)) == NULL) + goto err; +#else + ERR_raise(ERR_LIB_CMP, ERR_R_UNSUPPORTED); + goto err; +#endif + } } if (!sk_OSSL_CMP_CERTRESPONSE_push(repMsg->response, resp)) @@ -519,27 +577,37 @@ OSSL_CMP_MSG *ossl_cmp_certrep_new(OSSL_CMP_CTX *ctx, int bodytype, OSSL_CMP_MSG *ossl_cmp_rr_new(OSSL_CMP_CTX *ctx) { OSSL_CMP_MSG *msg = NULL; + const X509_NAME *issuer = NULL; + const X509_NAME *subject = NULL; + const ASN1_INTEGER *serialNumber = NULL; + EVP_PKEY *pubkey = NULL; OSSL_CMP_REVDETAILS *rd; int ret; - if (!ossl_assert(ctx != NULL && (ctx->oldCert != NULL - || ctx->p10CSR != NULL))) + if (!ossl_assert(ctx != NULL + && (ctx->oldCert != NULL || ctx->p10CSR != NULL + || (ctx->serialNumber != NULL && ctx->issuer != NULL)))) return NULL; if ((rd = OSSL_CMP_REVDETAILS_new()) == NULL) goto err; + if (ctx->serialNumber != NULL && ctx->issuer != NULL) { + issuer = ctx->issuer; + serialNumber = ctx->serialNumber; + } else if (ctx->oldCert != NULL) { + issuer = X509_get_issuer_name(ctx->oldCert); + serialNumber = X509_get0_serialNumber(ctx->oldCert); + } else if (ctx->p10CSR != NULL) { + pubkey = X509_REQ_get0_pubkey(ctx->p10CSR); + subject = X509_REQ_get_subject_name(ctx->p10CSR); + } else { + goto err; + } + /* Fill the template from the contents of the certificate to be revoked */ - ret = ctx->oldCert != NULL - ? OSSL_CRMF_CERTTEMPLATE_fill(rd->certDetails, - NULL /* pubkey would be redundant */, - NULL /* subject would be redundant */, - X509_get_issuer_name(ctx->oldCert), - X509_get0_serialNumber(ctx->oldCert)) - : OSSL_CRMF_CERTTEMPLATE_fill(rd->certDetails, - X509_REQ_get0_pubkey(ctx->p10CSR), - X509_REQ_get_subject_name(ctx->p10CSR), - NULL, NULL); + ret = OSSL_CRMF_CERTTEMPLATE_fill(rd->certDetails, pubkey, subject, + issuer, serialNumber); if (!ret) goto err; @@ -584,23 +652,20 @@ OSSL_CMP_MSG *ossl_cmp_rp_new(OSSL_CMP_CTX *ctx, const OSSL_CMP_PKISI *si, goto err; rep = msg->body->value.rp; - if ((si1 = OSSL_CMP_PKISI_dup(si)) == NULL) + if ((si1 = OSSL_CMP_PKISI_dup(si)) == NULL + || !sk_OSSL_CMP_PKISI_push(rep->status, si1)) goto err; - if (!sk_OSSL_CMP_PKISI_push(rep->status, si1)) { - OSSL_CMP_PKISI_free(si1); - goto err; - } + si1 = NULL; /* ownership transferred to rep->status */ if ((rep->revCerts = sk_OSSL_CRMF_CERTID_new_null()) == NULL) goto err; if (cid != NULL) { - if ((cid_copy = OSSL_CRMF_CERTID_dup(cid)) == NULL) + if ((cid_copy = OSSL_CRMF_CERTID_dup(cid)) == NULL + || !sk_OSSL_CRMF_CERTID_push(rep->revCerts, cid_copy)) goto err; - if (!sk_OSSL_CRMF_CERTID_push(rep->revCerts, cid_copy)) { - OSSL_CRMF_CERTID_free(cid_copy); - goto err; - } + + cid_copy = NULL; /* ownership transferred to rep->revCerts */ } if (!unprotectedErrors @@ -612,6 +677,8 @@ OSSL_CMP_MSG *ossl_cmp_rp_new(OSSL_CMP_CTX *ctx, const OSSL_CMP_PKISI *si, err: ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_CREATING_RP); + OSSL_CMP_PKISI_free(si1); + OSSL_CRMF_CERTID_free(cid_copy); OSSL_CMP_MSG_free(msg); return NULL; } @@ -673,7 +740,7 @@ int ossl_cmp_msg_gen_push1_ITAVs(OSSL_CMP_MSG *msg, } /* - * Creates a new General Message/Response with an empty itav stack + * Creates a new General Message/Response with a copy of the given itav stack * returns a pointer to the PKIMessage on success, NULL on error */ static OSSL_CMP_MSG *gen_new(OSSL_CMP_CTX *ctx, @@ -787,6 +854,8 @@ OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int certReqId, { OSSL_CMP_MSG *msg = NULL; OSSL_CMP_CERTSTATUS *certStatus = NULL; + EVP_MD *md; + int is_fallback; ASN1_OCTET_STRING *certHash = NULL; OSSL_CMP_PKISI *sinfo; @@ -814,13 +883,23 @@ OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int certReqId, /* set the ID of the certReq */ if (!ASN1_INTEGER_set(certStatus->certReqId, certReqId)) goto err; + + certStatus->hashAlg = NULL; /* * The hash of the certificate, using the same hash algorithm * as is used to create and verify the certificate signature. - * If not available, a default hash algorithm is used. + * If not available, a fallback hash algorithm is used. */ - if ((certHash = X509_digest_sig(ctx->newCert, NULL, NULL)) == NULL) + if ((certHash = X509_digest_sig(ctx->newCert, &md, &is_fallback)) == NULL) goto err; + if (is_fallback) { + if (!ossl_cmp_hdr_set_pvno(msg->header, OSSL_CMP_PVNO_3)) + goto err; + if ((certStatus->hashAlg = X509_ALGOR_new()) == NULL) + goto err; + X509_ALGOR_set_md(certStatus->hashAlg, md); + } + EVP_MD_free(md); if (!ossl_cmp_certstatus_set0_certHash(certStatus, certHash)) goto err; @@ -962,8 +1041,7 @@ static int suitable_rid(const ASN1_INTEGER *certReqId, int rid) return 1; trid = ossl_cmp_asn1_get_int(certReqId); - - if (trid == OSSL_CMP_CERTREQID_NONE) { + if (trid <= OSSL_CMP_CERTREQID_INVALID) { ERR_raise(ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID); return 0; } @@ -1023,22 +1101,51 @@ ossl_cmp_certrepmessage_get0_certresponse(const OSSL_CMP_CERTREPMESSAGE *crm, } /*- - * Retrieve the newly enrolled certificate from the given certResponse crep. - * Uses libctx and propq from ctx, in case of indirect POPO also private key. + * Retrieve newly enrolled certificate and key from the given certResponse crep. + * Stores any centrally generated key in ctx->newPkey. + * In case of indirect POPO uses ctx->newPkey to decrypt the new certificate. * Returns a pointer to a copy of the found certificate, or NULL if not found. */ -X509 *ossl_cmp_certresponse_get1_cert(const OSSL_CMP_CTX *ctx, - const OSSL_CMP_CERTRESPONSE *crep) +X509 *ossl_cmp_certresponse_get1_cert(const OSSL_CMP_CTX *ctx, const OSSL_CMP_CERTRESPONSE *crep) { OSSL_CMP_CERTORENCCERT *coec; X509 *crt = NULL; - EVP_PKEY *pkey; + OSSL_CRMF_ENCRYPTEDKEY *encr_key; + EVP_PKEY *pkey = NULL; + int central_keygen = OSSL_CMP_CTX_get_option(ctx, OSSL_CMP_OPT_POPO_METHOD) + == OSSL_CRMF_POPO_NONE; + + if (crep->certifiedKeyPair == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_CERTIFICATE_NOT_FOUND); + return NULL; + } + encr_key = crep->certifiedKeyPair->privateKey; + if (encr_key == NULL && central_keygen) { + ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_CENTRAL_GEN_KEY); + return NULL; + } + if (encr_key != NULL) { + if (!central_keygen) { + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_CENTRAL_GEN_KEY); + return NULL; + } + /* found encrypted private key, try to extract */ + pkey = OSSL_CRMF_ENCRYPTEDKEY_get1_pkey(encr_key, ctx->trusted, + ctx->untrusted, + ctx->pkey, ctx->cert, + ctx->secretValue, + ctx->libctx, ctx->propq); + if (pkey == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_FAILED_EXTRACTING_CENTRAL_GEN_KEY); + return NULL; + } + OSSL_CMP_CTX_set0_newPkey((OSSL_CMP_CTX *)ctx, 1, pkey); + } if (!ossl_assert(crep != NULL && ctx != NULL)) return NULL; - if (crep->certifiedKeyPair - && (coec = crep->certifiedKeyPair->certOrEncCert) != NULL) { + if ((coec = crep->certifiedKeyPair->certOrEncCert) != NULL) { switch (coec->type) { case OSSL_CMP_CERTORENCCERT_CERTIFICATE: crt = X509_dup(coec->value.certificate); @@ -1051,10 +1158,8 @@ X509 *ossl_cmp_certresponse_get1_cert(const OSSL_CMP_CTX *ctx, ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PRIVATE_KEY); return NULL; } - crt = - OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(coec->value.encryptedCert, - ctx->libctx, ctx->propq, - pkey); + crt = OSSL_CRMF_ENCRYPTEDKEY_get1_encCert(coec->value.encryptedCert, + ctx->libctx, ctx->propq, pkey, 0); break; default: ERR_raise(ERR_LIB_CMP, CMP_R_UNKNOWN_CERT_TYPE); @@ -1106,8 +1211,8 @@ OSSL_CMP_MSG *OSSL_CMP_MSG_read(const char *file, OSSL_LIB_CTX *libctx, } msg = OSSL_CMP_MSG_new(libctx, propq); - if (msg == NULL){ - ERR_raise(ERR_LIB_CMP, ERR_R_MALLOC_FAILURE); + if (msg == NULL) { + ERR_raise(ERR_LIB_CMP, ERR_R_CMP_LIB); return NULL; } @@ -1178,3 +1283,13 @@ int i2d_OSSL_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg) { return ASN1_i2d_bio_of(OSSL_CMP_MSG, i2d_OSSL_CMP_MSG, bio, msg); } + +int ossl_cmp_is_error_with_waiting(const OSSL_CMP_MSG *msg) +{ + if (!ossl_assert(msg != NULL)) + return 0; + + return (OSSL_CMP_MSG_get_bodytype(msg) == OSSL_CMP_PKIBODY_ERROR + && ossl_cmp_pkisi_get_status(msg->body->value.error->pKIStatusInfo) + == OSSL_CMP_PKISTATUS_waiting); +} diff --git a/crypto/cmp/cmp_protect.c b/crypto/cmp/cmp_protect.c index 539f6534cd01..e4f3bffed720 100644 --- a/crypto/cmp/cmp_protect.c +++ b/crypto/cmp/cmp_protect.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2025 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -10,6 +10,7 @@ */ #include "cmp_local.h" +#include "crypto/asn1.h" /* explicit #includes not strictly needed since implied by the above: */ #include <openssl/asn1t.h> @@ -21,9 +22,11 @@ /* * This function is also used by the internal verify_PBMAC() in cmp_vfy.c. * - * Calculate protection for given PKImessage according to - * the algorithm and parameters in the message header's protectionAlg + * Calculate protection for |msg| according to |msg->header->protectionAlg| * using the credentials, library context, and property criteria in the ctx. + * Unless |msg->header->protectionAlg| is PasswordBasedMAC, + * its value is completed according to |ctx->pkey| and |ctx->digest|, + * where the latter irrelevant in the case of Edwards curves. * * returns ASN1_BIT_STRING representing the protection on success, else NULL */ @@ -91,9 +94,8 @@ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_CTX *ctx, if ((prot = ASN1_BIT_STRING_new()) == NULL) goto end; - /* OpenSSL defaults all bit strings to be encoded as ASN.1 NamedBitList */ - prot->flags &= ~(ASN1_STRING_FLAG_BITS_LEFT | 0x07); - prot->flags |= ASN1_STRING_FLAG_BITS_LEFT; + /* OpenSSL by default encodes all bit strings as ASN.1 NamedBitList */ + ossl_asn1_string_set_bits_left(prot, 0); if (!ASN1_BIT_STRING_set(prot, protection, sig_len)) { ASN1_BIT_STRING_free(prot); prot = NULL; @@ -104,23 +106,22 @@ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_CTX *ctx, OPENSSL_free(prot_part_der); return prot; } else { - int md_nid; - const EVP_MD *md = NULL; + const EVP_MD *md = ctx->digest; + char name[80] = ""; if (ctx->pkey == NULL) { ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION); return NULL; } - if (!OBJ_find_sigid_algs(OBJ_obj2nid(algorOID), &md_nid, NULL) - || (md = EVP_get_digestbynid(md_nid)) == NULL) { - ERR_raise(ERR_LIB_CMP, CMP_R_UNKNOWN_ALGORITHM_ID); - return NULL; - } + if (EVP_PKEY_get_default_digest_name(ctx->pkey, name, sizeof(name)) > 0 + && strcmp(name, "UNDEF") == 0) /* at least for Ed25519, Ed448 */ + md = NULL; if ((prot = ASN1_BIT_STRING_new()) == NULL) return NULL; - if (ASN1_item_sign_ex(ASN1_ITEM_rptr(OSSL_CMP_PROTECTEDPART), NULL, + if (ASN1_item_sign_ex(ASN1_ITEM_rptr(OSSL_CMP_PROTECTEDPART), + msg->header->protectionAlg, /* sets X509_ALGOR */ NULL, prot, &prot_part, NULL, ctx->pkey, md, ctx->libctx, ctx->propq)) return prot; @@ -129,6 +130,25 @@ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_CTX *ctx, } } +void ossl_cmp_set_own_chain(OSSL_CMP_CTX *ctx) +{ + if (!ossl_assert(ctx != NULL)) + return; + /* if not yet done try to build chain using available untrusted certs */ + if (ctx->chain == NULL) { + ossl_cmp_debug(ctx, "trying to build chain for own CMP signer cert"); + ctx->chain = X509_build_chain(ctx->cert, ctx->untrusted, NULL, 0, + ctx->libctx, ctx->propq); + if (ctx->chain != NULL) { + ossl_cmp_debug(ctx, "success building chain for own CMP signer cert"); + } else { + /* dump errors to avoid confusion when printing further ones */ + OSSL_CMP_CTX_print_errors(ctx); + ossl_cmp_warn(ctx, "could not build chain for own CMP signer cert"); + } + } +} + /* ctx is not const just because ctx->chain may get adapted */ int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg) { @@ -141,22 +161,7 @@ int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg) int prepend = X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP | X509_ADD_FLAG_PREPEND | X509_ADD_FLAG_NO_SS; - /* if not yet done try to build chain using available untrusted certs */ - if (ctx->chain == NULL) { - ossl_cmp_debug(ctx, - "trying to build chain for own CMP signer cert"); - ctx->chain = X509_build_chain(ctx->cert, ctx->untrusted, NULL, 0, - ctx->libctx, ctx->propq); - if (ctx->chain != NULL) { - ossl_cmp_debug(ctx, - "success building chain for own CMP signer cert"); - } else { - /* dump errors to avoid confusion when printing further ones */ - OSSL_CMP_CTX_print_errors(ctx); - ossl_cmp_warn(ctx, - "could not build chain for own CMP signer cert"); - } - } + ossl_cmp_set_own_chain(ctx); if (ctx->chain != NULL) { if (!ossl_x509_add_certs_new(&msg->extraCerts, ctx->chain, prepend)) return 0; @@ -185,15 +190,16 @@ int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg) * Create an X509_ALGOR structure for PasswordBasedMAC protection based on * the pbm settings in the context */ -static int set_pbmac_algor(const OSSL_CMP_CTX *ctx, X509_ALGOR **alg) +static X509_ALGOR *pbmac_algor(const OSSL_CMP_CTX *ctx) { OSSL_CRMF_PBMPARAMETER *pbm = NULL; unsigned char *pbm_der = NULL; int pbm_der_len; ASN1_STRING *pbm_str = NULL; + X509_ALGOR *alg = NULL; if (!ossl_assert(ctx != NULL)) - return 0; + return NULL; pbm = OSSL_CRMF_pbmp_new(ctx->libctx, ctx->pbm_slen, EVP_MD_get_type(ctx->pbm_owf), ctx->pbm_itercnt, @@ -201,47 +207,18 @@ static int set_pbmac_algor(const OSSL_CMP_CTX *ctx, X509_ALGOR **alg) pbm_str = ASN1_STRING_new(); if (pbm == NULL || pbm_str == NULL) goto err; - if ((pbm_der_len = i2d_OSSL_CRMF_PBMPARAMETER(pbm, &pbm_der)) < 0) goto err; - if (!ASN1_STRING_set(pbm_str, pbm_der, pbm_der_len)) goto err; - if (*alg == NULL && (*alg = X509_ALGOR_new()) == NULL) - goto err; - OPENSSL_free(pbm_der); - - X509_ALGOR_set0(*alg, OBJ_nid2obj(NID_id_PasswordBasedMAC), - V_ASN1_SEQUENCE, pbm_str); - OSSL_CRMF_PBMPARAMETER_free(pbm); - return 1; - + alg = ossl_X509_ALGOR_from_nid(NID_id_PasswordBasedMAC, + V_ASN1_SEQUENCE, pbm_str); err: - ASN1_STRING_free(pbm_str); + if (alg == NULL) + ASN1_STRING_free(pbm_str); OPENSSL_free(pbm_der); OSSL_CRMF_PBMPARAMETER_free(pbm); - return 0; -} - -static int set_sig_algor(const OSSL_CMP_CTX *ctx, X509_ALGOR **alg) -{ - int nid = 0; - ASN1_OBJECT *algo = NULL; - - if (!OBJ_find_sigid_by_algs(&nid, EVP_MD_get_type(ctx->digest), - EVP_PKEY_get_id(ctx->pkey))) { - ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_KEY_TYPE); - return 0; - } - if ((algo = OBJ_nid2obj(nid)) == NULL) - return 0; - if (*alg == NULL && (*alg = X509_ALGOR_new()) == NULL) - return 0; - - if (X509_ALGOR_set0(*alg, algo, V_ASN1_UNDEF, NULL)) - return 1; - ASN1_OBJECT_free(algo); - return 0; + return alg; } static int set_senderKID(const OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg, @@ -260,6 +237,7 @@ int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg) /* * For the case of re-protection remove pre-existing protection. + * Does not remove any pre-existing extraCerts. */ X509_ALGOR_free(msg->header->protectionAlg); msg->header->protectionAlg = NULL; @@ -271,7 +249,7 @@ int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg) goto err; } else if (ctx->secretValue != NULL) { /* use PasswordBasedMac according to 5.1.3.1 if secretValue is given */ - if (!set_pbmac_algor(ctx, &msg->header->protectionAlg)) + if ((msg->header->protectionAlg = pbmac_algor(ctx)) == NULL) goto err; if (!set_senderKID(ctx, msg, NULL)) goto err; @@ -290,7 +268,7 @@ int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg) goto err; } - if (!set_sig_algor(ctx, &msg->header->protectionAlg)) + if ((msg->header->protectionAlg = X509_ALGOR_new()) == NULL) goto err; /* set senderKID to keyIdentifier of the cert according to 5.1.1 */ if (!set_senderKID(ctx, msg, X509_get0_subject_key_id(ctx->cert))) @@ -306,6 +284,7 @@ int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg) goto err; } if (!ctx->unprotectedSend + /* protect according to msg->header->protectionAlg partly set above */ && ((msg->protection = ossl_cmp_calc_protection(ctx, msg)) == NULL)) goto err; diff --git a/crypto/cmp/cmp_server.c b/crypto/cmp/cmp_server.c index 96f977636ca2..6a833f83c538 100644 --- a/crypto/cmp/cmp_server.c +++ b/crypto/cmp/cmp_server.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2025 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -20,11 +20,11 @@ #include <openssl/err.h> /* the context for the generic CMP server */ -struct ossl_cmp_srv_ctx_st -{ - void *custom_ctx; /* pointer to application-specific server context */ - OSSL_CMP_CTX *ctx; /* Client CMP context, reusing transactionID etc. */ - int certReqId; /* id of last ir/cr/kur, OSSL_CMP_CERTREQID_NONE for p10cr */ +struct ossl_cmp_srv_ctx_st { + OSSL_CMP_CTX *ctx; /* CMP client context reused for transactionID etc. */ + void *custom_ctx; /* application-specific server context */ + int certReqId; /* of ir/cr/kur, OSSL_CMP_CERTREQID_NONE for p10cr */ + int polling; /* current transaction is in polling mode */ OSSL_CMP_SRV_cert_request_cb_t process_cert_request; OSSL_CMP_SRV_rr_cb_t process_rr; @@ -32,6 +32,8 @@ struct ossl_cmp_srv_ctx_st OSSL_CMP_SRV_error_cb_t process_error; OSSL_CMP_SRV_certConf_cb_t process_certConf; OSSL_CMP_SRV_pollReq_cb_t process_pollReq; + OSSL_CMP_SRV_delayed_delivery_cb_t delayed_delivery; + OSSL_CMP_SRV_clean_transaction_cb_t clean_transaction; int sendUnprotectedErrors; /* Send error and rejection msgs unprotected */ int acceptUnprotected; /* Accept requests with no/invalid prot. */ @@ -59,6 +61,7 @@ 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; @@ -89,6 +92,19 @@ int OSSL_CMP_SRV_CTX_init(OSSL_CMP_SRV_CTX *srv_ctx, void *custom_ctx, return 1; } +int OSSL_CMP_SRV_CTX_init_trans(OSSL_CMP_SRV_CTX *srv_ctx, + OSSL_CMP_SRV_delayed_delivery_cb_t delay, + OSSL_CMP_SRV_clean_transaction_cb_t clean) +{ + if (srv_ctx == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + srv_ctx->delayed_delivery = delay; + srv_ctx->clean_transaction = clean; + return 1; +} + OSSL_CMP_CTX *OSSL_CMP_SRV_CTX_get0_cmp_ctx(const OSSL_CMP_SRV_CTX *srv_ctx) { if (srv_ctx == NULL) { @@ -149,6 +165,46 @@ int OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(OSSL_CMP_SRV_CTX *srv_ctx, return 1; } +/* return error msg with waiting status if polling is initiated, else NULL */ +static OSSL_CMP_MSG *delayed_delivery(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req) +{ + int ret; + unsigned long err; + int status = OSSL_CMP_PKISTATUS_waiting, + fail_info = 0, errorCode = 0; + const char *txt = NULL, *details = NULL; + OSSL_CMP_PKISI *si; + OSSL_CMP_MSG *msg; + + if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL + && srv_ctx->delayed_delivery != NULL)) + return NULL; + + ret = srv_ctx->delayed_delivery(srv_ctx, req); + if (ret == 0) + return NULL; + if (ret == 1) { + srv_ctx->polling = 1; + } else { + status = OSSL_CMP_PKISTATUS_rejection; + fail_info = 1 << OSSL_CMP_PKIFAILUREINFO_systemFailure; + txt = "server application error"; + err = ERR_peek_error(); + errorCode = ERR_GET_REASON(err); + details = ERR_reason_error_string(err); + } + + si = OSSL_CMP_STATUSINFO_new(status, fail_info, txt); + if (si == NULL) + return NULL; + + msg = ossl_cmp_error_new(srv_ctx->ctx, si, errorCode, details, + srv_ctx->sendUnprotectedErrors); + OSSL_CMP_PKISI_free(si); + return msg; +} + /* * Processes an ir/cr/p10cr/kur and returns a certification response. * Only handles the first certification request contained in req @@ -160,11 +216,12 @@ static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, OSSL_CMP_MSG *msg = NULL; OSSL_CMP_PKISI *si = NULL; X509 *certOut = NULL; + EVP_PKEY *keyOut = NULL; STACK_OF(X509) *chainOut = NULL, *caPubs = NULL; const OSSL_CRMF_MSG *crm = NULL; const X509_REQ *p10cr = NULL; int bodytype; - int certReqId; + int certReqId, central_keygen; if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL)) return NULL; @@ -195,20 +252,23 @@ static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, ERR_raise(ERR_LIB_CMP, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED); return NULL; } - - if ((crm = sk_OSSL_CRMF_MSG_value(reqs, OSSL_CMP_CERTREQID)) == NULL) { + if ((crm = sk_OSSL_CRMF_MSG_value(reqs, 0)) == NULL) { ERR_raise(ERR_LIB_CMP, CMP_R_CERTREQMSG_NOT_FOUND); return NULL; } certReqId = OSSL_CRMF_MSG_get_certReqId(crm); - if (certReqId != OSSL_CMP_CERTREQID) { + if (certReqId != OSSL_CMP_CERTREQID) { /* so far, only possible value */ ERR_raise(ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID); - return 0; + return NULL; } } srv_ctx->certReqId = certReqId; - if (!ossl_cmp_verify_popo(srv_ctx->ctx, req, srv_ctx->acceptRAVerified)) { + central_keygen = OSSL_CRMF_MSG_centralkeygen_requested(crm, p10cr); + if (central_keygen < 0) + return NULL; + if (central_keygen == 0 + && !ossl_cmp_verify_popo(srv_ctx->ctx, req, srv_ctx->acceptRAVerified)) { /* Proof of possession could not be verified */ si = OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_rejection, 1 << OSSL_CMP_PKIFAILUREINFO_badPOP, @@ -222,6 +282,8 @@ static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, &certOut, &chainOut, &caPubs); if (si == NULL) goto err; + if (ossl_cmp_pkisi_get_status(si) == OSSL_CMP_PKISTATUS_waiting) + srv_ctx->polling = 1; /* 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, @@ -230,19 +292,24 @@ static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, /* do not set if polling starts: */ && certOut != NULL)) goto err; + if (central_keygen == 1 + && srv_ctx->ctx->newPkey_priv && srv_ctx->ctx->newPkey != NULL) + keyOut = srv_ctx->ctx->newPkey; } msg = ossl_cmp_certrep_new(srv_ctx->ctx, bodytype, certReqId, si, - certOut, NULL /* enc */, chainOut, caPubs, + certOut, keyOut, NULL /* enc */, chainOut, caPubs, srv_ctx->sendUnprotectedErrors); + /* When supporting OSSL_CRMF_POPO_KEYENC, "enc" will need to be set */ if (msg == NULL) ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_CREATING_CERTREP); err: OSSL_CMP_PKISI_free(si); X509_free(certOut); - sk_X509_pop_free(chainOut, X509_free); - sk_X509_pop_free(caPubs, X509_free); + OSSL_CMP_CTX_set0_newPkey(srv_ctx->ctx, 0, NULL); + OSSL_STACK_OF_X509_free(chainOut); + OSSL_STACK_OF_X509_free(caPubs); return msg; } @@ -264,9 +331,8 @@ static OSSL_CMP_MSG *process_rr(OSSL_CMP_SRV_CTX *srv_ctx, ERR_raise(ERR_LIB_CMP, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED); return NULL; } - - if ((details = sk_OSSL_CMP_REVDETAILS_value(req->body->value.rr, - OSSL_CMP_REVREQSID)) == NULL) { + details = sk_OSSL_CMP_REVDETAILS_value(req->body->value.rr, 0); + if (details == NULL) { ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE); return NULL; } @@ -355,7 +421,7 @@ static OSSL_CMP_MSG *process_certConf(OSSL_CMP_SRV_CTX *srv_ctx, } else { if (num > 1) ossl_cmp_warn(ctx, "All CertStatus but the first will be ignored"); - status = sk_OSSL_CMP_CERTSTATUS_value(ccc, OSSL_CMP_CERTREQID); + status = sk_OSSL_CMP_CERTSTATUS_value(ccc, 0); } if (status != NULL) { @@ -386,38 +452,96 @@ static OSSL_CMP_MSG *process_certConf(OSSL_CMP_SRV_CTX *srv_ctx, return msg; } +/* pollReq is handled separately, to avoid recursive call */ +static OSSL_CMP_MSG *process_non_polling_request(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req) +{ + OSSL_CMP_MSG *rsp = NULL; + + if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL + && req->body != NULL)) + return NULL; + + switch (OSSL_CMP_MSG_get_bodytype(req)) { + case OSSL_CMP_PKIBODY_IR: + case OSSL_CMP_PKIBODY_CR: + case OSSL_CMP_PKIBODY_P10CR: + case OSSL_CMP_PKIBODY_KUR: + if (srv_ctx->process_cert_request == NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); + else + rsp = process_cert_request(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_RR: + if (srv_ctx->process_rr == NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); + else + rsp = process_rr(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_GENM: + if (srv_ctx->process_genm == NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); + else + rsp = process_genm(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_ERROR: + if (srv_ctx->process_error == NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); + else + rsp = process_error(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_CERTCONF: + if (srv_ctx->process_certConf == NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); + else + rsp = process_certConf(srv_ctx, req); + break; + + case OSSL_CMP_PKIBODY_POLLREQ: + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + break; + default: + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); + break; + } + + return rsp; +} + static OSSL_CMP_MSG *process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *req) { OSSL_CMP_POLLREQCONTENT *prc; OSSL_CMP_POLLREQ *pr; int certReqId; - OSSL_CMP_MSG *certReq; + OSSL_CMP_MSG *orig_req; int64_t check_after = 0; OSSL_CMP_MSG *msg = NULL; if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL)) return NULL; + if (!srv_ctx->polling) { + ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + return NULL; + } + prc = req->body->value.pollReq; if (sk_OSSL_CMP_POLLREQ_num(prc) != 1) { ERR_raise(ERR_LIB_CMP, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED); return NULL; } - pr = sk_OSSL_CMP_POLLREQ_value(prc, OSSL_CMP_CERTREQID); + pr = sk_OSSL_CMP_POLLREQ_value(prc, 0); certReqId = ossl_cmp_asn1_get_int(pr->certReqId); - if (certReqId != srv_ctx->certReqId) { - ERR_raise(ERR_LIB_CMP, CMP_R_BAD_REQUEST_ID); - return NULL; - } if (!srv_ctx->process_pollReq(srv_ctx, req, certReqId, - &certReq, &check_after)) + &orig_req, &check_after)) return NULL; - if (certReq != NULL) { - msg = process_cert_request(srv_ctx, certReq); - OSSL_CMP_MSG_free(certReq); + if (orig_req != NULL) { + srv_ctx->polling = 0; + msg = process_non_polling_request(srv_ctx, orig_req); + OSSL_CMP_MSG_free(orig_req); } else { if ((msg = ossl_cmp_pollRep_new(srv_ctx->ctx, certReqId, check_after)) == NULL) @@ -487,6 +611,12 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, if (!OSSL_CMP_CTX_set1_recipient(ctx, hdr->sender->d.directoryName)) goto err; + if (srv_ctx->polling && req_type != OSSL_CMP_PKIBODY_POLLREQ + && req_type != OSSL_CMP_PKIBODY_ERROR) { + ERR_raise(ERR_LIB_CMP, CMP_R_EXPECTED_POLLREQ); + goto err; + } + switch (req_type) { case OSSL_CMP_PKIBODY_IR: case OSSL_CMP_PKIBODY_CR: @@ -496,10 +626,8 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, case OSSL_CMP_PKIBODY_GENM: case OSSL_CMP_PKIBODY_ERROR: if (ctx->transactionID != NULL) { - char *tid; + char *tid = i2s_ASN1_OCTET_STRING(NULL, ctx->transactionID); - tid = OPENSSL_buf2hexstr(ctx->transactionID->data, - ctx->transactionID->length); if (tid != NULL) ossl_cmp_log1(WARN, ctx, "Assuming that last transaction with ID=%s got aborted", @@ -510,6 +638,13 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, 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)) { + ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE); + goto err; + } + break; default: /* transactionID should be already initialized */ @@ -529,49 +664,17 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, if (!req_verified) 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: - if (srv_ctx->process_cert_request == NULL) - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - else - rsp = process_cert_request(srv_ctx, req); - break; - case OSSL_CMP_PKIBODY_RR: - if (srv_ctx->process_rr == NULL) - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - else - rsp = process_rr(srv_ctx, req); - break; - case OSSL_CMP_PKIBODY_GENM: - if (srv_ctx->process_genm == NULL) - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - else - rsp = process_genm(srv_ctx, req); - break; - case OSSL_CMP_PKIBODY_ERROR: - if (srv_ctx->process_error == NULL) - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - else - rsp = process_error(srv_ctx, req); - break; - case OSSL_CMP_PKIBODY_CERTCONF: - if (srv_ctx->process_certConf == NULL) - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - else - rsp = process_certConf(srv_ctx, req); - break; - case OSSL_CMP_PKIBODY_POLLREQ: + if (req_type == OSSL_CMP_PKIBODY_POLLREQ) { if (srv_ctx->process_pollReq == NULL) - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); + ERR_raise(ERR_LIB_CMP, CMP_R_UNSUPPORTED_PKIBODY); else rsp = process_pollReq(srv_ctx, req); - break; - default: - ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PKIBODY); - break; + } else { + if (srv_ctx->delayed_delivery != NULL + && (rsp = delayed_delivery(srv_ctx, req)) != NULL) { + goto err; + } + rsp = process_non_polling_request(srv_ctx, req); } err: @@ -581,6 +684,7 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, int flags = 0; unsigned long err = ERR_peek_error_data(&data, &flags); int fail_info = 1 << OSSL_CMP_PKIFAILUREINFO_badRequest; + /* fail_info is not very specific */ OSSL_CMP_PKISI *si = NULL; if (!req_verified) { @@ -626,10 +730,19 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, break; /* fall through */ + case OSSL_CMP_PKIBODY_ERROR: + if (rsp != NULL && ossl_cmp_is_error_with_waiting(rsp)) + break; + /* fall through */ + case OSSL_CMP_PKIBODY_RP: case OSSL_CMP_PKIBODY_PKICONF: case OSSL_CMP_PKIBODY_GENP: - case OSSL_CMP_PKIBODY_ERROR: + /* 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 */ diff --git a/crypto/cmp/cmp_status.c b/crypto/cmp/cmp_status.c index 68144aa4fed8..b9086d84f846 100644 --- a/crypto/cmp/cmp_status.c +++ b/crypto/cmp/cmp_status.c @@ -184,11 +184,11 @@ char *snprint_PKIStatusInfo_parts(int status, int fail_info, || (status_string = ossl_cmp_PKIStatus_to_string(status)) == NULL) return NULL; -#define ADVANCE_BUFFER \ - if (printed_chars < 0 || (size_t)printed_chars >= bufsize) \ - return NULL; \ - write_ptr += printed_chars; \ - bufsize -= printed_chars; +#define ADVANCE_BUFFER \ + if (printed_chars < 0 || (size_t)printed_chars >= bufsize) \ + return NULL; \ + write_ptr += printed_chars; \ + bufsize -= printed_chars; printed_chars = BIO_snprintf(write_ptr, bufsize, "%s", status_string); ADVANCE_BUFFER; diff --git a/crypto/cmp/cmp_util.c b/crypto/cmp/cmp_util.c index 7cf27cc9d4b4..f3c21c5d914c 100644 --- a/crypto/cmp/cmp_util.c +++ b/crypto/cmp/cmp_util.c @@ -1,5 +1,5 @@ /* - * Copyright 2007-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2007-2021 The OpenSSL Project Authors. All Rights Reserved. * Copyright Nokia 2007-2019 * Copyright Siemens AG 2015-2019 * @@ -53,8 +53,7 @@ static OSSL_CMP_severity parse_level(const char *level) if (end_level == NULL) return -1; - if (strncmp(level, OSSL_CMP_LOG_PREFIX, - strlen(OSSL_CMP_LOG_PREFIX)) == 0) + if (HAS_PREFIX(level, OSSL_CMP_LOG_PREFIX)) level += strlen(OSSL_CMP_LOG_PREFIX); len = end_level - level; if (len > max_level_len) @@ -190,7 +189,7 @@ void OSSL_CMP_print_errors_cb(OSSL_CMP_log_cb_t log_fn) BIO_free(bio); } #else - /* ERR_raise(ERR_LIB_CMP, CMP_R_NO_STDIO) makes no sense during error printing */ + /* ERR_raise(..., CMP_R_NO_STDIO) would make no sense here */ #endif } else { if (log_fn(component, file, line, OSSL_CMP_LOG_ERR, msg) <= 0) @@ -244,6 +243,7 @@ int ossl_cmp_asn1_octet_string_set1(ASN1_OCTET_STRING **tgt, const ASN1_OCTET_STRING *src) { ASN1_OCTET_STRING *new; + if (tgt == NULL) { ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); return 0; diff --git a/crypto/cmp/cmp_vfy.c b/crypto/cmp/cmp_vfy.c index b9951045c2e8..47bf38b2af5d 100644 --- a/crypto/cmp/cmp_vfy.c +++ b/crypto/cmp/cmp_vfy.c @@ -34,7 +34,8 @@ static int verify_signature(const OSSL_CMP_CTX *cmp_ctx, return 0; bio = BIO_new(BIO_s_mem()); /* may be NULL */ - + if (bio == NULL) + return 0; /* verify that keyUsage, if present, contains digitalSignature */ if (!cmp_ctx->ignore_keyusage && (X509_get_key_usage(cert) & X509v3_KU_DIGITAL_SIGNATURE) == 0) { @@ -138,6 +139,24 @@ int OSSL_CMP_validate_cert_path(const OSSL_CMP_CTX *ctx, return valid; } +static int verify_cb_cert(X509_STORE *ts, X509 *cert, int err) +{ + X509_STORE_CTX_verify_cb verify_cb; + X509_STORE_CTX *csc; + int ok = 0; + + if (ts == NULL || (verify_cb = X509_STORE_get_verify_cb(ts)) == NULL) + return ok; + if ((csc = X509_STORE_CTX_new()) != NULL + && X509_STORE_CTX_init(csc, ts, cert, NULL)) { + X509_STORE_CTX_set_error(csc, err); + X509_STORE_CTX_set_current_cert(csc, cert); + ok = (*verify_cb)(0, csc); + } + X509_STORE_CTX_free(csc); + return ok; +} + /* Return 0 if expect_name != NULL and there is no matching actual_name */ static int check_name(const OSSL_CMP_CTX *ctx, int log_success, const char *actual_desc, const X509_NAME *actual_name, @@ -156,8 +175,8 @@ static int check_name(const OSSL_CMP_CTX *ctx, int log_success, str = X509_NAME_oneline(actual_name, NULL, 0); if (X509_NAME_cmp(actual_name, expect_name) == 0) { if (log_success && str != NULL) - ossl_cmp_log2(INFO, ctx, " subject matches %s: %s", expect_desc, - str); + ossl_cmp_log3(INFO, ctx, " %s matches %s: %s", + actual_desc, expect_desc, str); OPENSSL_free(str); return 1; } @@ -186,7 +205,7 @@ static int check_kid(const OSSL_CMP_CTX *ctx, ossl_cmp_warn(ctx, "missing Subject Key Identifier in certificate"); return 0; } - str = OPENSSL_buf2hexstr(ckid->data, ckid->length); + str = i2s_ASN1_OCTET_STRING(NULL, ckid); if (ASN1_OCTET_STRING_cmp(ckid, skid) == 0) { if (str != NULL) ossl_cmp_log1(INFO, ctx, " subjectKID matches senderKID: %s", str); @@ -197,7 +216,7 @@ static int check_kid(const OSSL_CMP_CTX *ctx, if (str != NULL) ossl_cmp_log1(INFO, ctx, " cert Subject Key Identifier = %s", str); OPENSSL_free(str); - if ((str = OPENSSL_buf2hexstr(skid->data, skid->length)) != NULL) + if ((str = i2s_ASN1_OCTET_STRING(NULL, skid)) != NULL) ossl_cmp_log1(INFO, ctx, " does not match senderKID = %s", str); OPENSSL_free(str); return 0; @@ -255,9 +274,14 @@ static int cert_acceptable(const OSSL_CMP_CTX *ctx, time_cmp = X509_cmp_timeframe(vpm, X509_get0_notBefore(cert), X509_get0_notAfter(cert)); if (time_cmp != 0) { + int err = time_cmp > 0 ? X509_V_ERR_CERT_HAS_EXPIRED + : X509_V_ERR_CERT_NOT_YET_VALID; + ossl_cmp_warn(ctx, time_cmp > 0 ? "cert has expired" : "cert is not yet valid"); - return 0; + if (ctx->log_cb != NULL /* logging not temporarily disabled */ + && verify_cb_cert(ts, cert, err) <= 0) + return 0; } if (!check_name(ctx, 1, @@ -353,7 +377,7 @@ static int check_msg_given_cert(const OSSL_CMP_CTX *ctx, X509 *cert, /*- * Try all certs in given list for verifying msg, normally or in 3GPP mode. * If already_checked1 == NULL then certs are assumed to be the msg->extraCerts. - * On success cache the found cert using ossl_cmp_ctx_set0_validatedSrvCert(). + * On success cache the found cert using ossl_cmp_ctx_set1_validatedSrvCert(). */ static int check_msg_with_certs(OSSL_CMP_CTX *ctx, const STACK_OF(X509) *certs, const char *desc, @@ -382,13 +406,7 @@ static int check_msg_with_certs(OSSL_CMP_CTX *ctx, const STACK_OF(X509) *certs, if (mode_3gpp ? check_cert_path_3gpp(ctx, msg, cert) : check_cert_path(ctx, ctx->trusted, cert)) { /* store successful sender cert for further msgs in transaction */ - if (!X509_up_ref(cert)) - return 0; - if (!ossl_cmp_ctx_set0_validatedSrvCert(ctx, cert)) { - X509_free(cert); - return 0; - } - return 1; + return ossl_cmp_ctx_set1_validatedSrvCert(ctx, cert); } } if (in_extraCerts && n_acceptable_certs == 0) @@ -399,21 +417,21 @@ static int check_msg_with_certs(OSSL_CMP_CTX *ctx, const STACK_OF(X509) *certs, /*- * Verify msg trying first ctx->untrusted, which should include extraCerts * at its front, then trying the trusted certs in truststore (if any) of ctx. - * On success cache the found cert using ossl_cmp_ctx_set0_validatedSrvCert(). + * On success cache the found cert using ossl_cmp_ctx_set1_validatedSrvCert(). */ static int check_msg_all_certs(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, int mode_3gpp) { int ret = 0; - if (mode_3gpp - && ((!ctx->permitTAInExtraCertsForIR - || OSSL_CMP_MSG_get_bodytype(msg) != OSSL_CMP_PKIBODY_IP))) + if (ctx->permitTAInExtraCertsForIR + && OSSL_CMP_MSG_get_bodytype(msg) == OSSL_CMP_PKIBODY_IP) + ossl_cmp_info(ctx, mode_3gpp ? + "normal mode failed; trying now 3GPP mode trusting extraCerts" + : "trying first normal mode using trust store"); + else if (mode_3gpp) return 0; - ossl_cmp_info(ctx, - mode_3gpp ? "normal mode failed; trying now 3GPP mode trusting extraCerts" - : "trying first normal mode using trust store"); if (check_msg_with_certs(ctx, msg->extraCerts, "extraCerts", NULL, NULL, msg, mode_3gpp)) return 1; @@ -426,25 +444,20 @@ static int check_msg_all_certs(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, : "no trusted store"); } else { STACK_OF(X509) *trusted = X509_STORE_get1_all_certs(ctx->trusted); + ret = check_msg_with_certs(ctx, trusted, mode_3gpp ? "self-issued extraCerts" : "certs in trusted store", msg->extraCerts, ctx->untrusted, msg, mode_3gpp); - sk_X509_pop_free(trusted, X509_free); + OSSL_STACK_OF_X509_free(trusted); } return ret; } -static int no_log_cb(const char *func, const char *file, int line, - OSSL_CMP_severity level, const char *msg) -{ - return 1; -} - /*- * Verify message signature with any acceptable and valid candidate cert. - * On success cache the found cert using ossl_cmp_ctx_set0_validatedSrvCert(). + * On success cache the found cert using ossl_cmp_ctx_set1_validatedSrvCert(). */ static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) { @@ -459,6 +472,7 @@ static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) if (sender == NULL || msg->body == NULL) return 0; /* other NULL cases already have been checked */ if (sender->type != GEN_DIRNAME) { + /* So far, only X509_NAME is supported */ ERR_raise(ERR_LIB_CMP, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED); return 0; } @@ -468,7 +482,7 @@ static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) /* enable clearing irrelevant errors in attempts to validate sender certs */ (void)ERR_set_mark(); - ctx->log_cb = no_log_cb; /* temporarily disable logging */ + ctx->log_cb = NULL; /* temporarily disable logging */ /* * try first cached scrt, used successfully earlier in same transaction, @@ -481,7 +495,7 @@ static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) return 1; } /* cached sender cert has shown to be no more successfully usable */ - (void)ossl_cmp_ctx_set0_validatedSrvCert(ctx, NULL); + (void)ossl_cmp_ctx_set1_validatedSrvCert(ctx, NULL); /* re-do the above check (just) for adding diagnostic information */ ossl_cmp_info(ctx, "trying to verify msg signature with previously validated cert"); @@ -500,8 +514,7 @@ static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) (void)ERR_clear_last_mark(); sname = X509_NAME_oneline(sender->d.directoryName, NULL, 0); - skid_str = skid == NULL ? NULL - : OPENSSL_buf2hexstr(skid->data, skid->length); + skid_str = skid == NULL ? NULL : i2s_ASN1_OCTET_STRING(NULL, skid); if (ctx->log_cb != NULL) { ossl_cmp_info(ctx, "trying to verify msg signature with a valid cert that.."); if (sname != NULL) @@ -537,7 +550,7 @@ static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) * the sender certificate can have been pinned by providing it in ctx->srvCert, * else it is searched in msg->extraCerts, ctx->untrusted, in ctx->trusted * (in this order) and is path is validated against ctx->trusted. - * On success cache the found cert using ossl_cmp_ctx_set0_validatedSrvCert(). + * 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 @@ -599,7 +612,7 @@ int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) break; } ossl_cmp_debug(ctx, - "sucessfully validated PBM-based CMP message protection"); + "successfully validated PBM-based CMP message protection"); return 1; } ossl_cmp_warn(ctx, "verifying PBM-based CMP message protection failed"); @@ -624,15 +637,17 @@ int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_TRUST_ANCHOR); return 0; } - if (check_msg_find_cert(ctx, msg)) + if (check_msg_find_cert(ctx, msg)) { + ossl_cmp_debug(ctx, + "successfully validated signature-based CMP message protection using trust store"); return 1; + } } else { /* use pinned sender cert */ /* use ctx->srvCert for signature check even if not acceptable */ if (verify_signature(ctx, msg, scrt)) { ossl_cmp_debug(ctx, - "sucessfully validated signature-based CMP message protection"); - - return 1; + "successfully validated signature-based CMP message protection using pinned server cert"); + return ossl_cmp_ctx_set1_validatedSrvCert(ctx, scrt); } ossl_cmp_warn(ctx, "CMP message signature verification failed"); ERR_raise(ERR_LIB_CMP, CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG); @@ -642,12 +657,35 @@ int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg) return 0; } +static int check_transactionID_or_nonce(ASN1_OCTET_STRING *expected, + ASN1_OCTET_STRING *actual, int reason) +{ + if (expected != NULL + && (actual == NULL || ASN1_OCTET_STRING_cmp(expected, actual) != 0)) { +#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + char *expected_str, *actual_str; + + expected_str = i2s_ASN1_OCTET_STRING(NULL, expected); + actual_str = actual == NULL ? NULL: i2s_ASN1_OCTET_STRING(NULL, actual); + ERR_raise_data(ERR_LIB_CMP, reason, + "expected = %s, actual = %s", + expected_str == NULL ? "?" : expected_str, + actual == NULL ? "(none)" : + actual_str == NULL ? "?" : actual_str); + OPENSSL_free(expected_str); + OPENSSL_free(actual_str); + return 0; +#endif + } + return 1; +} + /*- * Check received message (i.e., response by server or request from client) * Any msg->extraCerts are prepended to ctx->untrusted. * * Ensures that: - * its sender is of appropriate type (curently only X509_NAME) and + * its sender is of appropriate type (currently only X509_NAME) and * matches any expected sender or srvCert subject given in the ctx * it has a valid body type * its protection is valid (or invalid/absent, but only if a callback function @@ -667,68 +705,94 @@ int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, { OSSL_CMP_PKIHEADER *hdr; const X509_NAME *expected_sender; + int num_untrusted, num_added, res; if (!ossl_assert(ctx != NULL && msg != NULL && msg->header != NULL)) return 0; hdr = OSSL_CMP_MSG_get0_header(msg); - /* validate sender name of received msg */ - if (hdr->sender->type != GEN_DIRNAME) { - ERR_raise(ERR_LIB_CMP, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED); - return 0; - } - /* - * Compare actual sender name of response with expected sender name. - * Mitigates risk to accept misused PBM secret - * or misused certificate of an unauthorized entity of a trusted hierarchy. - */ + /* If expected_sender is given, validate sender name of received msg */ expected_sender = ctx->expected_sender; if (expected_sender == NULL && ctx->srvCert != NULL) expected_sender = X509_get_subject_name(ctx->srvCert); - if (!check_name(ctx, 0, "sender DN field", hdr->sender->d.directoryName, - "expected sender", expected_sender)) - return 0; + if (expected_sender != NULL) { + const X509_NAME *actual_sender; + char *str; + + if (hdr->sender->type != GEN_DIRNAME) { + ERR_raise(ERR_LIB_CMP, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED); + return 0; + } + actual_sender = hdr->sender->d.directoryName; + /* + * Compare actual sender name of response with expected sender name. + * Mitigates risk of accepting misused PBM secret or + * misused certificate of an unauthorized entity of a trusted hierarchy. + */ + if (!check_name(ctx, 0, "sender DN field", actual_sender, + "expected sender", expected_sender)) { + str = X509_NAME_oneline(actual_sender, NULL, 0); + ERR_raise_data(ERR_LIB_CMP, CMP_R_UNEXPECTED_SENDER, + str != NULL ? str : "<unknown>"); + OPENSSL_free(str); + return 0; + } + } /* Note: if recipient was NULL-DN it could be learned here if needed */ - if (sk_X509_num(msg->extraCerts) > 10) - ossl_cmp_warn(ctx, - "received CMP message contains more than 10 extraCerts"); + num_added = sk_X509_num(msg->extraCerts); + if (num_added > 10) + ossl_cmp_log1(WARN, ctx, "received CMP message contains %d extraCerts", + num_added); /* * Store any provided extraCerts in ctx for use in OSSL_CMP_validate_msg() * and for future use, such that they are available to ctx->certConf_cb and * the peer does not need to send them again in the same transaction. * Note that it does not help validating the message before storing the * extraCerts because they do not belong to the protected msg part anyway. - * For efficiency, the extraCerts are prepended so they get used first. + * The extraCerts are prepended. Allows simple removal if they shall not be + * cached. Also they get used first, which is likely good for efficiency. */ - if (!X509_add_certs(ctx->untrusted, msg->extraCerts, - /* this allows self-signed certs */ - X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP - | X509_ADD_FLAG_PREPEND)) + num_untrusted = ctx->untrusted == NULL ? 0 : sk_X509_num(ctx->untrusted); + res = ossl_x509_add_certs_new(&ctx->untrusted, msg->extraCerts, + /* this allows self-signed certs */ + X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP + | X509_ADD_FLAG_PREPEND); + num_added = (ctx->untrusted == NULL ? 0 : sk_X509_num(ctx->untrusted)) + - num_untrusted; + if (!res) { + while (num_added-- > 0) + X509_free(sk_X509_shift(ctx->untrusted)); return 0; + } - /* validate message protection */ - if (hdr->protectionAlg != NULL) { - /* detect explicitly permitted exceptions for invalid protection */ - if (!OSSL_CMP_validate_msg(ctx, msg) - && (cb == NULL || (*cb)(ctx, msg, 1, cb_arg) <= 0)) { -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION); - return 0; + if (hdr->protectionAlg != NULL) + res = OSSL_CMP_validate_msg(ctx, msg) + /* explicitly permitted exceptions for invalid protection: */ + || (cb != NULL && (*cb)(ctx, msg, 1, cb_arg) > 0); + else + /* explicitly permitted exceptions for missing protection: */ + res = cb != NULL && (*cb)(ctx, msg, 0, cb_arg) > 0; +#ifdef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + res = 1; /* support more aggressive fuzzing by letting invalid msg pass */ #endif - } - } else { - /* detect explicitly permitted exceptions for missing protection */ - if (cb == NULL || (*cb)(ctx, msg, 0, cb_arg) <= 0) { -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION + + /* remove extraCerts again if not caching */ + if (ctx->noCacheExtraCerts) + while (num_added-- > 0) + X509_free(sk_X509_shift(ctx->untrusted)); + + if (!res) { + if (hdr->protectionAlg != NULL) + ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_VALIDATING_PROTECTION); + else ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_PROTECTION); - return 0; -#endif - } + return 0; } /* check CMP version number in header */ - if (ossl_cmp_hdr_get_pvno(hdr) != OSSL_CMP_PVNO) { + if (ossl_cmp_hdr_get_pvno(hdr) != OSSL_CMP_PVNO_2 + && ossl_cmp_hdr_get_pvno(hdr) != OSSL_CMP_PVNO_3) { #ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION ERR_raise(ERR_LIB_CMP, CMP_R_UNEXPECTED_PVNO); return 0; @@ -743,26 +807,30 @@ int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, } /* compare received transactionID with the expected one in previous msg */ - if (ctx->transactionID != NULL - && (hdr->transactionID == NULL - || ASN1_OCTET_STRING_cmp(ctx->transactionID, - hdr->transactionID) != 0)) { -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - ERR_raise(ERR_LIB_CMP, CMP_R_TRANSACTIONID_UNMATCHED); + if (!check_transactionID_or_nonce(ctx->transactionID, hdr->transactionID, + CMP_R_TRANSACTIONID_UNMATCHED)) return 0; -#endif - } + /* + * enable clearing irrelevant errors + * in attempts to validate recipient nonce in case of delayed delivery. + */ + (void)ERR_set_mark(); /* compare received nonce with the one we sent */ - if (ctx->senderNonce != NULL - && (msg->header->recipNonce == NULL - || ASN1_OCTET_STRING_cmp(ctx->senderNonce, - hdr->recipNonce) != 0)) { -#ifndef FUZZING_BUILD_MODE_UNSAFE_FOR_PRODUCTION - ERR_raise(ERR_LIB_CMP, CMP_R_RECIPNONCE_UNMATCHED); - return 0; -#endif + if (!check_transactionID_or_nonce(ctx->senderNonce, hdr->recipNonce, + CMP_R_RECIPNONCE_UNMATCHED)) { + /* check if we are polling and received final response */ + if (ctx->first_senderNonce == NULL + || OSSL_CMP_MSG_get_bodytype(msg) == OSSL_CMP_PKIBODY_POLLREP + /* compare received nonce with our sender nonce at poll start */ + || !check_transactionID_or_nonce(ctx->first_senderNonce, + hdr->recipNonce, + CMP_R_RECIPNONCE_UNMATCHED)) { + (void)ERR_clear_last_mark(); + return 0; + } } + (void)ERR_pop_to_mark(); /* if not yet present, learn transactionID */ if (ctx->transactionID == NULL @@ -777,18 +845,6 @@ int ossl_cmp_msg_check_update(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, if (!ossl_cmp_ctx_set1_recipNonce(ctx, hdr->senderNonce)) return 0; - /* - * Store any provided extraCerts in ctx for future use, - * such that they are available to ctx->certConf_cb and - * the peer does not need to send them again in the same transaction. - * For efficiency, the extraCerts are prepended so they get used first. - */ - if (!X509_add_certs(ctx->untrusted, msg->extraCerts, - /* this allows self-signed certs */ - X509_ADD_FLAG_UP_REF | X509_ADD_FLAG_NO_DUP - | X509_ADD_FLAG_PREPEND)) - return 0; - if (ossl_cmp_hdr_get_protection_nid(hdr) == NID_id_PasswordBasedMAC) { /* * RFC 4210, 5.3.2: 'Note that if the PKI Message Protection is |
