diff --git a/apps/cmp.c b/apps/cmp.c index 7639ab2cf8b22..a853913d0306f 100644 --- a/apps/cmp.c +++ b/apps/cmp.c @@ -97,6 +97,8 @@ static char *opt_oldwithnew = NULL; static char *opt_crlcert = NULL; static char *opt_oldcrl = NULL; static char *opt_crlout = NULL; +static char *opt_template = NULL; +static char *opt_keyspec = NULL; /* client authentication */ static char *opt_ref = NULL; @@ -225,6 +227,7 @@ typedef enum OPTION_choice { OPT_CONFIG, OPT_SECTION, OPT_VERBOSITY, OPT_CMD, OPT_INFOTYPE, OPT_PROFILE, OPT_GENINFO, + OPT_TEMPLATE, OPT_KEYSPEC, OPT_NEWKEY, OPT_NEWKEYPASS, OPT_SUBJECT, OPT_DAYS, OPT_REQEXTS, @@ -313,6 +316,10 @@ const OPTIONS cmp_options[] = { "Comma-separated list of OID and value to place in generalInfo PKIHeader"}, {OPT_MORE_STR, 0, 0, "of form :int: or :str:, e.g. \'1.2.3.4:int:56789, id-kp:str:name'"}, + { "template", OPT_TEMPLATE, 's', + "File to save certTemplate received in genp of type certReqTemplate"}, + { "keyspec", OPT_KEYSPEC, 's', + "Optional file to save Key specification received in genp of type certReqTemplate"}, OPT_SECTION("Certificate enrollment"), {"newkey", OPT_NEWKEY, 's', @@ -620,6 +627,7 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */ {&opt_config}, {&opt_section}, {(char **)&opt_verbosity}, {&opt_cmd_s}, {&opt_infotype_s}, {&opt_profile}, {&opt_geninfo}, + {&opt_template}, {&opt_keyspec}, {&opt_newkey}, {&opt_newkeypass}, {&opt_subject}, {(char **)&opt_days}, {&opt_reqexts}, @@ -2176,6 +2184,14 @@ static int setup_client_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) if (opt_oldwithnew != NULL) CMP_warn1("-oldwithnew %s", msg); } + if (opt_cmd != CMP_GENM || opt_infotype != NID_id_it_certReqTemplate) { + const char *msg = "option is ignored unless -cmd 'genm' and -infotype 'certReqTemplate' is given"; + + if (opt_template != NULL) + CMP_warn1("-template %s", msg); + if (opt_keyspec != NULL) + CMP_warn1("-keyspec %s", msg); + } if (!setup_verification_ctx(ctx)) goto err; @@ -2420,6 +2436,57 @@ static int save_crl_or_delete(X509_CRL *crl, const char *file, const char *desc) return (crl == NULL) ? delete_file(file, desc) : save_crl(crl, file, desc); } +static int save_template(const char *file, const OSSL_CRMF_CERTTEMPLATE *tmpl) +{ + BIO *bio = BIO_new_file(file, "wb"); + + if (bio == NULL) { + CMP_err1("error saving certTemplate from genp: cannot open file %s", + file); + return 0; + } + if (!ASN1_i2d_bio_of(OSSL_CRMF_CERTTEMPLATE, i2d_OSSL_CRMF_CERTTEMPLATE, + bio, tmpl)) { + CMP_err1("error saving certTemplate from genp: cannot write file %s", + file); + return 0; + } else { + CMP_info1("stored certTemplate from genp to file '%s'", file); + } + BIO_free(bio); + return 1; +} + +static int save_keyspec(const char *file, const OSSL_CMP_ATAVS *keyspec) +{ + BIO *bio = BIO_new_file(file, "wb"); + + if (bio == NULL) { + CMP_err1("error saving keySpec from genp: cannot open file %s", file); + return 0; + } + + if (!ASN1_i2d_bio_of(OSSL_CMP_ATAVS, i2d_OSSL_CMP_ATAVS, bio, keyspec)) { + CMP_err1("error saving keySpec from genp: cannot write file %s", file); + return 0; + } else { + CMP_info1("stored keySpec from genp to file '%s'", file); + } + BIO_free(bio); + return 1; +} + +static const char *nid_name(int nid) +{ + const char *name = OBJ_nid2ln(nid); + + if (name == NULL) + name = OBJ_nid2sn(nid); + if (name == NULL) + name = ""; + return name; +} + static int print_itavs(const STACK_OF(OSSL_CMP_ITAV) *itavs) { int i, ret = 1; @@ -2845,6 +2912,12 @@ static int get_opts(int argc, char **argv) case OPT_GENINFO: opt_geninfo = opt_str(); break; + case OPT_TEMPLATE: + opt_template = opt_str(); + break; + case OPT_KEYSPEC: + opt_keyspec = opt_str(); + break; case OPT_NEWKEY: opt_newkey = opt_str(); @@ -3154,6 +3227,69 @@ static int cmp_server(OSSL_CMP_CTX *srv_cmp_ctx) } #endif +static void print_keyspec(OSSL_CMP_ATAVS *keySpec) +{ + const char *desc = "specifications contained in keySpec from genp"; + BIO *mem; + int i; + const char *p; + long len; + + if (keySpec == NULL) + return; + + mem = BIO_new(BIO_s_mem()); + if (mem == NULL) { + CMP_err1("Out of memory - cannot dump key %s", desc); + return; + } + BIO_printf(mem, "Key %s:\n", desc); + + for (i = 0; i < sk_OSSL_CMP_ATAV_num(keySpec); i++) { + OSSL_CMP_ATAV *atav = sk_OSSL_CMP_ATAV_value(keySpec, i); + ASN1_OBJECT *type = OSSL_CMP_ATAV_get0_type(atav /* may be NULL */); + int nid = OBJ_obj2nid(type); + + switch (nid) { + case NID_id_regCtrl_algId: + { + X509_ALGOR *alg = OSSL_CMP_ATAV_get0_algId(atav); + const ASN1_OBJECT *oid; + int paramtype; + const void *param; + + X509_ALGOR_get0(&oid, ¶mtype, ¶m, alg); + BIO_printf(mem, "Key algorithm: "); + i2a_ASN1_OBJECT(mem, oid); + if (paramtype == V_ASN1_UNDEF || alg->parameter == NULL) { + BIO_printf(mem, "\n"); + } else { + BIO_printf(mem, " - "); + ASN1_item_print(mem, (ASN1_VALUE *)alg, + 0, ASN1_ITEM_rptr(X509_ALGOR), NULL); + } + } + break; + case NID_id_regCtrl_rsaKeyLen: + BIO_printf(mem, "Key algorithm: RSA %d bit\n", + OSSL_CMP_ATAV_get_rsaKeyLen(atav)); + break; + default: + BIO_printf(mem, "Invalid key spec: %s\n", nid_name(nid)); + break; + } + } + BIO_printf(mem, "End of key %s", desc); + + len = BIO_get_mem_data(mem, &p); + if (len > INT_MAX) + CMP_err1("Info too large - cannot dump key %s", desc); + else + CMP_info2("%.*s", (int)len, p); + BIO_free(mem); + return; +} + static void print_status(void) { /* print PKIStatusInfo */ @@ -3300,6 +3436,38 @@ static int do_genm(OSSL_CMP_CTX *ctx) X509_CRL_free(crl); return res; + } else if (opt_infotype == NID_id_it_certReqTemplate) { + OSSL_CRMF_CERTTEMPLATE *certTemplate; + OSSL_CMP_ATAVS *keySpec; + int res = 0; + + if (!OSSL_CMP_get1_certReqTemplate(ctx, &certTemplate, &keySpec)) + return 0; + + if (certTemplate == NULL) { + CMP_warn("no certificate request template available"); + if (!delete_file(opt_template, "certTemplate from genp")) + return 0; + return 1; + } + if (!save_template(opt_template, certTemplate)) + goto tmpl_end; + + if (opt_keyspec != NULL) { + if (keySpec == NULL) { + CMP_warn("no key specifications available"); + if (!delete_file(opt_keyspec, "keySpec from genp")) + goto tmpl_end; + } else if (!save_keyspec(opt_keyspec, keySpec)) { + goto tmpl_end; + } + } + print_keyspec(keySpec); + res = 1; + tmpl_end: + OSSL_CRMF_CERTTEMPLATE_free(certTemplate); + sk_OSSL_CMP_ATAV_pop_free(keySpec, OSSL_CMP_ATAV_free); + return res; } else { OSSL_CMP_ITAV *req; STACK_OF(OSSL_CMP_ITAV) *itavs; diff --git a/apps/lib/cmp_mock_srv.c b/apps/lib/cmp_mock_srv.c index b69d29a678d64..128f971395f89 100644 --- a/apps/lib/cmp_mock_srv.c +++ b/apps/lib/cmp_mock_srv.c @@ -451,7 +451,7 @@ static int check_client_crl(const STACK_OF(OSSL_CMP_CRLSTATUS) *crlStatusList, static OSSL_CMP_ITAV *process_genm_itav(mock_srv_ctx *ctx, int req_nid, const OSSL_CMP_ITAV *req) { - OSSL_CMP_ITAV *rsp; + OSSL_CMP_ITAV *rsp = NULL; switch (req_nid) { case NID_id_it_caCerts: @@ -490,6 +490,43 @@ static OSSL_CMP_ITAV *process_genm_itav(mock_srv_ctx *ctx, int req_nid, rsp = OSSL_CMP_ITAV_new_crls(res == 0 ? NULL : ctx->crlOut); } break; + case NID_id_it_certReqTemplate: + { + OSSL_CRMF_CERTTEMPLATE *reqtemp; + OSSL_CMP_ATAVS *keyspec = NULL; + X509_ALGOR *keyalg = NULL; + + if ((reqtemp = OSSL_CRMF_CERTTEMPLATE_new()) == NULL) + return NULL; + + if (!OSSL_CRMF_CERTTEMPLATE_fill(reqtemp, NULL, NULL, + X509_get_issuer_name(ctx->refCert), + NULL)) + goto crt_err; + + if ((keyspec = OSSL_CMP_ATAVS_new()) == NULL) + goto crt_err; + + if ((keyalg = X509_ALGOR_new()) == NULL) + goto crt_err; + + (void)X509_ALGOR_set0(keyalg, OBJ_nid2obj(NID_X9_62_id_ecPublicKey), + V_ASN1_UNDEF, NULL); /* cannot fail */ + + if (!sk_OSSL_CMP_ATAV_push(keyspec, OSSL_CMP_ATAV_new_algId(keyalg)) + || !sk_OSSL_CMP_ATAV_push(keyspec, + OSSL_CMP_ATAV_new_rsaKeyLen(4096))) + goto crt_err; + + rsp = OSSL_CMP_ITAV_new0_certReqTemplate(reqtemp, keyspec); + return rsp; + crt_err: + OSSL_CRMF_CERTTEMPLATE_free(reqtemp); + OSSL_CMP_ATAVS_free(keyspec); + X509_ALGOR_free(keyalg); + return NULL; + } + break; default: rsp = OSSL_CMP_ITAV_dup(req); } diff --git a/crypto/cmp/cmp_asn.c b/crypto/cmp/cmp_asn.c index f20e5098ca9ca..2f067cb73a83d 100644 --- a/crypto/cmp/cmp_asn.c +++ b/crypto/cmp/cmp_asn.c @@ -12,6 +12,7 @@ #include #include "cmp_local.h" +#include "internal/crmf.h" /* explicit #includes not strictly needed since implied by the above: */ #include @@ -117,6 +118,9 @@ ASN1_ADB(OSSL_CMP_ITAV) = { ADB_ENTRY(NID_id_it_rootCaKeyUpdate, ASN1_OPT(OSSL_CMP_ITAV, infoValue.rootCaKeyUpdate, OSSL_CMP_ROOTCAKEYUPDATE)), + ADB_ENTRY(NID_id_it_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)), @@ -143,6 +147,19 @@ ASN1_SEQUENCE(OSSL_CMP_ROOTCAKEYUPDATE) = { } 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), @@ -358,6 +375,222 @@ int OSSL_CMP_ITAV_get0_rootCaKeyUpdate(const OSSL_CMP_ITAV *itav, 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 *req; + + if (itav == NULL || certTemplate == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + + if (certTemplate != NULL) + *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; + } + req = itav->infoValue.certReqTemplate; + if (req == NULL) /* no requirements available */ + return 1; + + if ((*certTemplate = OSSL_CRMF_CERTTEMPLATE_dup(req->certTemplate)) == NULL) + return 0; + if (keySpec != NULL && req->keySpec != NULL) { + int i, n = sk_OSSL_CMP_ATAV_num(req->keySpec); + + *keySpec = sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_new_reserve(NULL, n); + if (*keySpec == NULL) + return 0; + for (i = 0; i < n; i++) { + OSSL_CMP_ATAV *atav = sk_OSSL_CMP_ATAV_value(req->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 = ""; + ERR_raise_data(ERR_LIB_CMP, CMP_R_INVALID_KEYSPEC, + "keySpec with index %d in certReqTemplate has invalid type %s", + i, name); + goto err; + } + sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_push(*keySpec, atav); + sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_set(req->keySpec, i, NULL); + } + } + 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) { diff --git a/crypto/cmp/cmp_err.c b/crypto/cmp/cmp_err.c index 689aa6a9520f7..5cec9438f6145 100644 --- a/crypto/cmp/cmp_err.c +++ b/crypto/cmp/cmp_err.c @@ -85,12 +85,15 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { "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"}, diff --git a/crypto/cmp/cmp_genm.c b/crypto/cmp/cmp_genm.c index 17f2f1d3acc57..c68cddad05f01 100644 --- a/crypto/cmp/cmp_genm.c +++ b/crypto/cmp/cmp_genm.c @@ -406,3 +406,36 @@ int OSSL_CMP_get1_crlUpdate(OSSL_CMP_CTX *ctx, const X509 *crlcert, OSSL_CMP_ITAV_free(itav); return res; } + +int OSSL_CMP_get1_certReqTemplate(OSSL_CMP_CTX *ctx, + OSSL_CRMF_CERTTEMPLATE **certTemplate, + OSSL_CMP_ATAVS **keySpec) +{ + OSSL_CMP_ITAV *req, *itav = NULL; + int res = 0; + + if (keySpec != NULL) + *keySpec = NULL; + if (certTemplate == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT); + return 0; + } + *certTemplate = NULL; + + if ((req = OSSL_CMP_ITAV_new0_certReqTemplate(NULL, NULL)) == NULL) { + ERR_raise(ERR_LIB_CMP, CMP_R_GENERATE_CERTREQTEMPLATE); + return 0; + } + + if ((itav = get_genm_itav(ctx, req, NID_id_it_certReqTemplate, + "certReqTemplate")) == NULL) + return 0; + + if (!OSSL_CMP_ITAV_get1_certReqTemplate(itav, certTemplate, keySpec)) + goto end; + + res = 1; + end: + OSSL_CMP_ITAV_free(itav); + return res; +} diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h index 9ebd1858a5574..597080379701e 100644 --- a/crypto/cmp/cmp_local.h +++ b/crypto/cmp/cmp_local.h @@ -294,6 +294,8 @@ struct ossl_cmp_itav_st { 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 */ @@ -800,6 +802,17 @@ struct ossl_cmp_rootcakeyupdate_st { } /* 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); diff --git a/crypto/crmf/crmf_asn.c b/crypto/crmf/crmf_asn.c index 85b4213934a92..f1b2df365e8a8 100644 --- a/crypto/crmf/crmf_asn.c +++ b/crypto/crmf/crmf_asn.c @@ -152,6 +152,12 @@ ASN1_ADB(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) = { ADB_ENTRY(NID_id_regInfo_certReq, ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, value.certReq, OSSL_CRMF_CERTREQUEST)), + ADB_ENTRY(NID_id_regCtrl_algId, + ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, + value.algId, X509_ALGOR)), + ADB_ENTRY(NID_id_regCtrl_rsaKeyLen, + ASN1_SIMPLE(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, + value.rsaKeyLen, ASN1_INTEGER)), } ASN1_ADB_END(OSSL_CRMF_ATTRIBUTETYPEANDVALUE, 0, type, 0, &attributetypeandvalue_default_tt, NULL); @@ -194,6 +200,7 @@ ASN1_SEQUENCE(OSSL_CRMF_CERTTEMPLATE) = { X509_EXTENSION, 9), } ASN1_SEQUENCE_END(OSSL_CRMF_CERTTEMPLATE) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_CERTTEMPLATE) +IMPLEMENT_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTTEMPLATE) ASN1_SEQUENCE(OSSL_CRMF_CERTREQUEST) = { ASN1_SIMPLE(OSSL_CRMF_CERTREQUEST, certReqId, ASN1_INTEGER), diff --git a/crypto/crmf/crmf_local.h b/crypto/crmf/crmf_local.h index e8937b4231e64..cfa01ab3992cf 100644 --- a/crypto/crmf/crmf_local.h +++ b/crypto/crmf/crmf_local.h @@ -16,6 +16,7 @@ # include # include +# include "internal/crmf.h" /* for ossl_crmf_attributetypeandvalue_st */ /* explicit #includes not strictly needed since implied by the above: */ # include @@ -335,37 +336,6 @@ struct ossl_crmf_certrequest_st { DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_CERTREQUEST) DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTREQUEST) -struct ossl_crmf_attributetypeandvalue_st { - ASN1_OBJECT *type; - union { - /* NID_id_regCtrl_regToken */ - ASN1_UTF8STRING *regToken; - - /* NID_id_regCtrl_authenticator */ - ASN1_UTF8STRING *authenticator; - - /* NID_id_regCtrl_pkiPublicationInfo */ - OSSL_CRMF_PKIPUBLICATIONINFO *pkiPublicationInfo; - - /* NID_id_regCtrl_oldCertID */ - OSSL_CRMF_CERTID *oldCertID; - - /* NID_id_regCtrl_protocolEncrKey */ - X509_PUBKEY *protocolEncrKey; - - /* NID_id_regInfo_utf8Pairs */ - ASN1_UTF8STRING *utf8Pairs; - - /* NID_id_regInfo_certReq */ - OSSL_CRMF_CERTREQUEST *certReq; - - ASN1_TYPE *other; - } value; -} /* OSSL_CRMF_ATTRIBUTETYPEANDVALUE */; -DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) -DEFINE_STACK_OF(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) -DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) - /*- * CertReqMessages ::= SEQUENCE SIZE (1..MAX) OF CertReqMsg * CertReqMsg ::= SEQUENCE { diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 5102c481e34af..7663af0dfd97b 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -234,11 +234,13 @@ CMP_R_FAILED_BUILDING_OWN_CHAIN:164:failed building own chain CMP_R_FAILED_EXTRACTING_PUBKEY:141:failed extracting pubkey CMP_R_FAILURE_OBTAINING_RANDOM:110:failure obtaining random CMP_R_FAIL_INFO_OUT_OF_RANGE:129:fail info out of range +CMP_R_GENERATE_CERTREQTEMPLATE:197:generate certreqtemplate CMP_R_GENERATE_CRLSTATUS:198:error creating crlstatus CMP_R_GETTING_GENP:192:getting genp CMP_R_GET_ITAV:199:get itav CMP_R_INVALID_ARGS:100:invalid args CMP_R_INVALID_GENP:193:invalid genp +CMP_R_INVALID_KEYSPEC:202:invalid keyspec CMP_R_INVALID_OPTION:174:invalid option CMP_R_INVALID_ROOTCAKEYUPDATE:195:invalid rootcakeyupdate CMP_R_MISSING_CERTID:165:missing certid diff --git a/doc/build.info b/doc/build.info index 3214d0843b474..aedfd93ecd726 100644 --- a/doc/build.info +++ b/doc/build.info @@ -1595,6 +1595,10 @@ DEPEND[html/man3/OSSL_CALLBACK.html]=man3/OSSL_CALLBACK.pod GENERATE[html/man3/OSSL_CALLBACK.html]=man3/OSSL_CALLBACK.pod DEPEND[man/man3/OSSL_CALLBACK.3]=man3/OSSL_CALLBACK.pod GENERATE[man/man3/OSSL_CALLBACK.3]=man3/OSSL_CALLBACK.pod +DEPEND[html/man3/OSSL_CMP_ATAV_set0.html]=man3/OSSL_CMP_ATAV_set0.pod +GENERATE[html/man3/OSSL_CMP_ATAV_set0.html]=man3/OSSL_CMP_ATAV_set0.pod +DEPEND[man/man3/OSSL_CMP_ATAV_set0.3]=man3/OSSL_CMP_ATAV_set0.pod +GENERATE[man/man3/OSSL_CMP_ATAV_set0.3]=man3/OSSL_CMP_ATAV_set0.pod DEPEND[html/man3/OSSL_CMP_CTX_new.html]=man3/OSSL_CMP_CTX_new.pod GENERATE[html/man3/OSSL_CMP_CTX_new.html]=man3/OSSL_CMP_CTX_new.pod DEPEND[man/man3/OSSL_CMP_CTX_new.3]=man3/OSSL_CMP_CTX_new.pod @@ -3366,6 +3370,7 @@ html/man3/OPENSSL_secure_malloc.html \ html/man3/OPENSSL_strcasecmp.html \ html/man3/OSSL_ALGORITHM.html \ html/man3/OSSL_CALLBACK.html \ +html/man3/OSSL_CMP_ATAV_set0.html \ html/man3/OSSL_CMP_CTX_new.html \ html/man3/OSSL_CMP_HDR_get0_transactionID.html \ html/man3/OSSL_CMP_ITAV_new_caCerts.html \ @@ -4020,6 +4025,7 @@ man/man3/OPENSSL_secure_malloc.3 \ man/man3/OPENSSL_strcasecmp.3 \ man/man3/OSSL_ALGORITHM.3 \ man/man3/OSSL_CALLBACK.3 \ +man/man3/OSSL_CMP_ATAV_set0.3 \ man/man3/OSSL_CMP_CTX_new.3 \ man/man3/OSSL_CMP_HDR_get0_transactionID.3 \ man/man3/OSSL_CMP_ITAV_new_caCerts.3 \ diff --git a/doc/man1/openssl-cmp.pod.in b/doc/man1/openssl-cmp.pod.in index 5b36e821befdf..1a996a9af85a2 100644 --- a/doc/man1/openssl-cmp.pod.in +++ b/doc/man1/openssl-cmp.pod.in @@ -19,6 +19,8 @@ Generic message options: [B<-infotype> I] [B<-profile> I] [B<-geninfo> I] +[B<-template> I] +[B<-keyspec> I] Certificate enrollment options: @@ -268,6 +270,18 @@ Each InfoTypeAndValue gives an OID and an integer or string value of the form I:int:I or I:str:I, e.g., C<'1.2.3.4:int:56789, id-kp:str:name'>. +=item B<-template> I + +The file to save any CRMF certTemplate in DER format +received in a genp message with id-it-certReqTemplate. + +=item B<-keyspec> I + +It is optioanl and used to specify the file to save any keySpec if +present in a genp message with id-it-keyGenParameters. + +Note: any keySpec field contents received are logged as INFO. + =back =head2 Certificate enrollment options diff --git a/doc/man3/OSSL_CMP_ATAV_set0.pod b/doc/man3/OSSL_CMP_ATAV_set0.pod new file mode 100644 index 0000000000000..4df639e1af8dc --- /dev/null +++ b/doc/man3/OSSL_CMP_ATAV_set0.pod @@ -0,0 +1,129 @@ +=pod + +=head1 NAME + +OSSL_CMP_ATAV, +OSSL_CMP_ATAV_create, +OSSL_CMP_ATAV_set0, +OSSL_CMP_ATAV_get0_type, +OSSL_CMP_ATAV_get0_value, +OSSL_CMP_ATAV_new_algId, +OSSL_CMP_ATAV_get0_algId, +OSSL_CMP_ATAV_new_rsaKeyLen, +OSSL_CMP_ATAV_get_rsaKeyLen, +OSSL_CMP_ATAVS, +OSSL_CMP_ATAV_push1, +OSSL_CMP_ATAV_free, +OSSL_CMP_ATAVS_new, +OSSL_CMP_ATAVS_free, +OSSL_CMP_ATAVS_it, +d2i_OSSL_CMP_ATAVS, +i2d_OSSL_CMP_ATAVS +- OSSL_CMP_ATAV utility functions + +=head1 SYNOPSIS + + #include + + typedef OSSL_CRMF_ATTRIBUTETYPEANDVALUE OSSL_CMP_ATAV; + OSSL_CMP_ATAV *OSSL_CMP_ATAV_create(ASN1_OBJECT *type, ASN1_TYPE *value); + void OSSL_CMP_ATAV_set0(OSSL_CMP_ATAV *atav, ASN1_OBJECT *type, + ASN1_TYPE *value); + ASN1_OBJECT *OSSL_CMP_ATAV_get0_type(const OSSL_CMP_ATAV *atav); + ASN1_TYPE *OSSL_CMP_ATAV_get0_value(const OSSL_CMP_ATAV *atav); + + OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_algId(const X509_ALGOR *alg); + X509_ALGOR *OSSL_CMP_ATAV_get0_algId(const OSSL_CMP_ATAV *atav); + OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_rsaKeyLen(int len); + int OSSL_CMP_ATAV_get_rsaKeyLen(const OSSL_CMP_ATAV *atav); + + typedef STACK_OF(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) OSSL_CMP_ATAVS; + int OSSL_CMP_ATAV_push1(OSSL_CMP_ATAVS **sk_p, const OSSL_CMP_ATAV *atav); + void OSSL_CMP_ATAV_free(OSSL_CMP_ATAV *atav); + + OSSL_CMP_ATAVS *OSSL_CMP_ATAVS_new(void); + void OSSL_CMP_ATAVS_free(OSSL_CMP_ATAVS *a); + const ASN1_ITEM * OSSL_CMP_ATAVS_it(void); + OSSL_CMP_ATAVS *d2i_OSSL_CMP_ATAVS(OSSL_CMP_ATAVS **a, const unsigned char **in, long len); + int i2d_OSSL_CMP_ATAVS(const OSSL_CMP_ATAVS *a, unsigned char **out); + +=head1 DESCRIPTION + +B is a short hand of B, +defined in RFC 4211 Appendix B. +It is typically used in CertRequest structures, +but also in CertReqTemplateContent structures for key specifications. + +OSSL_CMP_ATAV_create() creates a new B structure and fills it in. +It combines OSSL_CMP_ATAV_new() and OSSL_CMP_ATAV_set0(). + +OSSL_CMP_ATAV_set0() sets the I with an infoType of I and an +infoValue of I. +The pointers I and I may be NULL, otherwise +they must B be freed up after the call because they are used internally. +The I pointer must not be NULL. + +OSSL_CMP_ATAV_get0_type() returns a direct pointer to the infoType +in the I unless it is NULL. + +OSSL_CMP_ATAV_get0_value() returns a direct pointer to the infoValue +in the I as generic B pointer unless I is NULL. + +OSSL_CMP_ATAV_new_algId() creates a new B structure of type +B and fills it in with a copy of the given I. + +OSSL_CMP_ATAV_get0_algId() returns +a direct pointer to the algId infoValue in the I of type B +or NULL if I is NULL or does not contain an algId. + +OSSL_CMP_ATAV_new_rsaKeyLen() creates a new B structure of type +B and fills it in with the given I, which must be positive. + +OSSL_CMP_ATAV_get_rsaKeyLen() returns +the RSA key length in rsaKeyLen infoValue in the I, +-1 if I is NULL or does not contain an rsaKeyLen or cannot be parsed, +or -2 if the value is less than 0 or is greater than INT_MAX. + +OSSL_CMP_ATAV_push1() pushes a copy of I to the stack of B +pointed to by I<*sk_p>. It creates a new stack if I<*sk_p> points to NULL. + +OSSL_CMP_ATAV_free() deallocates I. It is defined as a macro. + +=head1 NOTES + +CMP is defined in RFC 4210. CRMF is defined in RFC 4211. + +=head1 RETURN VALUES + +OSSL_CMP_ATAV_create(), +OSSL_CMP_ATAV_new_algId(), and OSSL_CMP_ATAV_new_rsaKeyLen() +return a pointer to the ATAV structure on success, or NULL on error. + +OSSL_CMP_ATAV_set0() and OSSL_CMP_ATAV_free() do not return a value. + +OSSL_CMP_ATAV_get0_type(), OSSL_CMP_ATAV_get0_value(), and +OSSL_CMP_ATAV_get0_algId() +return the respective pointer or NULL if their input is NULL. + +OSSL_CMP_ATAV_get_rsaKeyLen() return a key length in bits or < 0 on error. + +OSSL_CMP_ATAV_push1() returns 1 on success, 0 on error. + +=head1 SEE ALSO + +L, L + +=head1 HISTORY + +The B type and related functions were added in OpenSSL 3.4. + +=head1 COPYRIGHT + +Copyright 2022 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 +in the file LICENSE in the source distribution or at +L. + +=cut diff --git a/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod b/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod index 209c56929e2e3..6fc1cf6f4f0ea 100644 --- a/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod +++ b/doc/man3/OSSL_CMP_ITAV_new_caCerts.pod @@ -14,7 +14,9 @@ OSSL_CMP_CRLSTATUS_get0, OSSL_CMP_ITAV_new0_crlStatusList, OSSL_CMP_ITAV_get0_crlStatusList, OSSL_CMP_ITAV_new_crls, -OSSL_CMP_ITAV_get0_crls +OSSL_CMP_ITAV_get0_crls, +OSSL_CMP_ITAV_new0_certReqTemplate, +OSSL_CMP_ITAV_get1_certReqTemplate - CMP utility functions for handling specific genm and genp messages =head1 SYNOPSIS @@ -48,6 +50,12 @@ OSSL_CMP_ITAV_get0_crls STACK_OF(OSSL_CMP_CRLSTATUS) **out); OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_crls(const X509_CRL *crl); int OSSL_CMP_ITAV_get0_crls(const OSSL_CMP_ITAV *itav, STACK_OF(X509_CRL) **out); + OSSL_CMP_ITAV + *OSSL_CMP_ITAV_new0_certReqTemplate(OSSL_CRMF_CERTTEMPLATE *certTemplate, + OSSL_CMP_ATAVS *keySpec); + int OSSL_CMP_ITAV_get1_certReqTemplate(const OSSL_CMP_ITAV *itav, + OSSL_CRMF_CERTTEMPLATE **certTemplate, + OSSL_CMP_ATAVS **keySpec); =head1 DESCRIPTION @@ -100,6 +108,27 @@ Data from I, if present, is preferred over data from I. If no distribution point names are available, candidate issuer names are taken from following sources, as far as present: +OSSL_CMP_ITAV_new0_certReqTemplate() creates an B structure +of type B. +If I is NULL then also I must be NULL, +and the resulting ITAV can be used in a B message to obtain the +requirements a PKI has on the certificate template used to request certificates, +or in a B message stating that there are no such requirements. +Otherwise the resulting ITAV includes a CertReqTemplateValue structure +with I of type B and an optional list +of key specifications I, each being of type B, and +the resulting ATAV can be used in a B message to provide requirements. + +OSSL_CMP_ITAV_get1_certReqTemplate() +requires that I has type B. +If assigns NULL to I<*certTemplate> if no B structure +with a certificate template value is in I, +otherwise a copy of the certTemplate field value. +If I is not NULL, it is assigned NULL +if the structure is not present in I or the keySpec field is absent. +Otherwise, the function checks that all elements of keySpec field are of type +B or B and assigns to I<*keySpec> a copy of the keySpec field. + =over 4 =item the list of distribution points in the first cRLDistributionPoints @@ -150,13 +179,14 @@ CMP is defined in RFC 4210. OSSL_CMP_ITAV_new_caCerts(), OSSL_CMP_ITAV_new_rootCaCert(), OSSL_CMP_ITAV_new_rootCaKeyUpdate(), OSSL_CMP_CRLSTATUS_new1(), -OSSL_CMP_CRLSTATUS_create(), OSSL_CMP_ITAV_new0_crlStatusList() -and OSSL_CMP_ITAV_new_crls() +OSSL_CMP_CRLSTATUS_create(), OSSL_CMP_ITAV_new0_crlStatusList(), +OSSL_CMP_ITAV_new_crls() and OSSL_CMP_ITAV_new0_certReqTemplate() return a pointer to the new ITAV structure on success, or NULL on error. OSSL_CMP_ITAV_get0_caCerts(), OSSL_CMP_ITAV_get0_rootCaCert(), OSSL_CMP_ITAV_get0_rootCaKeyUpdate(), OSSL_CMP_CRLSTATUS_get0(), -OSSL_CMP_ITAV_get0_crlStatusList() and OSSL_CMP_ITAV_get0_crls() +OSSL_CMP_ITAV_get0_crlStatusList(), OSSL_CMP_ITAV_get0_crls() +and OSSL_CMP_ITAV_get1_certReqTemplate() return 1 on success, 0 on error. =head1 SEE ALSO @@ -172,8 +202,9 @@ were added in OpenSSL 3.2. OSSL_CMP_CRLSTATUS_new1(), OSSL_CMP_CRLSTATUS_create(), OSSL_CMP_CRLSTATUS_get0(), OSSL_CMP_ITAV_new0_crlStatusList(), -OSSL_CMP_ITAV_get0_crlStatusList(), OSSL_CMP_ITAV_new_crls() -and OSSL_CMP_ITAV_get0_crls() were added in OpenSSL 3.4. +OSSL_CMP_ITAV_get0_crlStatusList(), OSSL_CMP_ITAV_new_crls(), +OSSL_CMP_ITAV_get0_crls(), OSSL_CMP_ITAV_new0_certReqTemplate() +and OSSL_CMP_ITAV_get1_certReqTemplate() were added in OpenSSL 3.4. =head1 COPYRIGHT diff --git a/doc/man3/OSSL_CMP_exec_certreq.pod b/doc/man3/OSSL_CMP_exec_certreq.pod index a264ec88275ad..c82aa948de4cf 100644 --- a/doc/man3/OSSL_CMP_exec_certreq.pod +++ b/doc/man3/OSSL_CMP_exec_certreq.pod @@ -16,7 +16,8 @@ OSSL_CMP_exec_RR_ses, OSSL_CMP_exec_GENM_ses, OSSL_CMP_get1_caCerts, OSSL_CMP_get1_rootCaKeyUpdate, -OSSL_CMP_get1_crlUpdate +OSSL_CMP_get1_crlUpdate, +OSSL_CMP_get1_certReqTemplate - functions implementing CMP client transactions =head1 SYNOPSIS @@ -45,7 +46,9 @@ OSSL_CMP_get1_crlUpdate int OSSL_CMP_get1_crlUpdate(OSSL_CMP_CTX *ctx, const X509 *crlcert, const X509_CRL *last_crl, X509_CRL **crl); - + int OSSL_CMP_get1_certReqTemplate(OSSL_CMP_CTX *ctx, + OSSL_CRMF_CERTTEMPLATE **certTemplate, + OSSL_CMP_ATAVS **keySpec); =head1 DESCRIPTION This is the OpenSSL API for doing CMP (Certificate Management Protocol) @@ -169,6 +172,14 @@ On success it assigns to I<*crl> the CRL received. NULL means that no CRL was provided by the server. The CRL obtained this way must be freed by the caller. +OSSL_CMP_get1_certReqTemplate() uses a genm request message with +infoType certReqTemplate to obtain a certificate request template from the +CMP server referenced by I. On success it assigns to I<*certTemplate> +the certificate template received. The optional I output parameter +is assigned the key specification if received, otherwise it set to NULL. +Both must be freed by the caller. +NULL output means that no certificate request template was provided by the server. + =head1 NOTES CMP is defined in RFC 4210 (and CRMF in RFC 4211). @@ -205,7 +216,8 @@ and the output parameter I has been used to assign the received value unless I is NULL. OSSL_CMP_exec_RR_ses(), OSSL_CMP_get1_caCerts(), -OSSL_CMP_get1_rootCaKeyUpdate() and OSSL_CMP_get1_crlUpdate() +OSSL_CMP_get1_rootCaKeyUpdate(), OSSL_CMP_get1_crlUpdate() +and OSSL_CMP_get1_certReqTemplate() return 1 on success, 0 on error. OSSL_CMP_exec_GENM_ses() returns NULL on error, @@ -235,7 +247,8 @@ were added in OpenSSL 3.2. Support for delayed delivery of all types of response messages was added in OpenSSL 3.3. -OSSL_CMP_get1_crlUpdate() was added in OpenSSL 3.4. +OSSL_CMP_get1_crlUpdate() and OSSL_CMP_get1_certReqTemplate() +was added in OpenSSL 3.4. =head1 COPYRIGHT diff --git a/doc/man3/OSSL_CRMF_MSG_get0_tmpl.pod b/doc/man3/OSSL_CRMF_MSG_get0_tmpl.pod index d0769ac61b490..08a04ad2eab0a 100644 --- a/doc/man3/OSSL_CRMF_MSG_get0_tmpl.pod +++ b/doc/man3/OSSL_CRMF_MSG_get0_tmpl.pod @@ -11,7 +11,10 @@ OSSL_CRMF_CERTTEMPLATE_get0_extensions, OSSL_CRMF_CERTID_get0_serialNumber, OSSL_CRMF_CERTID_get0_issuer, OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert, -OSSL_CRMF_MSG_get_certReqId +OSSL_CRMF_MSG_get_certReqId, +OSSL_CRMF_CERTTEMPLATE_dup, +OSSL_CRMF_ATTRIBUTETYPEANDVALUE_dup, +OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free - functions reading from CRMF CertReqMsg structures =head1 SYNOPSIS @@ -40,6 +43,11 @@ OSSL_CRMF_MSG_get_certReqId EVP_PKEY *pkey); int OSSL_CRMF_MSG_get_certReqId(const OSSL_CRMF_MSG *crm); + OSSL_CRMF_CERTTEMPLATE *OSSL_CRMF_CERTTEMPLATE_dup(const OSSL_CRMF_CERTTEMPLATE *a); + + OSSL_CRMF_ATTRIBUTETYPEANDVALUE + *OSSL_CRMF_ATTRIBUTETYPEANDVALUE_dup(const OSSL_CRMF_ATTRIBUTETYPEANDVALUE *a); + void OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free(OSSL_CRMF_ATTRIBUTETYPEANDVALUE *a); =head1 DESCRIPTION diff --git a/include/internal/crmf.h b/include/internal/crmf.h new file mode 100644 index 0000000000000..a2d831633ddad --- /dev/null +++ b/include/internal/crmf.h @@ -0,0 +1,51 @@ +/* + * Copyright 2019-2024 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ +#ifndef OSSL_CRYPTO_CRMF_H +# define OSSL_CRYPTO_CRMF_H +# pragma once + +# include + +struct ossl_crmf_attributetypeandvalue_st { + ASN1_OBJECT *type; + union { + /* NID_id_regCtrl_regToken */ + ASN1_UTF8STRING *regToken; + + /* NID_id_regCtrl_authenticator */ + ASN1_UTF8STRING *authenticator; + + /* NID_id_regCtrl_pkiPublicationInfo */ + OSSL_CRMF_PKIPUBLICATIONINFO *pkiPublicationInfo; + + /* NID_id_regCtrl_oldCertID */ + OSSL_CRMF_CERTID *oldCertID; + + /* NID_id_regCtrl_protocolEncrKey */ + X509_PUBKEY *protocolEncrKey; + + /* NID_id_regInfo_utf8Pairs */ + ASN1_UTF8STRING *utf8Pairs; + + /* NID_id_regInfo_certReq */ + OSSL_CRMF_CERTREQUEST *certReq; + + /* NID_id_regCtrl_algId */ + X509_ALGOR *algId; + + /* NID_id_regCtrl_rsaKeyLen */ + ASN1_INTEGER *rsaKeyLen; + + ASN1_TYPE *other; + } value; +} /* OSSL_CRMF_ATTRIBUTETYPEANDVALUE */; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) + +#endif /* OSSL_CRYPTO_CRMF_H */ diff --git a/include/openssl/cmp.h.in b/include/openssl/cmp.h.in index c46b9ab594fa7..e0637f9c27d45 100644 --- a/include/openssl/cmp.h.in +++ b/include/openssl/cmp.h.in @@ -234,6 +234,16 @@ typedef struct ossl_cmp_crlstatus_st OSSL_CMP_CRLSTATUS; generate_stack_macros("OSSL_CMP_CRLSTATUS"); -} +typedef OSSL_CRMF_ATTRIBUTETYPEANDVALUE OSSL_CMP_ATAV; +# define OSSL_CMP_ATAV_free OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free +typedef STACK_OF(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) OSSL_CMP_ATAVS; +DECLARE_ASN1_FUNCTIONS(OSSL_CMP_ATAVS) +# define stack_st_OSSL_CMP_ATAV stack_st_OSSL_CRMF_ATTRIBUTETYPEANDVALUE +# define sk_OSSL_CMP_ATAV_num sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_num +# define sk_OSSL_CMP_ATAV_value sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_value +# define sk_OSSL_CMP_ATAV_push sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_push +# define sk_OSSL_CMP_ATAV_pop_free sk_OSSL_CRMF_ATTRIBUTETYPEANDVALUE_pop_free + typedef struct ossl_cmp_revrepcontent_st OSSL_CMP_REVREPCONTENT; typedef struct ossl_cmp_pkisi_st OSSL_CMP_PKISI; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKISI) @@ -299,6 +309,23 @@ int OSSL_CMP_ITAV_get0_crlStatusList(const OSSL_CMP_ITAV *itav, STACK_OF(OSSL_CMP_CRLSTATUS) **out); OSSL_CMP_ITAV *OSSL_CMP_ITAV_new_crls(const X509_CRL *crls); int OSSL_CMP_ITAV_get0_crls(const OSSL_CMP_ITAV *it, STACK_OF(X509_CRL) **out); +OSSL_CMP_ITAV +*OSSL_CMP_ITAV_new0_certReqTemplate(OSSL_CRMF_CERTTEMPLATE *certTemplate, + OSSL_CMP_ATAVS *keySpec); +int OSSL_CMP_ITAV_get1_certReqTemplate(const OSSL_CMP_ITAV *itav, + OSSL_CRMF_CERTTEMPLATE **certTemplate, + OSSL_CMP_ATAVS **keySpec); + +OSSL_CMP_ATAV *OSSL_CMP_ATAV_create(ASN1_OBJECT *type, ASN1_TYPE *value); +void OSSL_CMP_ATAV_set0(OSSL_CMP_ATAV *itav, ASN1_OBJECT *type, + ASN1_TYPE *value); +ASN1_OBJECT *OSSL_CMP_ATAV_get0_type(const OSSL_CMP_ATAV *itav); +ASN1_TYPE *OSSL_CMP_ATAV_get0_value(const OSSL_CMP_ATAV *itav); +OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_algId(const X509_ALGOR *alg); +X509_ALGOR *OSSL_CMP_ATAV_get0_algId(const OSSL_CMP_ATAV *atav); +OSSL_CMP_ATAV *OSSL_CMP_ATAV_new_rsaKeyLen(int len); +int OSSL_CMP_ATAV_get_rsaKeyLen(const OSSL_CMP_ATAV *atav); +int OSSL_CMP_ATAV_push1(OSSL_CMP_ATAVS **sk_p, const OSSL_CMP_ATAV *itav); void OSSL_CMP_MSG_free(OSSL_CMP_MSG *msg); @@ -546,6 +573,9 @@ int OSSL_CMP_get1_rootCaKeyUpdate(OSSL_CMP_CTX *ctx, int OSSL_CMP_get1_crlUpdate(OSSL_CMP_CTX *ctx, const X509 *crlcert, const X509_CRL *last_crl, X509_CRL **crl); +int OSSL_CMP_get1_certReqTemplate(OSSL_CMP_CTX *ctx, + OSSL_CRMF_CERTTEMPLATE **certTemplate, + OSSL_CMP_ATAVS **keySpec); # ifdef __cplusplus } diff --git a/include/openssl/cmperr.h b/include/openssl/cmperr.h index 700ffbeb7beb6..d196924f74767 100644 --- a/include/openssl/cmperr.h +++ b/include/openssl/cmperr.h @@ -60,11 +60,13 @@ # define CMP_R_FAILED_EXTRACTING_PUBKEY 141 # define CMP_R_FAILURE_OBTAINING_RANDOM 110 # define CMP_R_FAIL_INFO_OUT_OF_RANGE 129 +# define CMP_R_GENERATE_CERTREQTEMPLATE 197 # define CMP_R_GENERATE_CRLSTATUS 198 # define CMP_R_GETTING_GENP 192 # define CMP_R_GET_ITAV 199 # define CMP_R_INVALID_ARGS 100 # define CMP_R_INVALID_GENP 193 +# define CMP_R_INVALID_KEYSPEC 202 # define CMP_R_INVALID_OPTION 174 # define CMP_R_INVALID_ROOTCAKEYUPDATE 195 # define CMP_R_MISSING_CERTID 165 diff --git a/include/openssl/crmf.h.in b/include/openssl/crmf.h.in index 43411fa42f66f..54a70ebc858e3 100644 --- a/include/openssl/crmf.h.in +++ b/include/openssl/crmf.h.in @@ -54,6 +54,12 @@ DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_MSG) generate_stack_macros("OSSL_CRMF_MSG"); -} typedef struct ossl_crmf_attributetypeandvalue_st OSSL_CRMF_ATTRIBUTETYPEANDVALUE; +void OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free(OSSL_CRMF_ATTRIBUTETYPEANDVALUE *v); +DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_ATTRIBUTETYPEANDVALUE) +{- + generate_stack_macros("OSSL_CRMF_ATTRIBUTETYPEANDVALUE"); +-} + typedef struct ossl_crmf_pbmparameter_st OSSL_CRMF_PBMPARAMETER; DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_PBMPARAMETER) typedef struct ossl_crmf_poposigningkey_st OSSL_CRMF_POPOSIGNINGKEY; @@ -71,6 +77,7 @@ typedef struct ossl_crmf_singlepubinfo_st OSSL_CRMF_SINGLEPUBINFO; DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_SINGLEPUBINFO) typedef struct ossl_crmf_certtemplate_st OSSL_CRMF_CERTTEMPLATE; DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_CERTTEMPLATE) +DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTTEMPLATE) typedef STACK_OF(OSSL_CRMF_MSG) OSSL_CRMF_MSGS; DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_MSGS) diff --git a/test/recipes/80-test_cmp_http_data/test_commands.csv b/test/recipes/80-test_cmp_http_data/test_commands.csv index 69dff91b7d809..4c7d385fa3ec9 100644 --- a/test/recipes/80-test_cmp_http_data/test_commands.csv +++ b/test/recipes/80-test_cmp_http_data/test_commands.csv @@ -96,6 +96,14 @@ expected,description, -section,val, -cmd,val,val2, -cacertsout,val,val2, -infoty 0,genm crlStatusList missing -crlcert & -oldcrl, -section,, -cmd,genm,, BLANK,,, -infotype,crlStatusList,,,,,,,, -crlout, _RESULT_DIR/test.crlout.pem 0,genm crlStatusList with wrong cert and correct crl, -section,, -cmd,genm,, BLANK,,, -infotype,crlStatusList,, -crlcert, server.crt, -oldcrl, oldcrl.pem,,, -crlout, _RESULT_DIR/test.crlout.pem ,,,,,,,,,,,,,,,,,,,,,, +1,genm certReqTemplate, -section,, -cmd,genm,, -template,_RESULT_DIR/test.template.der, -keyspec,_RESULT_DIR/test.keyspec.der, -infotype,certReqTemplate,,BLANK,,BLANK,,BLANK,,, -expect_sender, """" +0,genm certReqTemplate missing template option, -section,, -cmd,genm,, -template,"""",, -infotype,certReqTemplate,,BLANK,,BLANK, +1,genm certReqTemplate missing optional keyspec option, -section,, -cmd,genm,, -template,_RESULT_DIR/test.template.der, -keyspec,"""",, -infotype,certReqTemplate,,BLANK,,BLANK, +0,genm certReqTemplate keyspec arg non-ex dir, -section,, -cmd,genm,, -template,_RESULT_DIR/test.template.der, -keyspec,idontexist/idontexist,, -infotype,certReqTemplate,,BLANK,,BLANK, +0,genm certReqTemplate missing template arg , -section,, -cmd,genm,, -template,BLANK, -keyspec,_RESULT_DIR/test.keyspec.der, -infotype,certReqTemplate,,BLANK,,BLANK, +0,genm certReqTemplate template extra arg , -section,, -cmd,genm,, -template,_RESULT_DIR/test.template.der,_RESULT_DIR/test.template.der, -infotype,certReqTemplate,,BLANK,,BLANK, +0,genm certReqTemplate template arg non-ex dir, -section,, -cmd,genm,, -template,idontexist/idontexist,, -infotype,certReqTemplate,,BLANK,,BLANK, +,,,,,,,,,,,,,,,,,,,,,, 1,profile, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,profile1,BLANK,,BLANK, 0,profile wrong value, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,profile2,BLANK,,BLANK, 0,profile missing argument, -section,, -cmd,cr,, -cert,signer.crt, -key,signer.p12, -keypass,pass:12345,BLANK,, -profile,,,,, diff --git a/util/libcrypto.num b/util/libcrypto.num index 3f52107edaf08..6857f47bfe611 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5559,6 +5559,26 @@ OSSL_CMP_ITAV_get0_crls ? 3_4_0 EXIST::FUNCTION:CMP OSSL_CMP_ITAV_new0_crlStatusList ? 3_4_0 EXIST::FUNCTION:CMP OSSL_CMP_ITAV_new_crls ? 3_4_0 EXIST::FUNCTION:CMP OSSL_CMP_get1_crlUpdate ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ITAV_new0_certReqTemplate ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ITAV_get1_certReqTemplate ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_create ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_set0 ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_get0_type ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_get0_value ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_new_algId ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_get0_algId ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_new_rsaKeyLen ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_get_rsaKeyLen ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAV_push1 ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_get1_certReqTemplate ? 3_4_0 EXIST::FUNCTION:CMP +d2i_OSSL_CMP_ATAVS ? 3_4_0 EXIST::FUNCTION:CMP +i2d_OSSL_CMP_ATAVS ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAVS_free ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAVS_new ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CMP_ATAVS_it ? 3_4_0 EXIST::FUNCTION:CMP +OSSL_CRMF_ATTRIBUTETYPEANDVALUE_free ? 3_4_0 EXIST::FUNCTION:CRMF +OSSL_CRMF_ATTRIBUTETYPEANDVALUE_dup ? 3_4_0 EXIST::FUNCTION:CRMF +OSSL_CRMF_CERTTEMPLATE_dup ? 3_4_0 EXIST::FUNCTION:CRMF CRYPTO_atomic_store ? 3_4_0 EXIST::FUNCTION: CRYPTO_aligned_alloc ? 3_4_0 EXIST::FUNCTION: d2i_X509_ACERT ? 3_4_0 EXIST::FUNCTION: diff --git a/util/other.syms b/util/other.syms index 6bffe6bf186f9..87ef03fe335c5 100644 --- a/util/other.syms +++ b/util/other.syms @@ -460,6 +460,9 @@ OSSL_CMP_LOG_WARNING define OSSL_CMP_MSTR_HELPER define OSSL_CMP_MSTR define OSSL_CMP_P10CR define +OSSL_CMP_ATAV define +OSSL_CMP_ATAV_free define +OSSL_CMP_ATAVS define OSSL_CMP_certConf_cb_t datatype OSSL_CMP_log_cb_t datatype OSSL_CMP_severity datatype