Skip to content

Commit

Permalink
CMP mock server: add -ref_cert option and corresponding ossl_cmp_mock…
Browse files Browse the repository at this point in the history
…_srv_set1_refCert()

Fixes #16041

Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from #16050)
  • Loading branch information
DDvO committed Jan 4, 2022
1 parent acef3b2 commit b971d41
Show file tree
Hide file tree
Showing 7 changed files with 80 additions and 24 deletions.
23 changes: 20 additions & 3 deletions apps/cmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ static char *opt_srv_keypass = NULL;

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_extracerts = NULL;
static char *opt_rsp_capubs = NULL;
Expand Down Expand Up @@ -249,7 +250,7 @@ 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_RSP_CERT, OPT_RSP_EXTRACERTS, OPT_RSP_CAPUBS,
OPT_REF_CERT, OPT_RSP_CERT, OPT_RSP_EXTRACERTS, OPT_RSP_CAPUBS,
OPT_POLL_COUNT, OPT_CHECK_AFTER,
OPT_GRANT_IMPLICITCONF,
OPT_PKISTATUS, OPT_FAILURE,
Expand Down Expand Up @@ -498,6 +499,8 @@ const OPTIONS cmp_options[] = {
"Trusted certificates for client authentication"},
{"srv_untrusted", OPT_SRV_UNTRUSTED, 's',
"Intermediate certs that may be useful for verifying CMP protection"},
{"ref_cert", OPT_RSP_CERT, 's',
"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_extracerts", OPT_RSP_EXTRACERTS, 's',
Expand Down Expand Up @@ -600,7 +603,7 @@ 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_rsp_cert}, {&opt_rsp_extracerts}, {&opt_rsp_capubs},
{&opt_ref_cert}, {&opt_rsp_cert}, {&opt_rsp_extracerts}, {&opt_rsp_capubs},
{(char **)&opt_poll_count}, {(char **)&opt_check_after},
{(char **)&opt_grant_implicitconf},
{(char **)&opt_pkistatus}, {(char **)&opt_failure},
Expand Down Expand Up @@ -1074,6 +1077,18 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine)
(add_X509_stack_fn_t)OSSL_CMP_CTX_set1_untrusted))
goto err;

if (opt_ref_cert != NULL) {
X509 *cert = load_cert_pwd(opt_ref_cert, opt_keypass,
"reference cert to be expected by the mock server");

if (cert == NULL)
goto err;
if (!ossl_cmp_mock_srv_set1_refCert(srv_ctx, cert)) {
X509_free(cert);
goto err;
}
X509_free(cert);
}
if (opt_rsp_cert == NULL) {
CMP_warn("no -rsp_cert given for mock server");
} else {
Expand All @@ -1082,7 +1097,6 @@ static OSSL_CMP_SRV_CTX *setup_srv_ctx(ENGINE *engine)

if (cert == NULL)
goto err;
/* from server perspective the server is the client */
if (!ossl_cmp_mock_srv_set1_certOut(srv_ctx, cert)) {
X509_free(cert);
goto err;
Expand Down Expand Up @@ -2573,6 +2587,9 @@ static int get_opts(int argc, char **argv)
case OPT_SRV_UNTRUSTED:
opt_srv_untrusted = opt_str();
break;
case OPT_REF_CERT:
opt_ref_cert = opt_str();
break;
case OPT_RSP_CERT:
opt_rsp_cert = opt_str();
break;
Expand Down
1 change: 1 addition & 0 deletions apps/include/cmp_mock_srv.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(OSSL_LIB_CTX *libctx,
const char *propq);
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_chainOut(OSSL_CMP_SRV_CTX *srv_ctx,
STACK_OF(X509) *chain);
Expand Down
63 changes: 43 additions & 20 deletions apps/lib/cmp_mock_srv.c
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
/* the context for the CMP mock server */
typedef struct
{
X509 *refCert; /* cert to expect for oldCertID in kur/rr msg */
X509 *certOut; /* certificate to be returned in cp/ip/kup msg */
STACK_OF(X509) *chainOut; /* chain of certOut to add to extraCerts field */
STACK_OF(X509) *caPubsOut; /* certs to return in caPubs field of ip msg */
Expand All @@ -37,6 +38,7 @@ static void mock_srv_ctx_free(mock_srv_ctx *ctx)
return;

OSSL_CMP_PKISI_free(ctx->statusOut);
X509_free(ctx->refCert);
X509_free(ctx->certOut);
OSSL_STACK_OF_X509_free(ctx->chainOut);
OSSL_STACK_OF_X509_free(ctx->caPubsOut);
Expand All @@ -63,6 +65,22 @@ static mock_srv_ctx *mock_srv_ctx_new(void)
return NULL;
}

int ossl_cmp_mock_srv_set1_refCert(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert)
{
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 (cert == NULL || X509_up_ref(cert)) {
X509_free(ctx->refCert);
ctx->refCert = cert;
return 1;
}
return 0;
}

int ossl_cmp_mock_srv_set1_certOut(OSSL_CMP_SRV_CTX *srv_ctx, X509 *cert)
{
mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx);
Expand Down Expand Up @@ -170,6 +188,21 @@ int ossl_cmp_mock_srv_set_checkAfterTime(OSSL_CMP_SRV_CTX *srv_ctx, int sec)
return 1;
}

/* check for matching reference cert components, as far as given */
static int refcert_cmp(const X509 *refcert,
const X509_NAME *issuer, const ASN1_INTEGER *serial)
{
const X509_NAME *ref_issuer;
const ASN1_INTEGER *ref_serial;

if (refcert == NULL)
return 1;
ref_issuer = X509_get_issuer_name(refcert);
ref_serial = X509_get0_serialNumber(refcert);
return (ref_issuer == NULL || X509_NAME_cmp(issuer, ref_issuer) == 0)
&& (ref_serial == NULL || ASN1_INTEGER_cmp(serial, ref_serial) == 0);
}

static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
const OSSL_CMP_MSG *cert_req,
int certReqId,
Expand Down Expand Up @@ -212,24 +245,18 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
/* give final response after polling */
ctx->curr_pollCount = 0;

/* accept cert update request only for the reference cert, if given */
if (OSSL_CMP_MSG_get_bodytype(cert_req) == OSSL_CMP_KUR
&& crm != NULL && ctx->certOut != NULL) {
&& crm != NULL /* thus not p10cr */ && ctx->refCert != NULL) {
const OSSL_CRMF_CERTID *cid = OSSL_CRMF_MSG_get0_regCtrl_oldCertID(crm);
const X509_NAME *issuer = X509_get_issuer_name(ctx->certOut);
const ASN1_INTEGER *serial = X509_get0_serialNumber(ctx->certOut);

if (cid == NULL) {
ERR_raise(ERR_LIB_CMP, CMP_R_MISSING_CERTID);
return NULL;
}
if (issuer != NULL
&& X509_NAME_cmp(issuer, OSSL_CRMF_CERTID_get0_issuer(cid)) != 0) {
ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_CERTID);
return NULL;
}
if (serial != NULL
&& ASN1_INTEGER_cmp(serial,
OSSL_CRMF_CERTID_get0_serialNumber(cid)) != 0) {
if (!refcert_cmp(ctx->refCert,
OSSL_CRMF_CERTID_get0_issuer(cid),
OSSL_CRMF_CERTID_get0_serialNumber(cid))) {
ERR_raise(ERR_LIB_CMP, CMP_R_WRONG_CERTID);
return NULL;
}
Expand Down Expand Up @@ -270,19 +297,15 @@ static OSSL_CMP_PKISI *process_rr(OSSL_CMP_SRV_CTX *srv_ctx,
ERR_raise(ERR_LIB_CMP, CMP_R_NULL_ARGUMENT);
return NULL;
}
if (ctx->sendError || ctx->certOut == NULL) {
if (ctx->sendError) {
ERR_raise(ERR_LIB_CMP, CMP_R_ERROR_PROCESSING_MESSAGE);
return NULL;
}

/* Allow any RR derived from CSR, which may include subject and serial */
if (issuer == NULL || serial == NULL)
return OSSL_CMP_PKISI_dup(ctx->statusOut);

/* accept revocation only for the certificate we sent in ir/cr/kur */
if (X509_NAME_cmp(issuer, X509_get_issuer_name(ctx->certOut)) != 0
|| ASN1_INTEGER_cmp(serial,
X509_get0_serialNumber(ctx->certOut)) != 0) {
/* allow any RR derived from CSR which does not include issuer and serial */
if ((issuer != NULL || serial != NULL)
/* accept revocation only for the reference cert, if given */
&& !refcert_cmp(ctx->refCert, issuer, serial)) {
ERR_raise_data(ERR_LIB_CMP, CMP_R_REQUEST_NOT_ACCEPTED,
"wrong certificate to revoke");
return NULL;
Expand Down
10 changes: 9 additions & 1 deletion doc/internal/man3/ossl_cmp_mock_srv_new.pod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

ossl_cmp_mock_srv_new,
ossl_cmp_mock_srv_free,
ossl_cmp_mock_srv_set1_refCert,
ossl_cmp_mock_srv_set1_certOut,
ossl_cmp_mock_srv_set1_chainOut,
ossl_cmp_mock_srv_set1_caPubsOut,
Expand All @@ -20,6 +21,7 @@ ossl_cmp_mock_srv_set_checkAfterTime
OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(OSSL_LIB_CTX *libctx, const char *propq);
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_chainOut(OSSL_CMP_SRV_CTX *srv_ctx,
STACK_OF(X509) *chain);
Expand All @@ -39,12 +41,18 @@ I<propq>, both of which may be NULL to select the defaults.

ossl_cmp_mock_srv_free() deallocates the contexts for the CMP mock server.

OSSL_CMP_SRV_CTX_set1_refCert() sets the reference certificate to be expected
for rr messages and for any oldCertID included in kur messages.

OSSL_CMP_SRV_CTX_set1_certOut() sets the certificate to be returned in
cp/ip/kup.
Note that on each certificate request the mock server does not produce
a fresh certificate but just returns the same pre-existing certificate.

OSSL_CMP_SRV_CTX_set1_chainOut() sets the certificate chain to be added to
the extraCerts in a cp/ip/kup.
It should to useful to validate B<certOut>.
It should be useful for the validation of the certificate given via
OSSL_CMP_SRV_CTX_set1_certOut().

OSSL_CMP_SRV_CTX_set1_caPubsOut() sets the caPubs to be returned in an ip.

Expand Down
5 changes: 5 additions & 0 deletions doc/man1/openssl-cmp.pod.in
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,7 @@ Mock server options:
[B<-srv_keypass> I<arg>]
[B<-srv_trusted> I<filenames>|I<uris>]
[B<-srv_untrusted> I<filenames>|I<uris>]
[B<-ref_cert> I<filename>|I<uri>]
[B<-rsp_cert> I<filename>|I<uri>]
[B<-rsp_extracerts> I<filenames>|I<uris>]
[B<-rsp_capubs> I<filenames>|I<uris>]
Expand Down Expand Up @@ -959,6 +960,10 @@ have no effect on the certificate verification enabled via this option.

Intermediate CA certs that may be useful when validating client certificates.

=item B<-ref_cert> I<filename>|I<uri>

Certificate to be expected for RR messages and any oldCertID in KUR messages.

=item B<-rsp_cert> I<filename>|I<uri>

Certificate to be returned as mock enrollment result.
Expand Down
1 change: 1 addition & 0 deletions test/cmp_client_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ static CMP_SES_TEST_FIXTURE *set_up(const char *const test_case_name)
fixture->test_case_name = test_case_name;
if (!TEST_ptr(fixture->srv_ctx = ossl_cmp_mock_srv_new(libctx, NULL))
|| !OSSL_CMP_SRV_CTX_set_accept_unprotected(fixture->srv_ctx, 1)
|| !ossl_cmp_mock_srv_set1_refCert(fixture->srv_ctx, client_cert)
|| !ossl_cmp_mock_srv_set1_certOut(fixture->srv_ctx, client_cert)
|| (srv_cmp_ctx =
OSSL_CMP_SRV_CTX_get0_cmp_ctx(fixture->srv_ctx)) == NULL
Expand Down
1 change: 1 addition & 0 deletions test/recipes/80-test_cmp_http_data/Mock/server.cnf
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ srv_secret = pass:test
no_check_time = 1
srv_trusted = signer_root.crt

ref_cert = signer_only.crt
rsp_cert = signer_only.crt
rsp_capubs = signer_root.crt
rsp_extracerts = signer_issuing.crt
Expand Down

0 comments on commit b971d41

Please sign in to comment.