From cd977852363f5ea716636aa2ad07fe8a27205617 Mon Sep 17 00:00:00 2001 From: Rajeev Ranjan Date: Wed, 29 May 2024 18:19:29 +0200 Subject: [PATCH] CMP: add support for central key generation --- apps/cmp.c | 57 ++++++- crypto/cmp/cmp_asn.c | 4 +- crypto/cmp/cmp_client.c | 6 +- crypto/cmp/cmp_err.c | 6 + crypto/cmp/cmp_local.h | 8 +- crypto/cmp/cmp_msg.c | 56 +++++-- crypto/cmp/cmp_vfy.c | 3 +- crypto/crmf/crmf_asn.c | 13 ++ crypto/crmf/crmf_err.c | 13 +- crypto/crmf/crmf_lib.c | 312 +++++++++++++++++++++++++++++++------- crypto/crmf/crmf_local.h | 18 +++ crypto/err/openssl.txt | 9 ++ include/crypto/cmperr.h | 2 +- include/crypto/crmferr.h | 2 +- include/openssl/cmperr.h | 3 + include/openssl/crmf.h.in | 19 ++- include/openssl/crmferr.h | 8 +- test/cmp_msg_test.c | 2 +- util/libcrypto.num | 8 + 19 files changed, 463 insertions(+), 86 deletions(-) diff --git a/apps/cmp.c b/apps/cmp.c index dc2a1c3a6aee09..9c1afccb349ba0 100644 --- a/apps/cmp.c +++ b/apps/cmp.c @@ -123,6 +123,8 @@ static char *opt_profile = NULL; /* certificate enrollment */ static char *opt_newkey = NULL; static char *opt_newkeypass = NULL; +static int opt_centralkeygen = 0; +static char *opt_newkeyout = NULL; static char *opt_subject = NULL; static int opt_days = 0; static char *opt_reqexts = NULL; @@ -229,7 +231,8 @@ typedef enum OPTION_choice { OPT_CMD, OPT_INFOTYPE, OPT_PROFILE, OPT_GENINFO, OPT_TEMPLATE, OPT_KEYSPEC, - OPT_NEWKEY, OPT_NEWKEYPASS, OPT_SUBJECT, + OPT_NEWKEY, OPT_NEWKEYPASS, OPT_CENTRALKEYGEN, + OPT_NEWKEYOUT, OPT_SUBJECT, OPT_DAYS, OPT_REQEXTS, OPT_SANS, OPT_SAN_NODEFAULT, OPT_POLICIES, OPT_POLICY_OIDS, OPT_POLICY_OIDS_CRITICAL, @@ -325,6 +328,10 @@ const OPTIONS cmp_options[] = { {"newkey", OPT_NEWKEY, 's', "Private or public key for the requested cert. Default: CSR key or client key"}, {"newkeypass", OPT_NEWKEYPASS, 's', "New private key pass phrase source"}, + {"centralkeygen", OPT_CENTRALKEYGEN, '-', + "Request central (server-side) key generation. Default is local generation"}, + {"newkeyout", OPT_NEWKEYOUT, 's', + "File to save new key generated in central key generation"}, {"subject", OPT_SUBJECT, 's', "Distinguished Name (DN) of subject to use in the requested cert template"}, {OPT_MORE_STR, 0, 0, @@ -629,8 +636,8 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */ {&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}, + {&opt_newkey}, {&opt_newkeypass}, {(char **)&opt_centralkeygen}, + {&opt_newkeyout}, {&opt_subject}, {(char **)&opt_days}, {&opt_reqexts}, {&opt_sans}, {(char **)&opt_san_nodefault}, {&opt_policies}, {&opt_policy_oids}, {(char **)&opt_policy_oids_critical}, {(char **)&opt_popo}, {&opt_csr}, @@ -1671,11 +1678,27 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) if (!set_name(opt_issuer, OSSL_CMP_CTX_set1_issuer, ctx, "issuer")) return 0; if (opt_cmd == CMP_IR || opt_cmd == CMP_CR || opt_cmd == CMP_KUR) { - if (opt_reqin == NULL && opt_newkey == NULL + if (opt_reqin == NULL && opt_newkey == NULL && !opt_centralkeygen && opt_key == NULL && opt_csr == NULL && opt_oldcert == NULL) { - CMP_err("missing -newkey (or -key) to be certified and no -csr, -oldcert, -cert, or -reqin option given, which could provide fallback public key"); + CMP_err("missing -newkey (or -key) to be certified and no -csr, -oldcert, -cert, or -reqin option given, which could provide fallback public key." + "Neither central key generation is requested."); return 0; } + if (opt_popo == OSSL_CRMF_POPO_NONE && !opt_centralkeygen) { + CMP_info("POPO is disabled, using -centralkeygen"); + opt_centralkeygen = 1; + } + if (opt_centralkeygen) { + if (opt_popo > OSSL_CRMF_POPO_NONE) { + CMP_err1("-popo value %d is inconsistent with -centralkeygen", opt_popo); + return 0; + } + if (opt_newkeyout == NULL) { + CMP_err("-newkeyout not given, nowhere to save newly generated key"); + return 0; + } + opt_popo = OSSL_CRMF_POPO_NONE; + } if (opt_newkey == NULL && opt_popo != OSSL_CRMF_POPO_NONE && opt_popo != OSSL_CRMF_POPO_RAVERIFIED) { @@ -1723,6 +1746,10 @@ static int setup_request_ctx(OSSL_CMP_CTX *ctx, ENGINE *engine) CMP_warn1("-policies %s", msg); if (opt_policy_oids != NULL) CMP_warn1("-policy_oids %s", msg); + if (opt_centralkeygen) + CMP_warn1("-centralkeygen %s", msg); + if (opt_newkeyout != NULL) + CMP_warn1("-newkeyout %s", msg); if (opt_cmd != CMP_P10CR) { if (opt_implicit_confirm) CMP_warn1("-implicit_confirm %s, and 'p10cr'", msg); @@ -2921,13 +2948,18 @@ static int get_opts(int argc, char **argv) case OPT_KEYSPEC: opt_keyspec = opt_str(); break; - case OPT_NEWKEY: opt_newkey = opt_str(); break; case OPT_NEWKEYPASS: opt_newkeypass = opt_str(); break; + case OPT_CENTRALKEYGEN: + opt_centralkeygen = 1; + break; + case OPT_NEWKEYOUT: + opt_newkeyout = opt_str(); + break; case OPT_SUBJECT: opt_subject = opt_str(); break; @@ -3792,6 +3824,19 @@ int cmp_main(int argc, char **argv) if (save_free_certs(OSSL_CMP_CTX_get1_caPubs(cmp_ctx), opt_cacertsout, "CA") < 0) goto err; + if (opt_centralkeygen) { + EVP_PKEY *new_key = OSSL_CMP_CTX_get0_newPkey(cmp_ctx, 1 /* priv */); + BIO *out = bio_open_owner(opt_newkeyout, FORMAT_PEM, 1); + + if (out == NULL) + goto err; + CMP_info1("received central (server) generated key, saving to file '%s'", + opt_newkeyout); + if (PEM_write_bio_PrivateKey(out, new_key, NULL, NULL, 0, NULL, + NULL) <= 0) + goto err; + BIO_free(out); + } } if (!OSSL_CMP_CTX_reinit(cmp_ctx)) goto err; diff --git a/crypto/cmp/cmp_asn.c b/crypto/cmp/cmp_asn.c index 3bdb3ce688defd..d72eb402ee5d4a 100644 --- a/crypto/cmp/cmp_asn.c +++ b/crypto/cmp/cmp_asn.c @@ -889,7 +889,7 @@ 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) @@ -897,7 +897,7 @@ 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) diff --git a/crypto/cmp/cmp_client.c b/crypto/cmp/cmp_client.c index d588bb358b725b..f362527c7d6b47 100644 --- a/crypto/cmp/cmp_client.c +++ b/crypto/cmp/cmp_client.c @@ -505,6 +505,7 @@ static X509 *get1_cert_status(OSSL_CMP_CTX *ctx, int bodytype, { char buf[OSSL_CMP_PKISI_BUFLEN]; X509 *crt = NULL; + EVP_PKEY *privkey = NULL; if (!ossl_assert(ctx != NULL && crep != NULL)) return NULL; @@ -546,7 +547,7 @@ static X509 *get1_cert_status(OSSL_CMP_CTX *ctx, int bodytype, ERR_raise(ERR_LIB_CMP, CMP_R_UNKNOWN_PKISTATUS); goto err; } - crt = ossl_cmp_certresponse_get1_cert(ctx, crep); + crt = ossl_cmp_certresponse_get1_cert_key(crep, ctx, privkey); if (crt == NULL) /* according to PKIStatus, we can expect a cert */ ERR_raise(ERR_LIB_CMP, CMP_R_CERTIFICATE_NOT_FOUND); @@ -653,7 +654,7 @@ static int cert_response(OSSL_CMP_CTX *ctx, int sleep, int rid, 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 = NULL; @@ -745,6 +746,7 @@ static int cert_response(OSSL_CMP_CTX *ctx, int sleep, int rid, 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))) { diff --git a/crypto/cmp/cmp_err.c b/crypto/cmp/cmp_err.c index 5cec9438f6145a..c3a4b09961e2b9 100644 --- a/crypto/cmp/cmp_err.c +++ b/crypto/cmp/cmp_err.c @@ -79,6 +79,8 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { {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), @@ -97,6 +99,8 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { {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"}, @@ -151,6 +155,8 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { "transactionid unmatched"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_TRANSFER_ERROR), "transfer error"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNCLEAN_CTX), "unclean ctx"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_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), diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h index 597080379701e5..4ebbbbfd1462de 100644 --- a/crypto/cmp/cmp_local.h +++ b/crypto/cmp/cmp_local.h @@ -311,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) @@ -326,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) @@ -988,8 +988,8 @@ ossl_cmp_pollrepcontent_get0_pollrep(const OSSL_CMP_POLLREPCONTENT *prc, OSSL_CMP_CERTRESPONSE * ossl_cmp_certrepmessage_get0_certresponse(const OSSL_CMP_CERTREPMESSAGE *crm, int rid); -X509 *ossl_cmp_certresponse_get1_cert(const OSSL_CMP_CTX *ctx, - const OSSL_CMP_CERTRESPONSE *crep); +X509 *ossl_cmp_certresponse_get1_cert_key(const OSSL_CMP_CERTRESPONSE *crep, + const OSSL_CMP_CTX *ctx, EVP_PKEY *pkey); OSSL_CMP_MSG *ossl_cmp_msg_load(const char *file); int ossl_cmp_is_error_with_waiting(const OSSL_CMP_MSG *msg); diff --git a/crypto/cmp/cmp_msg.c b/crypto/cmp/cmp_msg.c index 9628f0500ad564..fdd6bc23815739 100644 --- a/crypto/cmp/cmp_msg.c +++ b/crypto/cmp/cmp_msg.c @@ -271,6 +271,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); @@ -283,6 +285,7 @@ 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) { @@ -297,6 +300,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 @@ -306,6 +310,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); @@ -1043,22 +1051,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. + * In case of indirect POPO uses the libctx and propq from ctx and private key. + * In case of central key generation, updates ctx->newPkey. * 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_key(const OSSL_CMP_CERTRESPONSE *crep, + const OSSL_CMP_CTX *ctx, EVP_PKEY *pkey) { OSSL_CMP_CERTORENCCERT *coec; X509 *crt = NULL; - EVP_PKEY *pkey; + OSSL_CRMF_ENCRYPTEDKEY *encr_key; + 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); @@ -1071,10 +1108,9 @@ 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, + crt = OSSL_CRMF_ENCRYPTEDKEY_get1_encCert(coec->value.encryptedCert, ctx->libctx, ctx->propq, - pkey); + pkey, 0); break; default: ERR_raise(ERR_LIB_CMP, CMP_R_UNKNOWN_CERT_TYPE); diff --git a/crypto/cmp/cmp_vfy.c b/crypto/cmp/cmp_vfy.c index 47bf38b2af5dab..f27bc533ec0b5a 100644 --- a/crypto/cmp/cmp_vfy.c +++ b/crypto/cmp/cmp_vfy.c @@ -347,10 +347,11 @@ static int check_cert_path_3gpp(const OSSL_CMP_CTX *ctx, * verify that the newly enrolled certificate (which assumed rid == * OSSL_CMP_CERTREQID) can also be validated with the same trusted store */ + EVP_PKEY *pkey = OSSL_CMP_CTX_get0_newPkey(ctx, 1); OSSL_CMP_CERTRESPONSE *crep = ossl_cmp_certrepmessage_get0_certresponse(msg->body->value.ip, OSSL_CMP_CERTREQID); - X509 *newcrt = ossl_cmp_certresponse_get1_cert(ctx, crep); + X509 *newcrt = ossl_cmp_certresponse_get1_cert_key(crep, ctx, pkey); /* * maybe better use get_cert_status() from cmp_client.c, which catches diff --git a/crypto/crmf/crmf_asn.c b/crypto/crmf/crmf_asn.c index 55b0c39bf82d67..8a8f47f57885bf 100644 --- a/crypto/crmf/crmf_asn.c +++ b/crypto/crmf/crmf_asn.c @@ -58,6 +58,19 @@ ASN1_SEQUENCE(OSSL_CRMF_ENCRYPTEDVALUE) = { } ASN1_SEQUENCE_END(OSSL_CRMF_ENCRYPTEDVALUE) IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_ENCRYPTEDVALUE) +/* + * Note from CMP Updates defining CMPv3: + * The EncryptedKey structure defined in CRMF [RFC4211] is reused + * here, which makes the update backward compatible. Using the new + * syntax with the untagged default choice EncryptedValue is bits-on- + * the-wire compatible with the old syntax. + */ +ASN1_CHOICE(OSSL_CRMF_ENCRYPTEDKEY) = { + ASN1_SIMPLE(OSSL_CRMF_ENCRYPTEDKEY, value.encryptedValue, OSSL_CRMF_ENCRYPTEDVALUE), + ASN1_IMP(OSSL_CRMF_ENCRYPTEDKEY, value.envelopedData, CMS_EnvelopedData, 0), +} ASN1_CHOICE_END(OSSL_CRMF_ENCRYPTEDKEY) +IMPLEMENT_ASN1_FUNCTIONS(OSSL_CRMF_ENCRYPTEDKEY) + ASN1_SEQUENCE(OSSL_CRMF_SINGLEPUBINFO) = { ASN1_SIMPLE(OSSL_CRMF_SINGLEPUBINFO, pubMethod, ASN1_INTEGER), ASN1_SIMPLE(OSSL_CRMF_SINGLEPUBINFO, pubLocation, GENERAL_NAME) diff --git a/crypto/crmf/crmf_err.c b/crypto/crmf/crmf_err.c index 44b2f2757d2c26..a98f5044de145d 100644 --- a/crypto/crmf/crmf_err.c +++ b/crypto/crmf/crmf_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-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 @@ -19,14 +19,25 @@ static const ERR_STRING_DATA CRMF_str_reasons[] = { {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_BAD_PBM_ITERATIONCOUNT), "bad pbm iterationcount"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_CMS_NOT_SUPPORTED), "cms not supported"}, {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_CRMFERROR), "crmferror"}, {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR), "error"}, {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR_DECODING_CERTIFICATE), "error decoding certificate"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR_DECODING_ENCRYPTEDKEY), + "error decoding encryptedkey"}, {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR_DECRYPTING_CERTIFICATE), "error decrypting certificate"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR_DECRYPTING_ENCRYPTEDKEY), + "error decrypting encryptedkey"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR_DECRYPTING_ENCRYPTEDVALUE), + "error decrypting encryptedvalue"}, {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR_DECRYPTING_SYMMETRIC_KEY), "error decrypting symmetric key"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR_SETTING_PURPOSE), + "error setting purpose"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ERROR_VERIFYING_ENCRYPTEDKEY), + "error verifying encryptedkey"}, {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_FAILURE_OBTAINING_RANDOM), "failure obtaining random"}, {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_ITERATIONCOUNT_BELOW_100), diff --git a/crypto/crmf/crmf_lib.c b/crypto/crmf/crmf_lib.c index cb077e41d2c4c5..d1b417eb6c154f 100644 --- a/crypto/crmf/crmf_lib.c +++ b/crypto/crmf/crmf_lib.c @@ -29,6 +29,7 @@ #include #include "crmf_local.h" +#include "internal/constant_time.h" #include "internal/sizes.h" #include "crypto/evp.h" #include "crypto/x509.h" @@ -612,102 +613,303 @@ int OSSL_CRMF_CERTTEMPLATE_fill(OSSL_CRMF_CERTTEMPLATE *tmpl, return 1; } -/*- - * Decrypts the certificate in the given encryptedValue using private key pkey. - * This is needed for the indirect PoP method as in RFC 4210 section 5.2.8.2. - * - * returns a pointer to the decrypted certificate - * returns NULL on error or if no certificate available - */ -X509 -*OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(const OSSL_CRMF_ENCRYPTEDVALUE *ecert, - OSSL_LIB_CTX *libctx, const char *propq, - EVP_PKEY *pkey) +#ifndef OPENSSL_NO_CMS +DECLARE_ASN1_ITEM(CMS_SignedData) /* copied from cms_local.h */ + +/* check for KGA authorization implied by CA flag or by explicit EKU cmKGA */ +static int check_cmKGA(ossl_unused const X509_PURPOSE *purpose, + const X509 *x, int ca) +{ + STACK_OF(ASN1_OBJECT) *ekus; + int i, ret = 1; + + if (ca) + return ret; + ekus = X509_get_ext_d2i(x, NID_ext_key_usage, NULL, NULL); + for (i = 0; i < sk_ASN1_OBJECT_num(ekus); i++) { +# if OPENSSL_VERSION_NUMBER >= 0x30000000L + if (OBJ_obj2nid(sk_ASN1_OBJECT_value(ekus, i)) == NID_cmKGA) + goto end; +# else + { + char txt[100]; + + if (OBJ_obj2txt(txt, sizeof(txt), sk_ASN1_OBJECT_value(ekus, i), 1) + && strcmp(txt, "1.3.6.1.5.5.7.3.32") == 0) /* OID cmKGA */ + goto end; + } +# endif + } + ret = 0; + + end: + sk_ASN1_OBJECT_pop_free(ekus, ASN1_OBJECT_free); + return ret; +} +#endif /* OPENSSL_NO_CMS */ + +EVP_PKEY +*OSSL_CRMF_ENCRYPTEDKEY_get1_pkey(OSSL_CRMF_ENCRYPTEDKEY *encryptedKey, + X509_STORE *ts, STACK_OF(X509) *extra, + EVP_PKEY *pkey, X509 *cert, + ASN1_OCTET_STRING *secret, + OSSL_LIB_CTX *libctx, const char *propq) +{ +#ifndef OPENSSL_NO_CMS + BIO *bio = NULL; + CMS_SignedData *sd = NULL; + BIO *pkey_bio = NULL; + int purpose_id = X509_PURPOSE_get_count() + 1; + X509_VERIFY_PARAM *ts_vpm, *bak_vpm = NULL; +#endif + EVP_PKEY *ret = NULL; + + if (encryptedKey == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return NULL; + } + if (encryptedKey->type != OSSL_CRMF_ENCRYPTEDKEY_ENVELOPEDDATA) { + unsigned char *p = NULL; + const unsigned char *p_copy; + int len; + + p = OSSL_CRMF_ENCRYPTEDVALUE_decrypt(encryptedKey->value.encryptedValue, + pkey, &len, libctx, propq); + if ((p_copy = p) != NULL) + ret = d2i_AutoPrivateKey_ex(NULL, &p_copy, len, libctx, propq); + OPENSSL_free(p); + return ret; + } + +#ifndef OPENSSL_NO_CMS + if (ts == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return NULL; + } + if ((bio = CMS_EnvelopedData_decrypt(encryptedKey->value.envelopedData, + NULL, pkey, cert, secret, 0, + libctx, propq)) == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_DECRYPTING_ENCRYPTEDKEY); + goto end; + } + sd = ASN1_item_d2i_bio(ASN1_ITEM_rptr(CMS_SignedData), bio, NULL); + if (sd == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_VERIFYING_ENCRYPTEDKEY); + goto end; + } + + if ((ts_vpm = X509_STORE_get0_param(ts)) == NULL + || (bak_vpm = X509_VERIFY_PARAM_new()) == NULL /* copy of VPMs of ts */ + || !X509_VERIFY_PARAM_inherit(bak_vpm, ts_vpm) + || !X509_PURPOSE_add(purpose_id, X509_TRUST_COMPAT, 0, check_cmKGA, + "CMP Key Generation Authority", "cmKGA", NULL) + /* override X509_PURPOSE_SMIME_SIGN: */ + || !X509_STORE_set_purpose(ts, purpose_id)) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_SETTING_PURPOSE); + goto end; + } + + extra = NULL; /* workaround for CMS_add0_cert() in cms_lib.c not allowing duplicate untrusted certs */ + pkey_bio = CMS_SignedData_verify(sd, NULL, NULL /* scerts */, ts, + extra, NULL, 0, libctx, propq); + + /* workaround for API limit getting and restoring original purpose in ts */ + if (!X509_VERIFY_PARAM_set_inh_flags(bak_vpm, X509_VP_FLAG_OVERWRITE) + || !X509_STORE_set1_param(ts, bak_vpm)) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_SETTING_PURPOSE); + goto end; + } + + if (pkey_bio == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_VERIFYING_ENCRYPTEDKEY); + goto end; + } + + /* unpack AsymmetricKeyPackage */ + if ((ret = d2i_PrivateKey_ex_bio(pkey_bio, NULL, libctx, propq)) == NULL) + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_DECODING_ENCRYPTEDKEY); + + end: + X509_VERIFY_PARAM_free(bak_vpm); + CMS_SignedData_free(sd); + BIO_free(bio); + BIO_free(pkey_bio); + return ret; +#else + /* prevent warning on unused parameters: */ + ((void)ts, (void)extra, (void)cert, (void)secret); + ERR_raise(ERR_LIB_CRMF, CRMF_R_CMS_NOT_SUPPORTED); + return NULL; +#endif /* OPENSSL_NO_CMS */ +} + + +unsigned char +*OSSL_CRMF_ENCRYPTEDVALUE_decrypt(const OSSL_CRMF_ENCRYPTEDVALUE *enc, + EVP_PKEY *pkey, int *outlen, + OSSL_LIB_CTX *libctx, const char *propq) { - X509 *cert = NULL; /* decrypted certificate */ EVP_CIPHER_CTX *evp_ctx = NULL; /* context for symmetric encryption */ unsigned char *ek = NULL; /* decrypted symmetric encryption key */ size_t eksize = 0; /* size of decrypted symmetric encryption key */ - EVP_CIPHER *cipher = NULL; /* used cipher */ + const EVP_CIPHER *cipher = NULL; /* used cipher */ int cikeysize = 0; /* key size from cipher */ unsigned char *iv = NULL; /* initial vector for symmetric encryption */ - unsigned char *outbuf = NULL; /* decryption output buffer */ - const unsigned char *p = NULL; /* needed for decoding ASN1 */ - int n, outlen = 0; + unsigned char *out = NULL; /* decryption output buffer */ + int symmAlg = 0; /* NIDs for symmetric algorithm */ + int n, ret = 0; EVP_PKEY_CTX *pkctx = NULL; /* private key context */ - char name[OSSL_MAX_NAME_SIZE]; - if (ecert == NULL || ecert->symmAlg == NULL || ecert->encSymmKey == NULL - || ecert->encValue == NULL || pkey == NULL) { + if (outlen == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); + return NULL; + } + *outlen = 0; + if (enc == NULL || enc->symmAlg == NULL || enc->encSymmKey == NULL + || enc->encValue == NULL || pkey == NULL) { ERR_raise(ERR_LIB_CRMF, CRMF_R_NULL_ARGUMENT); return NULL; } - /* select symmetric cipher based on algorithm given in message */ - OBJ_obj2txt(name, sizeof(name), ecert->symmAlg->algorithm, 0); - - (void)ERR_set_mark(); - cipher = EVP_CIPHER_fetch(NULL, name, NULL); - - if (cipher == NULL) - cipher = (EVP_CIPHER *)EVP_get_cipherbyname(name); + if ((symmAlg = OBJ_obj2nid(enc->symmAlg->algorithm)) == 0) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_CIPHER); + return NULL; + } - if (cipher == NULL) { - (void)ERR_clear_last_mark(); + /* select symmetric cipher based on algorithm given in message */ + if ((cipher = EVP_get_cipherbynid(symmAlg)) == NULL) { ERR_raise(ERR_LIB_CRMF, CRMF_R_UNSUPPORTED_CIPHER); goto end; } - (void)ERR_pop_to_mark(); cikeysize = EVP_CIPHER_get_key_length(cipher); /* first the symmetric key needs to be decrypted */ pkctx = EVP_PKEY_CTX_new_from_pkey(libctx, pkey, propq); - if (pkctx == NULL || EVP_PKEY_decrypt_init(pkctx) <= 0 - || evp_pkey_decrypt_alloc(pkctx, &ek, &eksize, (size_t)cikeysize, - ecert->encSymmKey->data, - ecert->encSymmKey->length) <= 0) + if (pkctx != NULL && EVP_PKEY_decrypt_init(pkctx)) { + ASN1_BIT_STRING *encKey = enc->encSymmKey; + size_t failure; + int retval; + + if (EVP_PKEY_decrypt(pkctx, NULL, &eksize, + encKey->data, encKey->length) <= 0 + || (ek = OPENSSL_malloc(eksize)) == NULL) + goto end; + retval = EVP_PKEY_decrypt(pkctx, ek, &eksize, + encKey->data, encKey->length); + ERR_clear_error(); /* error state may have sensitive information */ + failure = ~constant_time_is_zero_s(constant_time_msb(retval) + | constant_time_is_zero(retval)); + failure |= ~constant_time_eq_s(eksize, (size_t)cikeysize); + if (failure) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_DECRYPTING_SYMMETRIC_KEY); + goto end; + } + } else { goto end; - + } if ((iv = OPENSSL_malloc(EVP_CIPHER_get_iv_length(cipher))) == NULL) goto end; - if (ASN1_TYPE_get_octetstring(ecert->symmAlg->parameter, iv, + if (ASN1_TYPE_get_octetstring(enc->symmAlg->parameter, iv, EVP_CIPHER_get_iv_length(cipher)) != EVP_CIPHER_get_iv_length(cipher)) { ERR_raise(ERR_LIB_CRMF, CRMF_R_MALFORMED_IV); goto end; } - /* - * d2i_X509 changes the given pointer, so use p for decoding the message and - * keep the original pointer in outbuf so the memory can be freed later - */ - if ((p = outbuf = OPENSSL_malloc(ecert->encValue->length + - EVP_CIPHER_get_block_size(cipher))) == NULL + if ((out = OPENSSL_malloc(enc->encValue->length + + EVP_CIPHER_get_block_size(cipher))) == NULL || (evp_ctx = EVP_CIPHER_CTX_new()) == NULL) goto end; EVP_CIPHER_CTX_set_padding(evp_ctx, 0); if (!EVP_DecryptInit(evp_ctx, cipher, ek, iv) - || !EVP_DecryptUpdate(evp_ctx, outbuf, &outlen, - ecert->encValue->data, - ecert->encValue->length) - || !EVP_DecryptFinal(evp_ctx, outbuf + outlen, &n)) { - ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_DECRYPTING_CERTIFICATE); + || !EVP_DecryptUpdate(evp_ctx, out, outlen, + enc->encValue->data, + enc->encValue->length) + || !EVP_DecryptFinal(evp_ctx, out + *outlen, &n)) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_DECRYPTING_ENCRYPTEDVALUE); goto end; } - outlen += n; + *outlen += n; + ret = 1; - /* convert decrypted certificate from DER to internal ASN.1 structure */ - if ((cert = X509_new_ex(libctx, propq)) == NULL) - goto end; - if (d2i_X509(&cert, &p, outlen) == NULL) - ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_DECODING_CERTIFICATE); end: EVP_PKEY_CTX_free(pkctx); - OPENSSL_free(outbuf); EVP_CIPHER_CTX_free(evp_ctx); - EVP_CIPHER_free(cipher); OPENSSL_clear_free(ek, eksize); OPENSSL_free(iv); + if (ret) + return out; + OPENSSL_free(out); + return NULL; +} + + +/*- + * Decrypts the certificate in the given encryptedValue using private key pkey. + * This is needed for the indirect PoP method as in RFC 4210 section 5.2.8.2. + * + * returns a pointer to the decrypted certificate + * returns NULL on error or if no certificate available + */ +X509 +*OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(const OSSL_CRMF_ENCRYPTEDVALUE *ecert, + OSSL_LIB_CTX *libctx, const char *propq, + EVP_PKEY *pkey) +{ + unsigned char *buf = NULL; + const unsigned char *p; + int len; + X509 *cert = NULL; + + buf = OSSL_CRMF_ENCRYPTEDVALUE_decrypt(ecert, pkey, &len, libctx, propq); + if ((p = buf) == NULL + || (cert = X509_new_ex(libctx, propq)) == NULL) + goto end; + if (d2i_X509(&cert, &p, len) == NULL) { + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_DECODING_CERTIFICATE); + X509_free(cert); + cert = NULL; + } + + end: + OPENSSL_free(buf); return cert; } +/*- + * Decrypts the certificate in the given encryptedKey using private key pkey. + * This is needed for the indirect PoP method as in RFC 4210 section 5.2.8.2. + * + * returns a pointer to the decrypted certificate + * returns NULL on error or if no certificate available + */ +X509 +*OSSL_CRMF_ENCRYPTEDKEY_get1_encCert(const OSSL_CRMF_ENCRYPTEDKEY *ecert, + OSSL_LIB_CTX *libctx, const char *propq, + EVP_PKEY *pkey, unsigned int flags) +{ +#ifndef OPENSSL_NO_CMS + BIO *bio; + X509 *cert = NULL; +#endif + + if (ecert->type != OSSL_CRMF_ENCRYPTEDKEY_ENVELOPEDDATA) + return OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(ecert->value.encryptedValue, + libctx, propq, pkey); +#ifndef OPENSSL_NO_CMS + bio = CMS_EnvelopedData_decrypt(ecert->value.envelopedData, NULL, + pkey, NULL /* cert */, NULL, flags, + libctx, propq); + if (bio == NULL) + return NULL; + cert = d2i_X509_bio(bio, NULL); + if (cert == NULL) + ERR_raise(ERR_LIB_CRMF, CRMF_R_ERROR_DECODING_CERTIFICATE); + BIO_free(bio); + return cert; +#else + (void)flags; /* prevent warning on unused parameter */ + ERR_raise(ERR_LIB_CRMF, CRMF_R_CMS_NOT_SUPPORTED); + return NULL; +#endif /* OPENSSL_NO_CMS */ +} diff --git a/crypto/crmf/crmf_local.h b/crypto/crmf/crmf_local.h index cfa01ab3992cf1..e47f137b1926e8 100644 --- a/crypto/crmf/crmf_local.h +++ b/crypto/crmf/crmf_local.h @@ -15,6 +15,7 @@ # define OSSL_CRYPTO_CRMF_LOCAL_H # include +# include /* for CMS_EnvelopedData and CMS_SignedData */ # include # include "internal/crmf.h" /* for ossl_crmf_attributetypeandvalue_st */ @@ -52,6 +53,23 @@ struct ossl_crmf_encryptedvalue_st { ASN1_BIT_STRING *encValue; } /* OSSL_CRMF_ENCRYPTEDVALUE */; +/* + * EncryptedKey ::= CHOICE { + * encryptedValue EncryptedValue, -- Deprecated + * envelopedData [0] EnvelopedData } + * -- The encrypted private key MUST be placed in the envelopedData + * -- encryptedContentInfo encryptedContent OCTET STRING. + */ +# define OSSL_CRMF_ENCRYPTEDKEY_ENVELOPEDDATA 1 + +struct ossl_crmf_encryptedkey_st { + int type; + union { + OSSL_CRMF_ENCRYPTEDVALUE *encryptedValue; /* 0 */ /* Deprecated */ + CMS_EnvelopedData *envelopedData; /* 1 */ + } value; +} /* OSSL_CRMF_ENCRYPTEDKEY */; + /*- * Attributes ::= SET OF Attribute * => X509_ATTRIBUTE diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 93dfbeeea5ef00..f6bee0691aa1e5 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -231,6 +231,7 @@ CMP_R_ERROR_VALIDATING_PROTECTION:140:error validating protection CMP_R_ERROR_VALIDATING_SIGNATURE:171:error validating signature CMP_R_EXPECTED_POLLREQ:104:expected pollreq CMP_R_FAILED_BUILDING_OWN_CHAIN:164:failed building own chain +CMP_R_FAILED_EXTRACTING_CENTRAL_GEN_KEY:203:failed extracting central gen key 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 @@ -243,6 +244,7 @@ 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_CENTRAL_GEN_KEY:204:missing central gen key CMP_R_MISSING_CERTID:165:missing certid CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION:130:\ missing key input for creating protection @@ -279,6 +281,7 @@ CMP_R_TOTAL_TIMEOUT:184:total timeout CMP_R_TRANSACTIONID_UNMATCHED:152:transactionid unmatched CMP_R_TRANSFER_ERROR:159:transfer error CMP_R_UNCLEAN_CTX:191:unclean ctx +CMP_R_UNEXPECTED_CENTRAL_GEN_KEY:205:unexpected central gen key CMP_R_UNEXPECTED_CERTPROFILE:196:unexpected certprofile CMP_R_UNEXPECTED_CRLSTATUSLIST:201:unexpected crlstatuslist CMP_R_UNEXPECTED_PKIBODY:133:unexpected pkibody @@ -448,11 +451,17 @@ CONF_R_UNKNOWN_MODULE_NAME:113:unknown module name CONF_R_VARIABLE_EXPANSION_TOO_LONG:116:variable expansion too long CONF_R_VARIABLE_HAS_NO_VALUE:104:variable has no value CRMF_R_BAD_PBM_ITERATIONCOUNT:100:bad pbm iterationcount +CRMF_R_CMS_NOT_SUPPORTED:122:cms not supported CRMF_R_CRMFERROR:102:crmferror CRMF_R_ERROR:103:error CRMF_R_ERROR_DECODING_CERTIFICATE:104:error decoding certificate +CRMF_R_ERROR_DECODING_ENCRYPTEDKEY:123:error decoding encryptedkey CRMF_R_ERROR_DECRYPTING_CERTIFICATE:105:error decrypting certificate +CRMF_R_ERROR_DECRYPTING_ENCRYPTEDKEY:124:error decrypting encryptedkey +CRMF_R_ERROR_DECRYPTING_ENCRYPTEDVALUE:125:error decrypting encryptedvalue CRMF_R_ERROR_DECRYPTING_SYMMETRIC_KEY:106:error decrypting symmetric key +CRMF_R_ERROR_SETTING_PURPOSE:126:error setting purpose +CRMF_R_ERROR_VERIFYING_ENCRYPTEDKEY:127:error verifying encryptedkey CRMF_R_FAILURE_OBTAINING_RANDOM:107:failure obtaining random CRMF_R_ITERATIONCOUNT_BELOW_100:108:iterationcount below 100 CRMF_R_MALFORMED_IV:101:malformed iv diff --git a/include/crypto/cmperr.h b/include/crypto/cmperr.h index 2bd1637384661b..89512baabb9def 100644 --- a/include/crypto/cmperr.h +++ b/include/crypto/cmperr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 2020-2023 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-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 diff --git a/include/crypto/crmferr.h b/include/crypto/crmferr.h index f1a27e04993b60..89f80eee6b1545 100644 --- a/include/crypto/crmferr.h +++ b/include/crypto/crmferr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 2020-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2020-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 diff --git a/include/openssl/cmperr.h b/include/openssl/cmperr.h index d196924f747671..74fcda665fd834 100644 --- a/include/openssl/cmperr.h +++ b/include/openssl/cmperr.h @@ -57,6 +57,7 @@ # define CMP_R_ERROR_VALIDATING_SIGNATURE 171 # define CMP_R_EXPECTED_POLLREQ 104 # define CMP_R_FAILED_BUILDING_OWN_CHAIN 164 +# define CMP_R_FAILED_EXTRACTING_CENTRAL_GEN_KEY 203 # define CMP_R_FAILED_EXTRACTING_PUBKEY 141 # define CMP_R_FAILURE_OBTAINING_RANDOM 110 # define CMP_R_FAIL_INFO_OUT_OF_RANGE 129 @@ -69,6 +70,7 @@ # define CMP_R_INVALID_KEYSPEC 202 # define CMP_R_INVALID_OPTION 174 # define CMP_R_INVALID_ROOTCAKEYUPDATE 195 +# define CMP_R_MISSING_CENTRAL_GEN_KEY 204 # define CMP_R_MISSING_CERTID 165 # define CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION 130 # define CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE 142 @@ -103,6 +105,7 @@ # define CMP_R_TRANSACTIONID_UNMATCHED 152 # define CMP_R_TRANSFER_ERROR 159 # define CMP_R_UNCLEAN_CTX 191 +# define CMP_R_UNEXPECTED_CENTRAL_GEN_KEY 205 # define CMP_R_UNEXPECTED_CERTPROFILE 196 # define CMP_R_UNEXPECTED_CRLSTATUSLIST 201 # define CMP_R_UNEXPECTED_PKIBODY 133 diff --git a/include/openssl/crmf.h.in b/include/openssl/crmf.h.in index 54a70ebc858e3a..6f183b828e6366 100644 --- a/include/openssl/crmf.h.in +++ b/include/openssl/crmf.h.in @@ -45,8 +45,11 @@ extern "C" { # define OSSL_CRMF_SUBSEQUENTMESSAGE_ENCRCERT 0 # define OSSL_CRMF_SUBSEQUENTMESSAGE_CHALLENGERESP 1 typedef struct ossl_crmf_encryptedvalue_st OSSL_CRMF_ENCRYPTEDVALUE; - DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_ENCRYPTEDVALUE) + +typedef struct ossl_crmf_encryptedkey_st OSSL_CRMF_ENCRYPTEDKEY; +DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_ENCRYPTEDKEY) + typedef struct ossl_crmf_msg_st OSSL_CRMF_MSG; DECLARE_ASN1_FUNCTIONS(OSSL_CRMF_MSG) DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_MSG) @@ -181,6 +184,20 @@ X509 *OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(const OSSL_CRMF_ENCRYPTEDVALUE *ecert, OSSL_LIB_CTX *libctx, const char *propq, EVP_PKEY *pkey); +X509 +*OSSL_CRMF_ENCRYPTEDKEY_get1_encCert(const OSSL_CRMF_ENCRYPTEDKEY *ecert, + OSSL_LIB_CTX *libctx, const char *propq, + EVP_PKEY *pkey, unsigned int flags); +unsigned char +*OSSL_CRMF_ENCRYPTEDVALUE_decrypt(const OSSL_CRMF_ENCRYPTEDVALUE *enc, + EVP_PKEY *pkey, int *outlen, + OSSL_LIB_CTX *libctx, const char *propq); +EVP_PKEY +*OSSL_CRMF_ENCRYPTEDKEY_get1_pkey(OSSL_CRMF_ENCRYPTEDKEY *encryptedKey, + X509_STORE *ts, STACK_OF(X509) *extra, + EVP_PKEY *pkey, X509 *cert, + ASN1_OCTET_STRING *secret, + OSSL_LIB_CTX *libctx, const char *propq); # ifdef __cplusplus } diff --git a/include/openssl/crmferr.h b/include/openssl/crmferr.h index b242b922ef1a72..47ac046c57633f 100644 --- a/include/openssl/crmferr.h +++ b/include/openssl/crmferr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2021 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-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 @@ -24,11 +24,17 @@ * CRMF reason codes. */ # define CRMF_R_BAD_PBM_ITERATIONCOUNT 100 +# define CRMF_R_CMS_NOT_SUPPORTED 122 # define CRMF_R_CRMFERROR 102 # define CRMF_R_ERROR 103 # define CRMF_R_ERROR_DECODING_CERTIFICATE 104 +# define CRMF_R_ERROR_DECODING_ENCRYPTEDKEY 123 # define CRMF_R_ERROR_DECRYPTING_CERTIFICATE 105 +# define CRMF_R_ERROR_DECRYPTING_ENCRYPTEDKEY 124 +# define CRMF_R_ERROR_DECRYPTING_ENCRYPTEDVALUE 125 # define CRMF_R_ERROR_DECRYPTING_SYMMETRIC_KEY 106 +# define CRMF_R_ERROR_SETTING_PURPOSE 126 +# define CRMF_R_ERROR_VERIFYING_ENCRYPTEDKEY 127 # define CRMF_R_FAILURE_OBTAINING_RANDOM 107 # define CRMF_R_ITERATIONCOUNT_BELOW_100 108 # define CRMF_R_MALFORMED_IV 101 diff --git a/test/cmp_msg_test.c b/test/cmp_msg_test.c index e98b5624285b53..ba1fc58854c79a 100644 --- a/test/cmp_msg_test.c +++ b/test/cmp_msg_test.c @@ -403,7 +403,7 @@ static int execute_certrep_create(CMP_MSG_TEST_FIXTURE *fixture) goto err; if (!TEST_ptr_null(ossl_cmp_certrepmessage_get0_certresponse(crepmsg, 88))) goto err; - certfromresp = ossl_cmp_certresponse_get1_cert(ctx, read_cresp); + certfromresp = ossl_cmp_certresponse_get1_cert_key(read_cresp, ctx, NULL); if (certfromresp == NULL || !TEST_int_eq(X509_cmp(cert, certfromresp), 0)) goto err; diff --git a/util/libcrypto.num b/util/libcrypto.num index 72ebbe037eb472..9a018b7fc78ee2 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5665,6 +5665,14 @@ OSSL_IETF_ATTR_SYNTAX_get0_value ? 3_4_0 EXIST::FUNCTION: OSSL_IETF_ATTR_SYNTAX_add1_value ? 3_4_0 EXIST::FUNCTION: OSSL_IETF_ATTR_SYNTAX_print ? 3_4_0 EXIST::FUNCTION: X509_ACERT_add_attr_nconf ? 3_4_0 EXIST::FUNCTION: +d2i_OSSL_CRMF_ENCRYPTEDKEY ? 3_4_0 EXIST::FUNCTION:CRMF +i2d_OSSL_CRMF_ENCRYPTEDKEY ? 3_4_0 EXIST::FUNCTION:CRMF +OSSL_CRMF_ENCRYPTEDKEY_free ? 3_4_0 EXIST::FUNCTION:CRMF +OSSL_CRMF_ENCRYPTEDKEY_new ? 3_4_0 EXIST::FUNCTION:CRMF +OSSL_CRMF_ENCRYPTEDKEY_it ? 3_4_0 EXIST::FUNCTION:CRMF +OSSL_CRMF_ENCRYPTEDKEY_get1_encCert ? 3_4_0 EXIST::FUNCTION:CRMF +OSSL_CRMF_ENCRYPTEDVALUE_decrypt ? 3_4_0 EXIST::FUNCTION:CRMF +OSSL_CRMF_ENCRYPTEDKEY_get1_pkey ? 3_4_0 EXIST::FUNCTION:CRMF OSSL_LIB_CTX_get_conf_diagnostics ? 3_4_0 EXIST::FUNCTION: OSSL_LIB_CTX_set_conf_diagnostics ? 3_4_0 EXIST::FUNCTION: OSSL_LIB_CTX_get_data ? 3_4_0 EXIST::FUNCTION: