Skip to content

Commit

Permalink
CMP: add testcase for central keygen
Browse files Browse the repository at this point in the history
  • Loading branch information
rajeev-0 committed Aug 8, 2024
1 parent 4948a7b commit 9528eff
Show file tree
Hide file tree
Showing 16 changed files with 227 additions and 41 deletions.
37 changes: 33 additions & 4 deletions apps/cmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,8 @@ static char *opt_srv_trusted = NULL;
static char *opt_srv_untrusted = NULL;
static char *opt_ref_cert = NULL;
static char *opt_rsp_cert = NULL;
static char *opt_rsp_cert_key = NULL;
static char *opt_rsp_keypass = NULL;
static char *opt_rsp_crl = NULL;
static char *opt_rsp_extracerts = NULL;
static char *opt_rsp_capubs = NULL;
Expand Down Expand Up @@ -284,7 +286,8 @@ typedef enum OPTION_choice {
OPT_SRV_REF, OPT_SRV_SECRET,
OPT_SRV_CERT, OPT_SRV_KEY, OPT_SRV_KEYPASS,
OPT_SRV_TRUSTED, OPT_SRV_UNTRUSTED,
OPT_REF_CERT, OPT_RSP_CERT, OPT_RSP_CRL, OPT_RSP_EXTRACERTS, OPT_RSP_CAPUBS,
OPT_REF_CERT, OPT_RSP_CERT, OPT_RSP_CERT_KEY, OPT_RSP_KEYPASS,
OPT_RSP_CRL, OPT_RSP_EXTRACERTS, OPT_RSP_CAPUBS,
OPT_RSP_NEWWITHNEW, OPT_RSP_NEWWITHOLD, OPT_RSP_OLDWITHNEW,
OPT_POLL_COUNT, OPT_CHECK_AFTER,
OPT_GRANT_IMPLICITCONF,
Expand Down Expand Up @@ -577,6 +580,12 @@ const OPTIONS cmp_options[] = {
"Certificate to be expected for rr and any oldCertID in kur messages"},
{"rsp_cert", OPT_RSP_CERT, 's',
"Certificate to be returned as mock enrollment result"},
{"rsp_cert_key", OPT_RSP_CERT_KEY, 's',
"Private key for the certificate to be returned as mock enrollment result"},
{OPT_MORE_STR, 0, 0,
"Key to be returned for central key pair generation"},
{"rsp_keypass", OPT_RSP_KEYPASS, 's',
"Response private key (and cert) pass phrase source"},
{"rsp_crl", OPT_RSP_CRL, 's',
"CRL to be returned in genp of type crls"},
{"rsp_extracerts", OPT_RSP_EXTRACERTS, 's',
Expand Down Expand Up @@ -689,8 +698,8 @@ static varref cmp_vars[] = { /* must be in same order as enumerated above! */
{&opt_srv_ref}, {&opt_srv_secret},
{&opt_srv_cert}, {&opt_srv_key}, {&opt_srv_keypass},
{&opt_srv_trusted}, {&opt_srv_untrusted},
{&opt_ref_cert}, {&opt_rsp_cert}, {&opt_rsp_crl},
{&opt_rsp_extracerts}, {&opt_rsp_capubs},
{&opt_ref_cert}, {&opt_rsp_cert}, {&opt_rsp_cert_key}, {&opt_rsp_keypass},
{&opt_rsp_crl}, {&opt_rsp_extracerts}, {&opt_rsp_capubs},
{&opt_rsp_newwithnew}, {&opt_rsp_newwithold}, {&opt_rsp_oldwithnew},

{(char **)&opt_poll_count}, {(char **)&opt_check_after},
Expand Down Expand Up @@ -1203,11 +1212,25 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine)
if (opt_rsp_cert == NULL) {
CMP_warn("no -rsp_cert given for mock server");
} else {
if (!setup_cert(srv_ctx, opt_rsp_cert, opt_keypass,
if (!setup_cert(srv_ctx, opt_rsp_cert, opt_rsp_keypass,
"cert the mock server returns on certificate requests",
(add_X509_fn_t)ossl_cmp_mock_srv_set1_certOut))
goto err;
}
if (opt_rsp_cert_key != NULL) {
EVP_PKEY *pkey = load_key_pwd(opt_rsp_cert_key, opt_keyform,
opt_rsp_keypass, engine,
"private key for enrollment cert");

if (pkey == NULL
|| !ossl_cmp_mock_srv_set1_certOutKey(srv_ctx, pkey)) {
EVP_PKEY_free(pkey);
goto err;
}
EVP_PKEY_free(pkey);
}
cleanse(opt_rsp_keypass);

if (!setup_mock_crlout(srv_ctx, opt_rsp_crl,
"CRL to be returned by the mock server"))
goto err;
Expand Down Expand Up @@ -3118,6 +3141,12 @@ static int get_opts(int argc, char **argv)
case OPT_RSP_CERT:
opt_rsp_cert = opt_str();
break;
case OPT_RSP_CERT_KEY:
opt_rsp_cert_key = opt_str();
break;
case OPT_RSP_KEYPASS:
opt_rsp_keypass = opt_str();
break;
case OPT_RSP_CRL:
opt_rsp_crl = opt_str();
break;
Expand Down
2 changes: 2 additions & 0 deletions apps/include/cmp_mock_srv.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx);

int ossl_cmp_mock_srv_set1_refCert(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert);
int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert);
int ossl_cmp_mock_srv_set1_certOutKey(OSSL_CMP_SRV_CTX *srv_ctx,
EVP_PKEY *pkey);
int ossl_cmp_mock_srv_set1_crlOut(OSSL_CMP_SRV_CTX *srv_ctx, X509_CRL *crl);
int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx,
STACK_OF(X509) *chain);
Expand Down
25 changes: 25 additions & 0 deletions apps/lib/cmp_mock_srv.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
typedef struct {
X509 *refCert; /* cert to expect for oldCertID in kur/rr msg */
X509 *certOut; /* certificate to be returned in cp/ip/kup msg */
EVP_PKEY *certOutKey; /* Private key to be returned for central keygen */
X509_CRL *crlOut; /* CRL to be returned in genp for crls */
STACK_OF(X509) *chainOut; /* chain of certOut to add to extraCerts field */
STACK_OF(X509) *caPubsOut; /* used in caPubs of ip and in caCerts of genp */
Expand Down Expand Up @@ -87,6 +88,22 @@ static mock_srv_ctx *mock_srv_ctx_new(void)
DEFINE_OSSL_SET1_CERT(refCert)
DEFINE_OSSL_SET1_CERT(certOut)

int ossl_cmp_mock_srv_set1_certOutKey(OSSL_CMP_SRV_CTX *srv_ctx,
EVP_PKEY *pkey)
{
mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);

if (ctx == NULL) {
ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
return 0;
}
if (pkey != NULL && !EVP_PKEY_up_ref(pkey))
return 0;
EVP_PKEY_free(ctx->certOutKey);
ctx->certOutKey = pkey;
return 1;
}

int ossl_cmp_mock_srv_set1_crlOut(OSSL_CMP_SRV_CTX *srv_ctx,
X509_CRL *crl)
{
Expand Down Expand Up @@ -275,6 +292,7 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
int bodytype;
OSSL_CMP_PKISI *si = NULL;
EVP_PKEY *certOutKey = NULL;

if (ctx == NULL || cert_req == NULL
|| certOut == NULL || chainOut == NULL || caPubs == NULL) {
Expand Down Expand Up @@ -358,6 +376,13 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
&& (*certOut = X509_dup(ctx->certOut)) == NULL)
/* Should return a cert produced from request template, see FR #16054 */
goto err;
if (ctx->certOutKey != NULL
&& OSSL_CMP_SRV_CTX_centralKeygen_req(crm, (X509_REQ *) p10cr)
/* using newPkey to return the private key */
&& (((certOutKey = EVP_PKEY_dup(ctx->certOutKey)) == NULL)
|| !OSSL_CMP_CTX_set0_newPkey(OSSL_CMP_SRV_CTX_get0_cmp_ctx(srv_ctx),
1 /* priv */, certOutKey)))
goto err;
if (ctx->chainOut != NULL
&& (*chainOut = X509_chain_up_ref(ctx->chainOut)) == NULL)
goto err;
Expand Down
3 changes: 2 additions & 1 deletion crypto/cmp/cmp_local.h
Original file line number Diff line number Diff line change
Expand Up @@ -952,7 +952,8 @@ OSSL_CMP_MSG *ossl_cmp_certreq_new(OSSL_CMP_CTX *ctx, int bodytype,
const OSSL_CRMF_MSG *crm);
OSSL_CMP_MSG *ossl_cmp_certrep_new(OSSL_CMP_CTX *ctx, int bodytype,
int certReqId, const OSSL_CMP_PKISI *si,
X509 *cert, const X509 *encryption_recip,
X509 *cert, EVP_PKEY *certkey,
const X509 *encryption_recip,
STACK_OF(X509) *chain, STACK_OF(X509) *caPubs,
int unprotectedErrors);
OSSL_CMP_MSG *ossl_cmp_rr_new(OSSL_CMP_CTX *ctx);
Expand Down
38 changes: 37 additions & 1 deletion crypto/cmp/cmp_msg.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#include <openssl/crmf.h>
#include <openssl/err.h>
#include <openssl/x509.h>
#include <openssl/cms.h>
#include <openssl/pem.h>
#include <openssl/bio.h>

OSSL_CMP_MSG *OSSL_CMP_MSG_new(OSSL_LIB_CTX *libctx, const char *propq)
{
Expand Down Expand Up @@ -449,9 +452,39 @@ OSSL_CMP_MSG *ossl_cmp_certreq_new(OSSL_CMP_CTX *ctx, int type,
return NULL;
}

static OSSL_CRMF_ENCRYPTEDKEY *encprivatekey(OSSL_CMP_CTX *ctx, EVP_PKEY *privKey)
{
OSSL_CRMF_ENCRYPTEDKEY *ek = NULL;
CMS_EnvelopedData *envData = NULL;
STACK_OF(X509) *encryption_recips = NULL;
int res = 0;
X509 *recip = X509_dup(ctx->validatedSrvCert);

encryption_recips = sk_X509_new_null();
if (encryption_recips == NULL || recip == NULL
|| !sk_X509_push(encryption_recips, recip))
goto err;

envData = OSSL_CMS_env_sign_key(privKey, ctx->cert, ctx->pkey,
encryption_recips, ctx->libctx, ctx->propq);
if (envData == NULL)
goto err;
if ((ek = OSSL_CRMF_ENCRYPTEDKEY_init_envdata(envData)) == NULL)
goto err;
res = 1;

err:
sk_X509_pop_free(encryption_recips, X509_free);
if (!res)
M_ASN1_free_of(envData, CMS_EnvelopedData);

return ek;
}

OSSL_CMP_MSG *ossl_cmp_certrep_new(OSSL_CMP_CTX *ctx, int bodytype,
int certReqId, const OSSL_CMP_PKISI *si,
X509 *cert, const X509 *encryption_recip,
X509 *cert, EVP_PKEY *certkey,
const X509 *encryption_recip,
STACK_OF(X509) *chain, STACK_OF(X509) *caPubs,
int unprotectedErrors)
{
Expand Down Expand Up @@ -495,6 +528,9 @@ OSSL_CMP_MSG *ossl_cmp_certrep_new(OSSL_CMP_CTX *ctx, int bodytype,
if (!X509_up_ref(cert))
goto err;
resp->certifiedKeyPair->certOrEncCert->value.certificate = cert;

if (certkey != NULL)
resp->certifiedKeyPair->privateKey = encprivatekey(ctx, certkey);
}

if (!sk_OSSL_CMP_CERTRESPONSE_push(repMsg->response, resp))
Expand Down
32 changes: 29 additions & 3 deletions crypto/cmp/cmp_server.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,6 +205,27 @@ static OSSL_CMP_MSG *delayed_delivery(OSSL_CMP_SRV_CTX *srv_ctx,
return msg;
}

int OSSL_CMP_SRV_CTX_centralKeygen_req(const OSSL_CRMF_MSG *crm,
X509_REQ *p10cr)
{
X509_PUBKEY *pubkey = NULL;
const unsigned char *pk = NULL;
int pklen, ret = 0;

if (crm != NULL)
pubkey = OSSL_CRMF_CERTTEMPLATE_get0_publicKey(OSSL_CRMF_MSG_get0_tmpl(crm));
else if (p10cr != NULL)
pubkey = X509_REQ_get_X509_PUBKEY(p10cr);

if (pubkey == NULL
|| (X509_PUBKEY_get0_param(NULL, &pk, &pklen, NULL, pubkey)
&& pklen == 0))
ret = 1;

pk = NULL;
return ret;
}

/*
* Processes an ir/cr/p10cr/kur and returns a certification response.
* Only handles the first certification request contained in req
Expand All @@ -216,9 +237,10 @@ static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
OSSL_CMP_MSG *msg = NULL;
OSSL_CMP_PKISI *si = NULL;
X509 *certOut = NULL;
EVP_PKEY *certOutKey = NULL;
STACK_OF(X509) *chainOut = NULL, *caPubs = NULL;
const OSSL_CRMF_MSG *crm = NULL;
const X509_REQ *p10cr = NULL;
X509_REQ *p10cr = NULL;
int bodytype;
int certReqId;

Expand Down Expand Up @@ -263,7 +285,8 @@ static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
}
srv_ctx->certReqId = certReqId;

if (!ossl_cmp_verify_popo(srv_ctx->ctx, req, srv_ctx->acceptRAVerified)) {
if (!(OSSL_CMP_SRV_CTX_centralKeygen_req(crm, p10cr)
|| ossl_cmp_verify_popo(srv_ctx->ctx, req, srv_ctx->acceptRAVerified))) {
/* Proof of possession could not be verified */
si = OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_rejection,
1 << OSSL_CMP_PKIFAILUREINFO_badPOP,
Expand All @@ -287,10 +310,12 @@ static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
/* do not set if polling starts: */
&& certOut != NULL))
goto err;
if (srv_ctx->ctx->newPkey != NULL && srv_ctx->ctx->newPkey_priv)
certOutKey = srv_ctx->ctx->newPkey;
}

msg = ossl_cmp_certrep_new(srv_ctx->ctx, bodytype, certReqId, si,
certOut, NULL /* enc */, chainOut, caPubs,
certOut, certOutKey, NULL /* enc */, chainOut, caPubs,
srv_ctx->sendUnprotectedErrors);
/* When supporting OSSL_CRMF_POPO_KEYENC, "enc" will need to be set */
if (msg == NULL)
Expand All @@ -299,6 +324,7 @@ static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
err:
OSSL_CMP_PKISI_free(si);
X509_free(certOut);
OSSL_CMP_CTX_set0_newPkey(srv_ctx->ctx, 0, NULL);
OSSL_STACK_OF_X509_free(chainOut);
OSSL_STACK_OF_X509_free(caPubs);
return msg;
Expand Down
1 change: 1 addition & 0 deletions crypto/cms/cms_asn1.c
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,7 @@ ASN1_NDEF_SEQUENCE(CMS_EnvelopedData) = {
ASN1_SIMPLE(CMS_EnvelopedData, encryptedContentInfo, CMS_EncryptedContentInfo),
ASN1_IMP_SET_OF_OPT(CMS_EnvelopedData, unprotectedAttrs, X509_ATTRIBUTE, 1)
} ASN1_NDEF_SEQUENCE_END(CMS_EnvelopedData)
IMPLEMENT_ASN1_DUP_FUNCTION(CMS_EnvelopedData)

ASN1_NDEF_SEQUENCE(CMS_DigestedData) = {
ASN1_EMBED(CMS_DigestedData, version, INT32),
Expand Down
39 changes: 39 additions & 0 deletions crypto/cms/cms_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -739,3 +739,42 @@ int ossl_cms_set1_keyid(ASN1_OCTET_STRING **pkeyid, X509 *cert)
*pkeyid = keyid;
return 1;
}

CMS_EnvelopedData *OSSL_CMS_env_sign_key(EVP_PKEY *privKey, /* TODO - take bio as input */
X509 *signcert, EVP_PKEY *signkey,
STACK_OF(X509) *encryption_recip,
OSSL_LIB_CTX *libctx, const char *propq)
{
CMS_EnvelopedData *evd = NULL;
BIO *privbio = NULL, *signbio = NULL, *envelopbio = NULL;
CMS_ContentInfo *signcms = NULL, *evpcms = NULL;

privbio = BIO_new(BIO_s_mem());
if (privbio == NULL || i2d_PrivateKey_bio(privbio, privKey) <= 0)
goto err;

signcms = CMS_sign_ex(signcert, signkey, NULL, privbio, CMS_BINARY,
libctx, propq);
if (signcms == NULL)
goto err;

signbio = BIO_new(BIO_s_mem());
if (signbio == NULL
|| ASN1_item_i2d_bio(ASN1_ITEM_rptr(CMS_SignedData), signbio, signcms->d.signedData) <= 0)
goto err;

evpcms = CMS_encrypt_ex(encryption_recip, signbio,
EVP_aes_256_cbc(), CMS_BINARY, libctx, propq);
if (evpcms == NULL)
goto err;
evd = CMS_EnvelopedData_dup(evpcms->d.envelopedData);

err:
BIO_free(privbio);
BIO_free(signbio);
BIO_free(envelopbio);
CMS_ContentInfo_free(signcms);
CMS_ContentInfo_free(evpcms);

return evd;
}
23 changes: 13 additions & 10 deletions crypto/crmf/crmf_lib.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
#include <openssl/crmf.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/cms.h>

/*-
* atyp = Attribute Type
Expand Down Expand Up @@ -627,18 +628,8 @@ static int check_cmKGA(ossl_unused const X509_PURPOSE *purpose,
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;

Expand Down Expand Up @@ -912,3 +903,15 @@ X509
return NULL;
#endif /* OPENSSL_NO_CMS */
}

OSSL_CRMF_ENCRYPTEDKEY
*OSSL_CRMF_ENCRYPTEDKEY_init_envdata(CMS_EnvelopedData *envdata)
{
OSSL_CRMF_ENCRYPTEDKEY *ek = OSSL_CRMF_ENCRYPTEDKEY_new();

if (ek == NULL)
return NULL;
ek->type = OSSL_CRMF_ENCRYPTEDKEY_ENVELOPEDDATA;
ek->value.envelopedData = envdata;
return ek;
}
2 changes: 2 additions & 0 deletions include/openssl/cmp.h.in
Original file line number Diff line number Diff line change
Expand Up @@ -542,6 +542,8 @@ int OSSL_CMP_SRV_CTX_set_accept_unprotected(OSSL_CMP_SRV_CTX *srv_ctx, int val);
int OSSL_CMP_SRV_CTX_set_accept_raverified(OSSL_CMP_SRV_CTX *srv_ctx, int val);
int OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(OSSL_CMP_SRV_CTX *srv_ctx,
int val);
int OSSL_CMP_SRV_CTX_centralKeygen_req(const OSSL_CRMF_MSG *crm,
X509_REQ *p10cr);

/* from cmp_client.c */
X509 *OSSL_CMP_exec_certreq(OSSL_CMP_CTX *ctx, int req_type,
Expand Down
Loading

0 comments on commit 9528eff

Please sign in to comment.