summaryrefslogtreecommitdiffstats
path: root/crypto/cmp/cmp_asn.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/cmp/cmp_asn.c')
-rw-r--r--crypto/cmp/cmp_asn.c289
1 files changed, 276 insertions, 13 deletions
diff --git a/crypto/cmp/cmp_asn.c b/crypto/cmp/cmp_asn.c
index 3049d4f080..f20e5098ca 100644
--- a/crypto/cmp/cmp_asn.c
+++ b/crypto/cmp/cmp_asn.c
@@ -120,6 +120,11 @@ ASN1_ADB(OSSL_CMP_ITAV) = {
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);
@@ -138,6 +143,20 @@ ASN1_SEQUENCE(OSSL_CMP_ROOTCAKEYUPDATE) = {
} ASN1_SEQUENCE_END(OSSL_CMP_ROOTCAKEYUPDATE)
IMPLEMENT_ASN1_FUNCTIONS(OSSL_CMP_ROOTCAKEYUPDATE)
+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;
@@ -287,23 +306,30 @@ OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_rootCaKeyUpdate(const X509 *newWithNew,
const X509 *oldWithNew)
{
OSSL_CMP_ITAV *itav;
- OSSL_CMP_ROOTCAKEYUPDATE *upd = OSSL_CMP_ROOTCAKEYUPDATE_new();
+ 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 (upd == NULL)
- return NULL;
- if (newWithNew != NULL && (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:
+ err:
OSSL_CMP_ROOTCAKEYUPDATE_free(upd);
return NULL;
}
@@ -324,11 +350,248 @@ int OSSL_CMP_ITAV_get0_rootCaKeyUpdate(const OSSL_CMP_ITAV *itav,
return 0;
}
upd = itav->infoValue.rootCaKeyUpdate;
- *newWithNew = upd->newWithNew;
+ *newWithNew = upd != NULL ? upd->newWithNew : NULL;
if (newWithOld != NULL)
- *newWithOld = upd->newWithOld;
+ *newWithOld = upd != NULL ? upd->newWithOld : NULL;
if (oldWithNew != NULL)
- *oldWithNew = upd->oldWithNew;
+ *oldWithNew = upd != NULL ? upd->oldWithNew : NULL;
+ return 1;
+}
+
+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)
+ goto err;
+ (void)sk_X509_CRL_push(crls, crl_copy); /* cannot fail */
+ }
+
+ itav->infoType = OBJ_nid2obj(NID_id_it_crls);
+ itav->infoValue.crls = crls;
+ return itav;
+
+ err:
+ 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;
}