From: Dr. David von Oheimb Date: Tue, 10 Mar 2020 09:29:46 +0000 (+0100) Subject: Chunk 8 of CMP contribution to OpenSSL: CMP server and cmp_mock_srv.c for testing X-Git-Tag: openssl-3.0.0-alpha1~291 X-Git-Url: http://git.ipfire.org/?p=thirdparty%2Fopenssl.git;a=commitdiff_plain;h=62dcd2aa17b27b7892ad62540f9034c9192f6530 Chunk 8 of CMP contribution to OpenSSL: CMP server and cmp_mock_srv.c for testing Certificate Management Protocol (CMP, RFC 4210) extension to OpenSSL Also includes CRMF (RFC 4211) and HTTP transfer (RFC 6712). Adds the CMP and CRMF API to libcrypto and the "cmp" app to the CLI. Adds extensive documentation and tests. Reviewed-by: Matt Caswell Reviewed-by: David von Oheimb (Merged from https://github.com/openssl/openssl/pull/11142) --- diff --git a/apps/build.info b/apps/build.info index 495e56065e..2186de3a27 100644 --- a/apps/build.info +++ b/apps/build.info @@ -23,6 +23,9 @@ IF[{- !$disabled{'deprecated-3.0'} -}] $OPENSSLSRC=$OPENSSLSRC \ dhparam.c dsa.c dsaparam.c gendsa.c rsa.c rsautl.c genrsa.c ENDIF +IF[{- !$disabled{'cmp'} -}] + $OPENSSLSRC=$OPENSSLSRC cmp_mock_srv.c +ENDIF IF[{- !$disabled{apps} -}] PROGRAMS=openssl diff --git a/apps/cmp_mock_srv.c b/apps/cmp_mock_srv.c new file mode 100644 index 0000000000..4cdda2417d --- /dev/null +++ b/apps/cmp_mock_srv.c @@ -0,0 +1,406 @@ +/* + * Copyright 2018-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright Siemens AG 2018-2020 + * + * 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 atf + * https://www.openssl.org/source/license.html + */ + +#include "apps.h" +#include "cmp_mock_srv.h" + +#include +#include +#include + +/* the context for the CMP mock server */ +typedef struct +{ + 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 */ + OSSL_CMP_PKISI *statusOut; /* status for ip/cp/kup/rp msg unless polling */ + int sendError; /* send error response also on valid requests */ + OSSL_CMP_MSG *certReq; /* ir/cr/p10cr/kur remembered while polling */ + int certReqId; /* id of last ir/cr/kur, used for polling */ + int pollCount; /* number of polls before actual cert response */ + int checkAfterTime; /* time the client should wait between polling */ +} mock_srv_ctx; + + +static void mock_srv_ctx_free(mock_srv_ctx *ctx) +{ + if (ctx == NULL) + return; + + OSSL_CMP_PKISI_free(ctx->statusOut); + X509_free(ctx->certOut); + sk_X509_pop_free(ctx->chainOut, X509_free); + sk_X509_pop_free(ctx->caPubsOut, X509_free); + OSSL_CMP_MSG_free(ctx->certReq); + OPENSSL_free(ctx); +} + +static mock_srv_ctx *mock_srv_ctx_new(void) +{ + mock_srv_ctx *ctx = OPENSSL_zalloc(sizeof(mock_srv_ctx)); + + if (ctx == NULL) + goto err; + + if ((ctx->statusOut = OSSL_CMP_PKISI_new()) == NULL) + goto err; + + ctx->certReqId = -1; + + /* all other elements are initialized to 0 or NULL, respectively */ + return ctx; + err: + mock_srv_ctx_free(ctx); + return NULL; +} + +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); + + if (ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + if (cert == NULL || X509_up_ref(cert)) { + X509_free(ctx->certOut); + ctx->certOut = cert; + return 1; + } + return 0; +} + +int ossl_cmp_mock_srv_set1_chainOut(OSSL_CMP_SRV_CTX *srv_ctx, + STACK_OF(X509) *chain) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + STACK_OF(X509) *chain_copy = NULL; + + if (ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + if (chain != NULL && (chain_copy = X509_chain_up_ref(chain)) == NULL) + return 0; + sk_X509_pop_free(ctx->chainOut, X509_free); + ctx->chainOut = chain_copy; + return 1; +} + +int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx, + STACK_OF(X509) *caPubs) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + STACK_OF(X509) *caPubs_copy = NULL; + + if (ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + if (caPubs != NULL && (caPubs_copy = X509_chain_up_ref(caPubs)) == NULL) + return 0; + sk_X509_pop_free(ctx->caPubsOut, X509_free); + ctx->caPubsOut = caPubs_copy; + return 1; +} + +int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status, + int fail_info, const char *text) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + OSSL_CMP_PKISI *si; + + if (ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + if ((si = OSSL_CMP_STATUSINFO_new(status, fail_info, text)) == NULL) + return 0; + OSSL_CMP_PKISI_free(ctx->statusOut); + ctx->statusOut = si; + return 1; +} + +int ossl_cmp_mock_srv_set_send_error(OSSL_CMP_SRV_CTX *srv_ctx, int val) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + ctx->sendError = val != 0; + return 1; +} + +int ossl_cmp_mock_srv_set_pollCount(OSSL_CMP_SRV_CTX *srv_ctx, int count) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + if (count < 0) { + CMPerr(0, CMP_R_INVALID_ARGS); + return 0; + } + ctx->pollCount = count; + return 1; +} + +int ossl_cmp_mock_srv_set_checkAfterTime(OSSL_CMP_SRV_CTX *srv_ctx, int sec) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + ctx->checkAfterTime = sec; + return 1; +} + +static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *cert_req, + int certReqId, + const OSSL_CRMF_MSG *crm, + const X509_REQ *p10cr, + X509 **certOut, + STACK_OF(X509) **chainOut, + STACK_OF(X509) **caPubs) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + OSSL_CMP_PKISI *si = NULL; + + if (ctx == NULL || cert_req == NULL + || certOut == NULL || chainOut == NULL || caPubs == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return NULL; + } + if (ctx->sendError) { + CMPerr(0, CMP_R_ERROR_PROCESSING_MSG); + return NULL; + } + + *certOut = NULL; + *chainOut = NULL; + *caPubs = NULL; + ctx->certReqId = certReqId; + if (ctx->pollCount > 0) { + ctx->pollCount--; + OSSL_CMP_MSG_free(ctx->certReq); + if ((ctx->certReq = OSSL_CMP_MSG_dup(cert_req)) == NULL) + return NULL; + return OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_waiting, 0, NULL); + } + if (ctx->certOut != NULL + && (*certOut = X509_dup(ctx->certOut)) == NULL) + goto err; + if (ctx->chainOut != NULL + && (*chainOut = X509_chain_up_ref(ctx->chainOut)) == NULL) + goto err; + if (ctx->caPubsOut != NULL + && (*caPubs = X509_chain_up_ref(ctx->caPubsOut)) == NULL) + goto err; + if (ctx->statusOut != NULL + && (si = OSSL_CMP_PKISI_dup(ctx->statusOut)) == NULL) + goto err; + return si; + + err: + X509_free(*certOut); + *certOut = NULL; + sk_X509_pop_free(*chainOut, X509_free); + *chainOut = NULL; + sk_X509_pop_free(*caPubs, X509_free); + *caPubs = NULL; + return NULL; +} + +static OSSL_CMP_PKISI *process_rr(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *rr, + const X509_NAME *issuer, + const ASN1_INTEGER *serial) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL || rr == NULL || issuer == NULL || serial == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return NULL; + } + if (ctx->sendError || ctx->certOut == NULL) { + CMPerr(0, CMP_R_ERROR_PROCESSING_MSG); + return NULL; + } + + /* 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) { + CMPerr(0, CMP_R_REQUEST_NOT_ACCEPTED); + return NULL; + } + return OSSL_CMP_PKISI_dup(ctx->statusOut); +} + +static int process_genm(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *genm, + const STACK_OF(OSSL_CMP_ITAV) *in, + STACK_OF(OSSL_CMP_ITAV) **out) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL || genm == NULL || in == NULL || out == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + if (ctx->sendError) { + CMPerr(0, CMP_R_ERROR_PROCESSING_MSG); + return 0; + } + + *out = sk_OSSL_CMP_ITAV_deep_copy(in, OSSL_CMP_ITAV_dup, + OSSL_CMP_ITAV_free); + return *out != NULL; +} + +static void process_error(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *error, + const OSSL_CMP_PKISI *statusInfo, + const ASN1_INTEGER *errorCode, + const OSSL_CMP_PKIFREETEXT *errorDetails) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + char buf[OSSL_CMP_PKISI_BUFLEN]; + char *sibuf; + int i; + + if (ctx == NULL || error == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return; + } + + BIO_printf(bio_err, "mock server received error:\n"); + + if (statusInfo == NULL) { + BIO_printf(bio_err, "pkiStatusInfo absent\n"); + } else { + sibuf = OSSL_CMP_snprint_PKIStatusInfo(statusInfo, buf, sizeof(buf)); + BIO_printf(bio_err, "pkiStatusInfo: %s\n", + sibuf != NULL ? sibuf: ""); + } + + if (errorCode == NULL) + BIO_printf(bio_err, "errorCode absent\n"); + else + BIO_printf(bio_err, "errorCode: %ld\n", ASN1_INTEGER_get(errorCode)); + + if (sk_ASN1_UTF8STRING_num(errorDetails) <= 0) { + BIO_printf(bio_err, "errorDetails absent\n"); + } else { + BIO_printf(bio_err, "errorDetails: "); + for (i = 0; i < sk_ASN1_UTF8STRING_num(errorDetails); i++) { + if (i > 0) + BIO_printf(bio_err, ", "); + BIO_printf(bio_err, "\""); + ASN1_STRING_print(bio_err, + sk_ASN1_UTF8STRING_value(errorDetails, i)); + BIO_printf(bio_err, "\""); + } + BIO_printf(bio_err, "\n"); + } +} + +static int process_certConf(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *certConf, int certReqId, + const ASN1_OCTET_STRING *certHash, + const OSSL_CMP_PKISI *si) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + ASN1_OCTET_STRING *digest; + + if (ctx == NULL || certConf == NULL || certHash == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + if (ctx->sendError || ctx->certOut == NULL) { + CMPerr(0, CMP_R_ERROR_PROCESSING_MSG); + return 0; + } + + if (certReqId != ctx->certReqId) { + /* in case of error, invalid reqId -1 */ + CMPerr(0, CMP_R_BAD_REQUEST_ID); + return 0; + } + + if ((digest = OSSL_CMP_X509_digest(ctx->certOut)) == NULL) + return 0; + if (ASN1_OCTET_STRING_cmp(certHash, digest) != 0) { + ASN1_OCTET_STRING_free(digest); + CMPerr(0, CMP_R_CERTHASH_UNMATCHED); + return 0; + } + ASN1_OCTET_STRING_free(digest); + return 1; +} + +static int process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *pollReq, int certReqId, + OSSL_CMP_MSG **certReq, int64_t *check_after) +{ + mock_srv_ctx *ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx); + + if (ctx == NULL || pollReq == NULL + || certReq == NULL || check_after == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + if (ctx->sendError || ctx->certReq == NULL) { + *certReq = NULL; + CMPerr(0, CMP_R_ERROR_PROCESSING_MSG); + return 0; + } + + if (ctx->pollCount == 0) { + *certReq = ctx->certReq; + ctx->certReq = NULL; + *check_after = 0; + } else { + ctx->pollCount--; + *certReq = NULL; + *check_after = ctx->checkAfterTime; + } + return 1; +} + +OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(void) +{ + OSSL_CMP_SRV_CTX *srv_ctx = OSSL_CMP_SRV_CTX_new(); + mock_srv_ctx *ctx = mock_srv_ctx_new(); + + if (srv_ctx != NULL && ctx != NULL + && OSSL_CMP_SRV_CTX_init(srv_ctx, ctx, process_cert_request, + process_rr, process_genm, process_error, + process_certConf, process_pollReq)) + return srv_ctx; + + mock_srv_ctx_free(ctx); + OSSL_CMP_SRV_CTX_free(srv_ctx); + return NULL; +} + +void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx) +{ + if (srv_ctx != NULL) + mock_srv_ctx_free(OSSL_CMP_SRV_CTX_get0_custom_ctx(srv_ctx)); + OSSL_CMP_SRV_CTX_free(srv_ctx); +} diff --git a/apps/cmp_mock_srv.h b/apps/cmp_mock_srv.h new file mode 100644 index 0000000000..bddc44df5b --- /dev/null +++ b/apps/cmp_mock_srv.h @@ -0,0 +1,34 @@ +/* + * Copyright 2018-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright Siemens AG 2018-2020 + * + * 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_APPS_CMP_MOCK_SRV_H +# define OSSL_APPS_CMP_MOCK_SRV_H + +# include +# ifndef OPENSSL_NO_CMP + +# include + +OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(void); +void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx); + +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); +int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx, + STACK_OF(X509) *caPubs); +int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status, + int fail_info, const char *text); +int ossl_cmp_mock_srv_set_send_error(OSSL_CMP_SRV_CTX *srv_ctx, int val); +int ossl_cmp_mock_srv_set_pollCount(OSSL_CMP_SRV_CTX *srv_ctx, int count); +int ossl_cmp_mock_srv_set_checkAfterTime(OSSL_CMP_SRV_CTX *srv_ctx, int sec); + +# endif /* !defined(OPENSSL_NO_CMP) */ +#endif /* !defined(OSSL_APPS_CMP_MOCK_SRV_H) */ diff --git a/crypto/cmp/build.info b/crypto/cmp/build.info index 41a5899319..1667334e2a 100644 --- a/crypto/cmp/build.info +++ b/crypto/cmp/build.info @@ -1,3 +1,4 @@ LIBS=../../libcrypto SOURCE[../../libcrypto]= cmp_asn.c cmp_ctx.c cmp_err.c cmp_util.c \ - cmp_status.c cmp_hdr.c cmp_protect.c cmp_msg.c cmp_vfy.c + cmp_status.c cmp_hdr.c cmp_protect.c cmp_msg.c cmp_vfy.c \ + cmp_server.c diff --git a/crypto/cmp/cmp_err.c b/crypto/cmp/cmp_err.c index f82ef9e325..0d311a8ddf 100644 --- a/crypto/cmp/cmp_err.c +++ b/crypto/cmp/cmp_err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2020 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 @@ -17,9 +17,12 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ALGORITHM_NOT_SUPPORTED), "algorithm not supported"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_BAD_REQUEST_ID), "bad request id"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTHASH_UNMATCHED), "certhash unmatched"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTID_NOT_FOUND), "certid not found"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTIFICATE_NOT_FOUND), "certificate not found"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTREQMSG_NOT_FOUND), + "certreqmsg not found"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTRESPONSE_NOT_FOUND), "certresponse not found"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERT_AND_KEY_DO_NOT_MATCH), @@ -48,10 +51,16 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_RR), "error creating rr"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_PARSING_PKISTATUS), "error parsing pkistatus"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_PROCESSING_MSG), + "error processing msg"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_PROTECTING_MESSAGE), "error protecting message"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_SETTING_CERTHASH), "error setting certhash"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_TRANSFERRING_OUT), + "error transferring out"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_UNEXPECTED_CERTCONF), + "error unexpected certconf"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_VALIDATING_PROTECTION), "error validating protection"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILED_EXTRACTING_PUBKEY), @@ -72,6 +81,8 @@ static const ERR_STRING_DATA CMP_str_reasons[] = { "missing sender identification"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_TRUST_STORE), "missing trust store"}, + {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED), + "multiple requests not supported"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MULTIPLE_SAN_SOURCES), "multiple san sources"}, {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_NO_STDIO), "no stdio"}, diff --git a/crypto/cmp/cmp_hdr.c b/crypto/cmp/cmp_hdr.c index 29f477f1b5..b5a9e9ba9e 100644 --- a/crypto/cmp/cmp_hdr.c +++ b/crypto/cmp/cmp_hdr.c @@ -153,25 +153,6 @@ int ossl_cmp_hdr_set1_senderKID(OSSL_CMP_PKIHEADER *hdr, } /* push the given text string to the given PKIFREETEXT ft */ -int ossl_cmp_pkifreetext_push_str(OSSL_CMP_PKIFREETEXT *ft, const char *text) -{ - ASN1_UTF8STRING *utf8string; - - if (!ossl_assert(ft != NULL && text != NULL)) - return 0; - if ((utf8string = ASN1_UTF8STRING_new()) == NULL) - return 0; - if (!ASN1_STRING_set(utf8string, text, -1)) - goto err; - if (!sk_ASN1_UTF8STRING_push(ft, utf8string)) - goto err; - return 1; - - err: - ASN1_UTF8STRING_free(utf8string); - return 0; -} - int ossl_cmp_hdr_push0_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text) { if (!ossl_assert(hdr != NULL && text != NULL)) @@ -193,7 +174,8 @@ int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text) && (hdr->freeText = sk_ASN1_UTF8STRING_new_null()) == NULL) return 0; - return ossl_cmp_pkifreetext_push_str(hdr->freeText, (char *)text->data); + return + ossl_cmp_sk_ASN1_UTF8STRING_push_str(hdr->freeText, (char *)text->data); } int ossl_cmp_hdr_generalInfo_push0_item(OSSL_CMP_PKIHEADER *hdr, @@ -205,7 +187,7 @@ int ossl_cmp_hdr_generalInfo_push0_item(OSSL_CMP_PKIHEADER *hdr, } int ossl_cmp_hdr_generalInfo_push1_items(OSSL_CMP_PKIHEADER *hdr, - STACK_OF(OSSL_CMP_ITAV) *itavs) + const STACK_OF(OSSL_CMP_ITAV) *itavs) { int i; OSSL_CMP_ITAV *itav; @@ -250,7 +232,7 @@ int ossl_cmp_hdr_set_implicitConfirm(OSSL_CMP_PKIHEADER *hdr) } /* return 1 if implicitConfirm in the generalInfo field of the header is set */ -int ossl_cmp_hdr_check_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr) +int ossl_cmp_hdr_has_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr) { int itavCount; int i; @@ -287,7 +269,7 @@ int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr) X509_get_subject_name(ctx->clCert) : ctx->subjectName; /* * The sender name is copied from the subject of the client cert, if any, - * or else from the the subject name provided for certification requests. + * or else from the subject name provided for certification requests. * As required by RFC 4210 section 5.1.1., if the sender name is not known * to the client it set to NULL-DN. In this case for identification at least * the senderKID must be set, which we take from any referenceValue given. diff --git a/crypto/cmp/cmp_local.h b/crypto/cmp/cmp_local.h index 015a3d4e67..ebc42d8c52 100644 --- a/crypto/cmp/cmp_local.h +++ b/crypto/cmp/cmp_local.h @@ -246,7 +246,6 @@ struct ossl_cmp_itav_st { } infoValue; } /* OSSL_CMP_ITAV */; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_ITAV) -DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_ITAV) typedef struct ossl_cmp_certorenccert_st { int type; @@ -284,8 +283,6 @@ struct ossl_cmp_pkisi_st { OSSL_CMP_PKIFREETEXT *statusString; OSSL_CMP_PKIFAILUREINFO *failInfo; } /* OSSL_CMP_PKISI */; -DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKISI) -DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_PKISI) DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTID) /*- @@ -296,10 +293,11 @@ DECLARE_ASN1_DUP_FUNCTION(OSSL_CRMF_CERTID) * crlEntryDetails Extensions OPTIONAL * } */ -typedef struct ossl_cmp_revdetails_st { +struct ossl_cmp_revdetails_st { OSSL_CRMF_CERTTEMPLATE *certDetails; X509_EXTENSIONS *crlEntryDetails; -} OSSL_CMP_REVDETAILS; +} /* OSSL_CMP_REVDETAILS */; +typedef struct ossl_cmp_revdetails_st OSSL_CMP_REVDETAILS; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_REVDETAILS) DEFINE_STACK_OF(OSSL_CMP_REVDETAILS) @@ -375,7 +373,6 @@ struct ossl_cmp_certstatus_st { OSSL_CMP_PKISI *statusInfo; } /* OSSL_CMP_CERTSTATUS */; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CERTSTATUS) - typedef STACK_OF(OSSL_CMP_CERTSTATUS) OSSL_CMP_CERTCONFIRMCONTENT; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_CERTCONFIRMCONTENT) @@ -670,7 +667,6 @@ struct ossl_cmp_msg_st { STACK_OF(X509) *extraCerts; /* 1 */ } /* OSSL_CMP_MSG */; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_MSG) -DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_MSG) /*- * ProtectedPart ::= SEQUENCE { @@ -728,17 +724,6 @@ DECLARE_ASN1_FUNCTIONS(CMP_PROTECTEDPART) * } */ -/* - * constants - */ -/* certReqId for the first - and so far only - certificate request */ -# define OSSL_CMP_CERTREQID 0 -/* sequence id for the first - and so far only - revocation request */ -# define OSSL_CMP_REVREQSID 0 -/* - * functions - */ - /* from cmp_asn.c */ int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a); @@ -755,6 +740,9 @@ int ossl_cmp_sk_X509_add1_certs(STACK_OF(X509) *sk, STACK_OF(X509) *certs, int no_self_issued, int no_dups, int prepend); int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs, int only_self_issued); +STACK_OF(X509) *ossl_cmp_X509_STORE_get1_certs(X509_STORE *store); +int ossl_cmp_sk_ASN1_UTF8STRING_push_str(STACK_OF(ASN1_UTF8STRING) *sk, + const char *text); int ossl_cmp_asn1_octet_string_set1(ASN1_OCTET_STRING **tgt, const ASN1_OCTET_STRING *src); int ossl_cmp_asn1_octet_string_set1_bytes(ASN1_OCTET_STRING **tgt, @@ -800,13 +788,11 @@ int ossl_cmp_ctx_set1_recipNonce(OSSL_CMP_CTX *ctx, const ASN1_OCTET_STRING *nonce); /* from cmp_status.c */ -OSSL_CMP_PKISI * -ossl_cmp_statusinfo_new(int status, int fail_info, const char *text); -int ossl_cmp_pkisi_get_pkistatus(const OSSL_CMP_PKISI *statusInfo); +int ossl_cmp_pkisi_get_status(const OSSL_CMP_PKISI *si); const char *ossl_cmp_PKIStatus_to_string(int status); -OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusstring(const OSSL_CMP_PKISI *si); +OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusString(const OSSL_CMP_PKISI *si); int ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si); -int ossl_cmp_pkisi_pkifailureinfo_check(const OSSL_CMP_PKISI *si, int bit_index); +int ossl_cmp_pkisi_check_pkifailureinfo(const OSSL_CMP_PKISI *si, int index); /* from cmp_hdr.c */ int ossl_cmp_hdr_set_pvno(OSSL_CMP_PKIHEADER *hdr, int pvno); @@ -817,15 +803,14 @@ int ossl_cmp_hdr_set1_recipient(OSSL_CMP_PKIHEADER *hdr, const X509_NAME *nm); int ossl_cmp_hdr_update_messageTime(OSSL_CMP_PKIHEADER *hdr); int ossl_cmp_hdr_set1_senderKID(OSSL_CMP_PKIHEADER *hdr, const ASN1_OCTET_STRING *senderKID); -int ossl_cmp_pkifreetext_push_str(OSSL_CMP_PKIFREETEXT *ft, const char *text); int ossl_cmp_hdr_push0_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text); int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text); int ossl_cmp_hdr_generalInfo_push0_item(OSSL_CMP_PKIHEADER *hdr, OSSL_CMP_ITAV *itav); int ossl_cmp_hdr_generalInfo_push1_items(OSSL_CMP_PKIHEADER *hdr, - STACK_OF(OSSL_CMP_ITAV) *itavs); + const STACK_OF(OSSL_CMP_ITAV) *itavs); int ossl_cmp_hdr_set_implicitConfirm(OSSL_CMP_PKIHEADER *hdr); -int ossl_cmp_hdr_check_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr); +int ossl_cmp_hdr_has_implicitConfirm(const OSSL_CMP_PKIHEADER *hdr); # define OSSL_CMP_TRANSACTIONID_LENGTH 16 # define OSSL_CMP_SENDERNONCE_LENGTH 16 int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr); @@ -860,6 +845,10 @@ int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr); # define OSSL_CMP_PKIBODY_POLLREQ 25 # define OSSL_CMP_PKIBODY_POLLREP 26 # define OSSL_CMP_PKIBODY_TYPE_MAX OSSL_CMP_PKIBODY_POLLREP +/* certReqId for the first - and so far only - certificate request */ +# define OSSL_CMP_CERTREQID 0 +/* sequence id for the first - and so far only - revocation request */ +# define OSSL_CMP_REVREQSID 0 const char *ossl_cmp_bodytype_to_string(int type); int ossl_cmp_msg_set_bodytype(OSSL_CMP_MSG *msg, int type); int ossl_cmp_msg_get_bodytype(const OSSL_CMP_MSG *msg); @@ -875,24 +864,26 @@ OSSL_CMP_MSG *ossl_cmp_rr_new(OSSL_CMP_CTX *ctx); OSSL_CMP_MSG *ossl_cmp_rp_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si, OSSL_CRMF_CERTID *certId, int unprot_err); OSSL_CMP_MSG *ossl_cmp_pkiconf_new(OSSL_CMP_CTX *ctx); +OSSL_CMP_MSG *ossl_cmp_pollRep_new(OSSL_CMP_CTX *ctx, int crid, + int64_t poll_after); int ossl_cmp_msg_gen_push0_ITAV(OSSL_CMP_MSG *msg, OSSL_CMP_ITAV *itav); int ossl_cmp_msg_gen_push1_ITAVs(OSSL_CMP_MSG *msg, - STACK_OF(OSSL_CMP_ITAV) *itavs); + const STACK_OF(OSSL_CMP_ITAV) *itavs); OSSL_CMP_MSG *ossl_cmp_genm_new(OSSL_CMP_CTX *ctx); -OSSL_CMP_MSG *ossl_cmp_genp_new(OSSL_CMP_CTX *ctx); +OSSL_CMP_MSG *ossl_cmp_genp_new(OSSL_CMP_CTX *ctx, + const STACK_OF(OSSL_CMP_ITAV) *itavs); OSSL_CMP_MSG *ossl_cmp_error_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si, int errorCode, - OSSL_CMP_PKIFREETEXT *errorDetails, - int unprotected); -int ossl_cmp_certstatus_set_certHash(OSSL_CMP_CERTSTATUS *certStatus, - const X509 *cert); + const char *details, int unprotected); +int ossl_cmp_certstatus_set0_certHash(OSSL_CMP_CERTSTATUS *certStatus, + ASN1_OCTET_STRING *hash); OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int fail_info, const char *text); OSSL_CMP_MSG *ossl_cmp_pollReq_new(OSSL_CMP_CTX *ctx, int crid); OSSL_CMP_MSG *ossl_cmp_pollRep_new(OSSL_CMP_CTX *ctx, int crid, int64_t poll_after); OSSL_CMP_PKISI * -ossl_cmp_revrepcontent_get_pkistatusinfo(OSSL_CMP_REVREPCONTENT *rrep, int rsid); +ossl_cmp_revrepcontent_get_pkisi(OSSL_CMP_REVREPCONTENT *rrep, int rsid); OSSL_CRMF_CERTID *ossl_cmp_revrepcontent_get_CertId(OSSL_CMP_REVREPCONTENT *rrep, int rsid); OSSL_CMP_POLLREP * @@ -904,11 +895,6 @@ ossl_cmp_certrepmessage_get0_certresponse(const OSSL_CMP_CERTREPMESSAGE *crepmsg X509 *ossl_cmp_certresponse_get1_certificate(EVP_PKEY *privkey, const OSSL_CMP_CERTRESPONSE *crep); OSSL_CMP_MSG *ossl_cmp_msg_load(const char *file); -/* BIO definitions */ -# define OSSL_d2i_CMP_MSG_bio(bp, p) \ - ASN1_d2i_bio_of(OSSL_CMP_MSG, OSSL_CMP_MSG_new, d2i_OSSL_CMP_MSG, bp, p) -# define OSSL_i2d_CMP_MSG_bio(bp, o) \ - ASN1_i2d_bio_of(OSSL_CMP_MSG, i2d_OSSL_CMP_MSG, bp, o) /* from cmp_protect.c */ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_MSG *msg, @@ -925,4 +911,4 @@ int ossl_cmp_msg_check_received(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg, ossl_cmp_allow_unprotected_cb_t cb, int cb_arg); int ossl_cmp_verify_popo(const OSSL_CMP_MSG *msg, int accept_RAVerified); -#endif /* !defined OSSL_CRYPTO_CMP_LOCAL_H */ +#endif /* !defined(OSSL_CRYPTO_CMP_LOCAL_H) */ diff --git a/crypto/cmp/cmp_msg.c b/crypto/cmp/cmp_msg.c index c794dc98bb..c608568130 100644 --- a/crypto/cmp/cmp_msg.c +++ b/crypto/cmp/cmp_msg.c @@ -205,18 +205,20 @@ static X509_NAME *determine_subj(OSSL_CMP_CTX *ctx, X509 *refcert, * Create CRMF certificate request message for IR/CR/KUR * returns a pointer to the OSSL_CRMF_MSG on success, NULL on error */ -static OSSL_CRMF_MSG *crm_new(OSSL_CMP_CTX *ctx, int bodytype, - int rid, EVP_PKEY *rkey) +static OSSL_CRMF_MSG *crm_new(OSSL_CMP_CTX *ctx, int bodytype, int rid) { OSSL_CRMF_MSG *crm = NULL; X509 *refcert = ctx->oldCert != NULL ? ctx->oldCert : ctx->clCert; /* refcert defaults to current client cert */ + EVP_PKEY *rkey = OSSL_CMP_CTX_get0_newPkey(ctx, 0); STACK_OF(GENERAL_NAME) *default_sans = NULL; X509_NAME *subject = determine_subj(ctx, refcert, bodytype); int crit = ctx->setSubjectAltNameCritical || subject == NULL; /* RFC5280: subjectAltName MUST be critical if subject is null */ X509_EXTENSIONS *exts = NULL; + if (rkey == NULL) + rkey = ctx->pkey; /* default is independent of ctx->oldClCert */ if (rkey == NULL || (bodytype == OSSL_CMP_PKIBODY_KUR && refcert == NULL)) { CMPerr(0, CMP_R_INVALID_ARGS); @@ -300,19 +302,12 @@ static OSSL_CRMF_MSG *crm_new(OSSL_CMP_CTX *ctx, int bodytype, OSSL_CMP_MSG *ossl_cmp_certReq_new(OSSL_CMP_CTX *ctx, int type, int err_code) { - EVP_PKEY *rkey; - EVP_PKEY *privkey; OSSL_CMP_MSG *msg; OSSL_CRMF_MSG *crm = NULL; if (!ossl_assert(ctx != NULL)) return NULL; - rkey = OSSL_CMP_CTX_get0_newPkey(ctx, 0); - if (rkey == NULL) - return NULL; - privkey = OSSL_CMP_CTX_get0_newPkey(ctx, 1); - if (type != OSSL_CMP_PKIBODY_IR && type != OSSL_CMP_PKIBODY_CR && type != OSSL_CMP_PKIBODY_KUR && type != OSSL_CMP_PKIBODY_P10CR) { CMPerr(0, CMP_R_INVALID_ARGS); @@ -329,15 +324,19 @@ OSSL_CMP_MSG *ossl_cmp_certReq_new(OSSL_CMP_CTX *ctx, int type, int err_code) /* body */ /* For P10CR the content has already been set in OSSL_CMP_MSG_create */ if (type != OSSL_CMP_PKIBODY_P10CR) { + EVP_PKEY *privkey = OSSL_CMP_CTX_get0_newPkey(ctx, 1); + + if (privkey == NULL) + privkey = ctx->pkey; /* default is independent of ctx->oldCert */ if (ctx->popoMethod == OSSL_CRMF_POPO_SIGNATURE && privkey == NULL) { CMPerr(0, CMP_R_MISSING_PRIVATE_KEY); goto err; } - if ((crm = crm_new(ctx, type, OSSL_CMP_CERTREQID, rkey)) == NULL - || !OSSL_CRMF_MSG_create_popo(crm, privkey, ctx->digest, - ctx->popoMethod) - /* value.ir is same for cr and kur */ - || !sk_OSSL_CRMF_MSG_push(msg->body->value.ir, crm)) + if ((crm = crm_new(ctx, type, OSSL_CMP_CERTREQID)) == NULL + || !OSSL_CRMF_MSG_create_popo(crm, privkey, ctx->digest, + ctx->popoMethod) + /* value.ir is same for cr and kur */ + || !sk_OSSL_CRMF_MSG_push(msg->body->value.ir, crm)) goto err; crm = NULL; /* TODO: here optional 2nd certreqmsg could be pushed to the stack */ @@ -385,7 +384,7 @@ OSSL_CMP_MSG *ossl_cmp_certRep_new(OSSL_CMP_CTX *ctx, int bodytype, || !ASN1_INTEGER_set(resp->certReqId, certReqId)) goto err; - status = ossl_cmp_pkisi_get_pkistatus(resp->status); + status = ossl_cmp_pkisi_get_status(resp->status); if (status != OSSL_CMP_PKISTATUS_rejection && status != OSSL_CMP_PKISTATUS_waiting && cert != NULL) { if (encrypted) { @@ -416,7 +415,7 @@ OSSL_CMP_MSG *ossl_cmp_certRep_new(OSSL_CMP_CTX *ctx, int bodytype, goto err; if (!unprotectedErrors - || ossl_cmp_pkisi_get_pkistatus(si) != OSSL_CMP_PKISTATUS_rejection) + || ossl_cmp_pkisi_get_status(si) != OSSL_CMP_PKISTATUS_rejection) if (!ossl_cmp_msg_protect(ctx, msg)) goto err; @@ -511,7 +510,7 @@ OSSL_CMP_MSG *ossl_cmp_rp_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si, } if (!unprot_err - || ossl_cmp_pkisi_get_pkistatus(si) != OSSL_CMP_PKISTATUS_rejection) + || ossl_cmp_pkisi_get_status(si) != OSSL_CMP_PKISTATUS_rejection) if (!ossl_cmp_msg_protect(ctx, msg)) goto err; @@ -560,7 +559,7 @@ int ossl_cmp_msg_gen_push0_ITAV(OSSL_CMP_MSG *msg, OSSL_CMP_ITAV *itav) } int ossl_cmp_msg_gen_push1_ITAVs(OSSL_CMP_MSG *msg, - STACK_OF(OSSL_CMP_ITAV) *itavs) + const STACK_OF(OSSL_CMP_ITAV) *itavs) { int i; OSSL_CMP_ITAV *itav = NULL; @@ -583,7 +582,9 @@ int ossl_cmp_msg_gen_push1_ITAVs(OSSL_CMP_MSG *msg, * Creates a new General Message/Response with an empty itav stack * returns a pointer to the PKIMessage on success, NULL on error */ -static OSSL_CMP_MSG *gen_new(OSSL_CMP_CTX *ctx, int body_type, int err_code) +static OSSL_CMP_MSG *gen_new(OSSL_CMP_CTX *ctx, + const STACK_OF(OSSL_CMP_ITAV) *itavs, + int body_type, int err_code) { OSSL_CMP_MSG *msg = NULL; @@ -594,7 +595,7 @@ static OSSL_CMP_MSG *gen_new(OSSL_CMP_CTX *ctx, int body_type, int err_code) return NULL; if (ctx->genm_ITAVs != NULL - && !ossl_cmp_msg_gen_push1_ITAVs(msg, ctx->genm_ITAVs)) + && !ossl_cmp_msg_gen_push1_ITAVs(msg, itavs)) goto err; if (!ossl_cmp_msg_protect(ctx, msg)) @@ -610,20 +611,23 @@ static OSSL_CMP_MSG *gen_new(OSSL_CMP_CTX *ctx, int body_type, int err_code) OSSL_CMP_MSG *ossl_cmp_genm_new(OSSL_CMP_CTX *ctx) { - return gen_new(ctx, OSSL_CMP_PKIBODY_GENM, CMP_R_ERROR_CREATING_GENM); + return gen_new(ctx, ctx->genm_ITAVs, + OSSL_CMP_PKIBODY_GENM, CMP_R_ERROR_CREATING_GENM); } -OSSL_CMP_MSG *ossl_cmp_genp_new(OSSL_CMP_CTX *ctx) +OSSL_CMP_MSG *ossl_cmp_genp_new(OSSL_CMP_CTX *ctx, + const STACK_OF(OSSL_CMP_ITAV) *itavs) { - return gen_new(ctx, OSSL_CMP_PKIBODY_GENP, CMP_R_ERROR_CREATING_GENP); + return gen_new(ctx, itavs, + OSSL_CMP_PKIBODY_GENP, CMP_R_ERROR_CREATING_GENP); } OSSL_CMP_MSG *ossl_cmp_error_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si, int errorCode, - OSSL_CMP_PKIFREETEXT *errorDetails, - int unprotected) + const char *details, int unprotected) { OSSL_CMP_MSG *msg = NULL; + OSSL_CMP_PKIFREETEXT *ft; if (!ossl_assert(ctx != NULL && si != NULL)) return NULL; @@ -641,11 +645,13 @@ OSSL_CMP_MSG *ossl_cmp_error_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si, if (!ASN1_INTEGER_set(msg->body->value.error->errorCode, errorCode)) goto err; } - if (errorDetails != NULL) - if ((msg->body->value.error->errorDetails = - sk_ASN1_UTF8STRING_deep_copy(errorDetails, ASN1_STRING_dup, - ASN1_STRING_free)) == NULL) + if (details != NULL) { + if ((ft = sk_ASN1_UTF8STRING_new_null()) == NULL) + goto err; + msg->body->value.error->errorDetails = ft; + if (!ossl_cmp_sk_ASN1_UTF8STRING_push_str(ft, details)) goto err; + } if (!unprotected && !ossl_cmp_msg_protect(ctx, msg)) goto err; @@ -658,44 +664,18 @@ OSSL_CMP_MSG *ossl_cmp_error_new(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si, } /* - * OSSL_CMP_CERTSTATUS_set_certHash() calculates a hash of the certificate, - * using the same hash algorithm as is used to create and verify the - * certificate signature, and places the hash into the certHash field of a - * OSSL_CMP_CERTSTATUS structure. This is used in the certConf message, - * for example, to confirm that the certificate was received successfully. + * Set the certHash field of a OSSL_CMP_CERTSTATUS structure. + * This is used in the certConf message, for example, + * to confirm that the certificate was received successfully. */ -int ossl_cmp_certstatus_set_certHash(OSSL_CMP_CERTSTATUS *certStatus, - const X509 *cert) +int ossl_cmp_certstatus_set0_certHash(OSSL_CMP_CERTSTATUS *certStatus, + ASN1_OCTET_STRING *hash) { - unsigned int len; - unsigned char hash[EVP_MAX_MD_SIZE]; - int md_NID; - const EVP_MD *md = NULL; - - if (!ossl_assert(certStatus != NULL && cert != NULL)) - return 0; - - /*- - * select hash algorithm, as stated in Appendix F. Compilable ASN.1 defs: - * the hash of the certificate, using the same hash algorithm - * as is used to create and verify the certificate signature - */ - if (OBJ_find_sigid_algs(X509_get_signature_nid(cert), &md_NID, NULL) - && (md = EVP_get_digestbynid(md_NID)) != NULL) { - if (!X509_digest(cert, md, hash, &len)) - goto err; - if (!ossl_cmp_asn1_octet_string_set1_bytes(&certStatus->certHash, hash, - len)) - goto err; - } else { - CMPerr(0, CMP_R_UNSUPPORTED_ALGORITHM); + if (!ossl_assert(certStatus != NULL)) return 0; - } - + ASN1_OCTET_STRING_free(certStatus->certHash); + certStatus->certHash = hash; return 1; - err: - CMPerr(0, CMP_R_ERROR_SETTING_CERTHASH); - return 0; } /* @@ -707,6 +687,7 @@ OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int fail_info, { OSSL_CMP_MSG *msg = NULL; OSSL_CMP_CERTSTATUS *certStatus = NULL; + ASN1_OCTET_STRING *certHash = NULL; OSSL_CMP_PKISI *sinfo; if (!ossl_assert(ctx != NULL && ctx->newCert != NULL)) @@ -732,8 +713,12 @@ OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int fail_info, * the hash of the certificate, using the same hash algorithm * as is used to create and verify the certificate signature */ - if (!ossl_cmp_certstatus_set_certHash(certStatus, ctx->newCert)) + if ((certHash = OSSL_CMP_X509_digest(ctx->newCert)) == NULL) + goto err; + + if (!ossl_cmp_certstatus_set0_certHash(certStatus, certHash)) goto err; + certHash = NULL; /* * For any particular CertStatus, omission of the statusInfo field * indicates ACCEPTANCE of the specified certificate. Alternatively, @@ -742,8 +727,8 @@ OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int fail_info, * the CA/RA. */ sinfo = fail_info != 0 ? - ossl_cmp_statusinfo_new(OSSL_CMP_PKISTATUS_rejection, fail_info, text) : - ossl_cmp_statusinfo_new(OSSL_CMP_PKISTATUS_accepted, 0, text); + OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_rejection, fail_info, text) : + OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_accepted, 0, text); if (sinfo == NULL) goto err; certStatus->statusInfo = sinfo; @@ -756,6 +741,7 @@ OSSL_CMP_MSG *ossl_cmp_certConf_new(OSSL_CMP_CTX *ctx, int fail_info, err: CMPerr(0, CMP_R_ERROR_CREATING_CERTCONF); OSSL_CMP_MSG_free(msg); + ASN1_OCTET_STRING_free(certHash); return NULL; } @@ -827,7 +813,7 @@ OSSL_CMP_MSG *ossl_cmp_pollRep_new(OSSL_CMP_CTX *ctx, int crid, * returns NULL on error */ OSSL_CMP_PKISI * -ossl_cmp_revrepcontent_get_pkistatusinfo(OSSL_CMP_REVREPCONTENT *rrep, int rsid) +ossl_cmp_revrepcontent_get_pkisi(OSSL_CMP_REVREPCONTENT *rrep, int rsid) { OSSL_CMP_PKISI *status; @@ -994,3 +980,14 @@ OSSL_CMP_MSG *ossl_cmp_msg_load(const char *file) BIO_free(bio); return msg; } + +OSSL_CMP_MSG *OSSL_d2i_CMP_MSG_bio(BIO *bio, OSSL_CMP_MSG **msg) +{ + return ASN1_d2i_bio_of(OSSL_CMP_MSG, OSSL_CMP_MSG_new, + d2i_OSSL_CMP_MSG, bio, msg); +} + +int OSSL_i2d_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg) +{ + return ASN1_i2d_bio_of(OSSL_CMP_MSG, i2d_OSSL_CMP_MSG, bio, msg); +} diff --git a/crypto/cmp/cmp_server.c b/crypto/cmp/cmp_server.c new file mode 100644 index 0000000000..a91f67b264 --- /dev/null +++ b/crypto/cmp/cmp_server.c @@ -0,0 +1,615 @@ +/* + * Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright Nokia 2007-2019 + * Copyright Siemens AG 2015-2019 + * + * 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 + */ + +/* general CMP server functions */ + +#include + +#include "cmp_local.h" + +/* explicit #includes not strictly needed since implied by the above: */ +#include +#include + +/* the context for the generic CMP server */ +struct ossl_cmp_srv_ctx_st +{ + OSSL_CMP_CTX *ctx; /* Client CMP context, partly reused for srv */ + void *custom_ctx; /* pointer to specific server context */ + + OSSL_CMP_SRV_cert_request_cb_t process_cert_request; + OSSL_CMP_SRV_rr_cb_t process_rr; + OSSL_CMP_SRV_genm_cb_t process_genm; + OSSL_CMP_SRV_error_cb_t process_error; + OSSL_CMP_SRV_certConf_cb_t process_certConf; + OSSL_CMP_SRV_pollReq_cb_t process_pollReq; + + int sendUnprotectedErrors; /* Send error and rejection msgs unprotected */ + int acceptUnprotected; /* Accept requests with no/invalid prot. */ + int acceptRAVerified; /* Accept ir/cr/kur with POPO RAVerified */ + int grantImplicitConfirm; /* Grant implicit confirmation if requested */ + +}; /* OSSL_CMP_SRV_CTX */ + +void OSSL_CMP_SRV_CTX_free(OSSL_CMP_SRV_CTX *srv_ctx) +{ + if (srv_ctx == NULL) + return; + + OSSL_CMP_CTX_free(srv_ctx->ctx); + OPENSSL_free(srv_ctx); +} + +OSSL_CMP_SRV_CTX *OSSL_CMP_SRV_CTX_new(void) +{ + OSSL_CMP_SRV_CTX *ctx = OPENSSL_zalloc(sizeof(OSSL_CMP_SRV_CTX)); + + if (ctx == NULL) + goto err; + + if ((ctx->ctx = OSSL_CMP_CTX_new()) == NULL) + goto err; + + /* all other elements are initialized to 0 or NULL, respectively */ + return ctx; + err: + OSSL_CMP_SRV_CTX_free(ctx); + return NULL; +} + +int OSSL_CMP_SRV_CTX_init(OSSL_CMP_SRV_CTX *srv_ctx, void *custom_ctx, + OSSL_CMP_SRV_cert_request_cb_t process_cert_request, + OSSL_CMP_SRV_rr_cb_t process_rr, + OSSL_CMP_SRV_genm_cb_t process_genm, + OSSL_CMP_SRV_error_cb_t process_error, + OSSL_CMP_SRV_certConf_cb_t process_certConf, + OSSL_CMP_SRV_pollReq_cb_t process_pollReq) +{ + if (srv_ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + srv_ctx->custom_ctx = custom_ctx; + srv_ctx->process_cert_request = process_cert_request; + srv_ctx->process_rr = process_rr; + srv_ctx->process_genm = process_genm; + srv_ctx->process_error = process_error; + srv_ctx->process_certConf = process_certConf; + srv_ctx->process_pollReq = process_pollReq; + return 1; +} + +OSSL_CMP_CTX *OSSL_CMP_SRV_CTX_get0_cmp_ctx(const OSSL_CMP_SRV_CTX *srv_ctx) +{ + if (srv_ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return NULL; + } + return srv_ctx->ctx; +} + +void *OSSL_CMP_SRV_CTX_get0_custom_ctx(const OSSL_CMP_SRV_CTX *srv_ctx) +{ + if (srv_ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return NULL; + } + return srv_ctx->custom_ctx; +} + +int OSSL_CMP_SRV_CTX_set_send_unprotected_errors(OSSL_CMP_SRV_CTX *srv_ctx, + int val) +{ + if (srv_ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + srv_ctx->sendUnprotectedErrors = val != 0; + return 1; +} + +int OSSL_CMP_SRV_CTX_set_accept_unprotected(OSSL_CMP_SRV_CTX *srv_ctx, int val) +{ + if (srv_ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + srv_ctx->acceptUnprotected = val != 0; + return 1; +} + +int OSSL_CMP_SRV_CTX_set_accept_raverified(OSSL_CMP_SRV_CTX *srv_ctx, int val) +{ + if (srv_ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + srv_ctx->acceptRAVerified = val != 0; + return 1; +} + +int OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(OSSL_CMP_SRV_CTX *srv_ctx, + int val) +{ + if (srv_ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + srv_ctx->grantImplicitConfirm = val != 0; + return 1; +} + +/* + * Processes an ir/cr/p10cr/kur and returns a certification response. + * Only handles the first certification request contained in req + * returns an ip/cp/kup on success and NULL on error + */ +static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req) +{ + OSSL_CMP_MSG *msg = NULL; + OSSL_CMP_PKISI *si = NULL; + X509 *certOut = NULL; + STACK_OF(X509) *chainOut = NULL, *caPubs = NULL; + const OSSL_CRMF_MSG *crm = NULL; + const X509_REQ *p10cr = NULL; + int bodytype; + int certReqId; + + if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL)) + return NULL; + + switch (ossl_cmp_msg_get_bodytype(req)) { + case OSSL_CMP_PKIBODY_P10CR: + case OSSL_CMP_PKIBODY_CR: + bodytype = OSSL_CMP_PKIBODY_CP; + break; + case OSSL_CMP_PKIBODY_IR: + bodytype = OSSL_CMP_PKIBODY_IP; + break; + case OSSL_CMP_PKIBODY_KUR: + bodytype = OSSL_CMP_PKIBODY_KUP; + break; + default: + CMPerr(0, CMP_R_UNEXPECTED_PKIBODY); + return NULL; + } + + if (ossl_cmp_msg_get_bodytype(req) == OSSL_CMP_PKIBODY_P10CR) { + certReqId = OSSL_CMP_CERTREQID; + p10cr = req->body->value.p10cr; + } else { + OSSL_CRMF_MSGS *reqs = req->body->value.ir; /* same for cr and kur */ + + if (sk_OSSL_CRMF_MSG_num(reqs) != 1) { /* TODO: handle case > 1 */ + CMPerr(0, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED); + return NULL; + } + + if ((crm = sk_OSSL_CRMF_MSG_value(reqs, OSSL_CMP_CERTREQID)) == NULL) { + CMPerr(0, CMP_R_CERTREQMSG_NOT_FOUND); + return NULL; + } + certReqId = OSSL_CRMF_MSG_get_certReqId(crm); + } + + if (!ossl_cmp_verify_popo(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, + ERR_reason_error_string(ERR_peek_error())); + if (si == NULL) + return NULL; + } else { + OSSL_CMP_PKIHEADER *hdr = OSSL_CMP_MSG_get0_header(req); + + si = srv_ctx->process_cert_request(srv_ctx, req, certReqId, crm, p10cr, + &certOut, &chainOut, &caPubs); + if (si == NULL) + goto err; + /* set OSSL_CMP_OPT_IMPLICITCONFIRM if and only if transaction ends */ + if (!OSSL_CMP_CTX_set_option(srv_ctx->ctx, OSSL_CMP_OPT_IMPLICITCONFIRM, + ossl_cmp_hdr_has_implicitConfirm(hdr) + && srv_ctx->grantImplicitConfirm + /* do not set if polling starts: */ + && certOut != NULL)) + goto err; + } + + msg = ossl_cmp_certRep_new(srv_ctx->ctx, bodytype, certReqId, si, + certOut, chainOut, caPubs, 0 /* encrypted */, + srv_ctx->sendUnprotectedErrors); + /* + * TODO when implemented in ossl_cmp_certrep_new(): + * in case OSSL_CRMF_POPO_KEYENC, set encrypted + */ + if (msg == NULL) + CMPerr(0, CMP_R_ERROR_CREATING_CERTREP); + + err: + OSSL_CMP_PKISI_free(si); + X509_free(certOut); + sk_X509_pop_free(chainOut, X509_free); + sk_X509_pop_free(caPubs, X509_free); + return msg; +} + +static OSSL_CMP_MSG *process_rr(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req) +{ + OSSL_CMP_MSG *msg = NULL; + OSSL_CMP_REVDETAILS *details; + OSSL_CRMF_CERTID *certId; + OSSL_CRMF_CERTTEMPLATE *tmpl; + X509_NAME *issuer; + ASN1_INTEGER *serial; + OSSL_CMP_PKISI *si; + + if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL)) + return NULL; + + if (sk_OSSL_CMP_REVDETAILS_num(req->body->value.rr) != 1) { + /* TODO: handle multiple elements if multiple requests have been sent */ + CMPerr(0, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED); + return NULL; + } + + if ((details = sk_OSSL_CMP_REVDETAILS_value(req->body->value.rr, + OSSL_CMP_REVREQSID)) == NULL) { + CMPerr(0, CMP_R_ERROR_PROCESSING_MSG); + return NULL; + } + + tmpl = details->certDetails; + issuer = OSSL_CRMF_CERTTEMPLATE_get0_issuer(tmpl); + serial = OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(tmpl); + /* here issuer and serial may safely be NULL */ + if ((certId = OSSL_CRMF_CERTID_gen(issuer, serial)) == NULL) + return NULL; + if ((si = srv_ctx->process_rr(srv_ctx, req, issuer, serial)) == NULL) + goto err; + + if ((msg = ossl_cmp_rp_new(srv_ctx->ctx, si, certId, + srv_ctx->sendUnprotectedErrors)) == NULL) + CMPerr(0, CMP_R_ERROR_CREATING_RR); + + err: + OSSL_CRMF_CERTID_free(certId); + OSSL_CMP_PKISI_free(si); + return msg; +} + +/* + * Processes genm and creates a genp message mirroring the contents of the + * incoming message + */ +static OSSL_CMP_MSG *process_genm(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req) +{ + OSSL_CMP_GENMSGCONTENT *itavs; + OSSL_CMP_MSG *msg; + + if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL)) + return NULL; + + if (!srv_ctx->process_genm(srv_ctx, req, req->body->value.genm, &itavs)) + return NULL; + + msg = ossl_cmp_genp_new(srv_ctx->ctx, itavs); + sk_OSSL_CMP_ITAV_pop_free(itavs, OSSL_CMP_ITAV_free); + return msg; +} + +static OSSL_CMP_MSG *process_error(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req) +{ + OSSL_CMP_ERRORMSGCONTENT *errorContent; + OSSL_CMP_MSG *msg; + + if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL)) + return NULL; + errorContent = req->body->value.error; + srv_ctx->process_error(srv_ctx, req, errorContent->pKIStatusInfo, + errorContent->errorCode, errorContent->errorDetails); + + if ((msg = ossl_cmp_pkiconf_new(srv_ctx->ctx)) == NULL) + CMPerr(0, CMP_R_ERROR_CREATING_PKICONF); + return msg; +} + +static OSSL_CMP_MSG *process_certConf(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req) +{ + OSSL_CMP_CTX *ctx; + OSSL_CMP_CERTCONFIRMCONTENT *ccc; + int num; + OSSL_CMP_MSG *msg = NULL; + OSSL_CMP_CERTSTATUS *status = NULL; + + if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL)) + return NULL; + + ctx = srv_ctx->ctx; + ccc = req->body->value.certConf; + num = sk_OSSL_CMP_CERTSTATUS_num(ccc); + + if (OSSL_CMP_CTX_get_option(ctx, OSSL_CMP_OPT_IMPLICITCONFIRM) == 1) { + CMPerr(0, CMP_R_ERROR_UNEXPECTED_CERTCONF); + return NULL; + } + + if (num == 0) { + ossl_cmp_err(ctx, "certificate rejected by client"); + } else { + if (num > 1) + ossl_cmp_warn(ctx, "All CertStatus but the first will be ignored"); + status = sk_OSSL_CMP_CERTSTATUS_value(ccc, OSSL_CMP_CERTREQID); + } + + if (status != NULL) { + int certReqId = ossl_cmp_asn1_get_int(status->certReqId); + ASN1_OCTET_STRING *certHash = status->certHash; + OSSL_CMP_PKISI *si = status->statusInfo; + + if (!srv_ctx->process_certConf(srv_ctx, req, certReqId, certHash, si)) + return NULL; /* reason code may be: CMP_R_CERTHASH_UNMATCHED */ + + if (si != NULL && ossl_cmp_pkisi_get_status(si) + != OSSL_CMP_PKISTATUS_accepted) { + int pki_status = ossl_cmp_pkisi_get_status(si); + const char *str = ossl_cmp_PKIStatus_to_string(pki_status); + + ossl_cmp_log2(INFO, ctx, "certificate rejected by client %s %s", + str == NULL ? "without" : "with", + str == NULL ? "PKIStatus" : str); + } + } + + if ((msg = ossl_cmp_pkiconf_new(ctx)) == NULL) + CMPerr(0, CMP_R_ERROR_CREATING_PKICONF); + return msg; +} + +static OSSL_CMP_MSG *process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req) +{ + OSSL_CMP_POLLREQCONTENT *prc; + OSSL_CMP_POLLREQ *pr; + int certReqId; + OSSL_CMP_MSG *certReq; + int64_t check_after = 0; + OSSL_CMP_MSG *msg = NULL; + + if (!ossl_assert(srv_ctx != NULL && srv_ctx->ctx != NULL && req != NULL)) + return NULL; + + prc = req->body->value.pollReq; + if (sk_OSSL_CMP_POLLREQ_num(prc) != 1) { /* TODO: handle case > 1 */ + CMPerr(0, CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED); + return NULL; + } + + pr = sk_OSSL_CMP_POLLREQ_value(prc, 0); + certReqId = ossl_cmp_asn1_get_int(pr->certReqId); + if (!srv_ctx->process_pollReq(srv_ctx, req, certReqId, + &certReq, &check_after)) + return NULL; + + if (certReq != NULL) { + msg = process_cert_request(srv_ctx, certReq); + OSSL_CMP_MSG_free(certReq); + } else { + if ((msg = ossl_cmp_pollRep_new(srv_ctx->ctx, certReqId, + check_after)) == NULL) + CMPerr(0, CMP_R_ERROR_CREATING_POLLREP); + } + return msg; +} + +/* + * Determines whether missing protection is allowed + */ +static int unprotected_exception(const OSSL_CMP_CTX *ctx, + const OSSL_CMP_MSG *req, + int invalid_protection, + int accept_unprotected_requests) +{ + if (accept_unprotected_requests) { + ossl_cmp_log1(WARN, ctx, "ignoring %s protection of request message", + invalid_protection ? "invalid" : "missing"); + return 1; + } + if (ossl_cmp_msg_get_bodytype(req) == OSSL_CMP_PKIBODY_ERROR + && OSSL_CMP_CTX_get_option(ctx, OSSL_CMP_OPT_UNPROTECTED_ERRORS) == 1) { + ossl_cmp_warn(ctx, "ignoring missing protection of error message"); + return 1; + } + return 0; +} + +/* + * returns created message and NULL on internal error + */ +OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req) +{ + OSSL_CMP_CTX *ctx; + OSSL_CMP_PKIHEADER *hdr; + int req_type, rsp_type; + OSSL_CMP_MSG *rsp = NULL; + + if (srv_ctx == NULL || srv_ctx->ctx == NULL + || req == NULL || req->body == NULL + || (hdr = OSSL_CMP_MSG_get0_header(req)) == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + ctx = srv_ctx->ctx; + + if (hdr->sender->type != GEN_DIRNAME) { + CMPerr(0, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED); + goto err; + } + if (!OSSL_CMP_CTX_set1_recipient(ctx, hdr->sender->d.directoryName)) + goto err; + + req_type = ossl_cmp_msg_get_bodytype(req); + switch (req_type) { + case OSSL_CMP_PKIBODY_IR: + case OSSL_CMP_PKIBODY_CR: + case OSSL_CMP_PKIBODY_P10CR: + case OSSL_CMP_PKIBODY_KUR: + case OSSL_CMP_PKIBODY_RR: + case OSSL_CMP_PKIBODY_GENM: + case OSSL_CMP_PKIBODY_ERROR: + if (ctx->transactionID != NULL) { + char *tid; + + tid = OPENSSL_buf2hexstr(ctx->transactionID->data, + ctx->transactionID->length); + ossl_cmp_log1(WARN, ctx, + "Assuming that last transaction with ID=%s got aborted", + tid); + OPENSSL_free(tid); + } + /* start of a new transaction, set transactionID and senderNonce */ + if (!OSSL_CMP_CTX_set1_transactionID(ctx, hdr->transactionID) + || !ossl_cmp_ctx_set1_recipNonce(ctx, hdr->senderNonce)) + goto err; + break; + default: + /* transactionID should be already initialized */ + if (ctx->transactionID == NULL) { + CMPerr(0, CMP_R_UNEXPECTED_PKIBODY); + /* ignore any (extra) error in next two function calls: */ + (void)OSSL_CMP_CTX_set1_transactionID(ctx, hdr->transactionID); + (void)ossl_cmp_ctx_set1_recipNonce(ctx, hdr->senderNonce); + goto err; + } + } + + if (ossl_cmp_msg_check_received(ctx, req, unprotected_exception, + srv_ctx->acceptUnprotected) < 0) + goto err; + + switch (req_type) { + case OSSL_CMP_PKIBODY_IR: + case OSSL_CMP_PKIBODY_CR: + case OSSL_CMP_PKIBODY_P10CR: + case OSSL_CMP_PKIBODY_KUR: + if (srv_ctx->process_cert_request == NULL) + CMPerr(0, CMP_R_UNEXPECTED_PKIBODY); + else + rsp = process_cert_request(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_RR: + if (srv_ctx->process_rr == NULL) + CMPerr(0, CMP_R_UNEXPECTED_PKIBODY); + else + rsp = process_rr(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_GENM: + if (srv_ctx->process_genm == NULL) + CMPerr(0, CMP_R_UNEXPECTED_PKIBODY); + else + rsp = process_genm(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_ERROR: + if (srv_ctx->process_error == NULL) + CMPerr(0, CMP_R_UNEXPECTED_PKIBODY); + else + rsp = process_error(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_CERTCONF: + if (srv_ctx->process_certConf == NULL) + CMPerr(0, CMP_R_UNEXPECTED_PKIBODY); + else + rsp = process_certConf(srv_ctx, req); + break; + case OSSL_CMP_PKIBODY_POLLREQ: + if (srv_ctx->process_pollReq == NULL) + CMPerr(0, CMP_R_UNEXPECTED_PKIBODY); + else + rsp = process_pollReq(srv_ctx, req); + break; + default: + /* TODO possibly support further request message types */ + CMPerr(0, CMP_R_UNEXPECTED_PKIBODY); + } + + err: + if (rsp == NULL) { + /* on error, try to respond with CMP error message to client */ + const char *data = NULL; + int flags = 0; + unsigned long err = ERR_peek_error_data(&data, &flags); + int fail_info = 1 << OSSL_CMP_PKIFAILUREINFO_badRequest; + /* TODO fail_info could be more specific */ + OSSL_CMP_PKISI *si = NULL; + + if ((si = OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_rejection, + fail_info, NULL)) == NULL) + return 0; + if (err != 0 && (flags & ERR_TXT_STRING) != 0) + data = ERR_reason_error_string(err); + rsp = ossl_cmp_error_new(srv_ctx->ctx, si, + err != 0 ? ERR_GET_REASON(err) : -1, + data, srv_ctx->sendUnprotectedErrors); + OSSL_CMP_PKISI_free(si); + } + + /* possibly close the transaction */ + rsp_type = + rsp != NULL ? ossl_cmp_msg_get_bodytype(rsp) : OSSL_CMP_PKIBODY_ERROR; + switch (rsp_type) { + case OSSL_CMP_PKIBODY_IP: + case OSSL_CMP_PKIBODY_CP: + case OSSL_CMP_PKIBODY_KUP: + case OSSL_CMP_PKIBODY_RP: + if (OSSL_CMP_CTX_get_option(ctx, OSSL_CMP_OPT_IMPLICITCONFIRM) == 0) + break; + /* fall through */ + + case OSSL_CMP_PKIBODY_PKICONF: + case OSSL_CMP_PKIBODY_GENP: + case OSSL_CMP_PKIBODY_ERROR: + /* TODO possibly support further terminating response message types */ + (void)OSSL_CMP_CTX_set1_transactionID(ctx, NULL); /* ignore any error */ + + default: /* not closing transaction in other cases */ + break; + } + return rsp; +} + +/* + * Server interface that may substitute OSSL_CMP_MSG_http_perform at the client. + * The OSSL_CMP_SRV_CTX must be set as client_ctx->transfer_cb_arg. + * returns received message on success, else NULL and pushes an element on the + * error stack. + */ +OSSL_CMP_MSG * OSSL_CMP_CTX_server_perform(OSSL_CMP_CTX *client_ctx, + const OSSL_CMP_MSG *req) +{ + OSSL_CMP_SRV_CTX *srv_ctx = NULL; + + if (client_ctx == NULL || req == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return 0; + } + + if ((srv_ctx = OSSL_CMP_CTX_get_transfer_cb_arg(client_ctx)) == NULL) { + CMPerr(0, CMP_R_ERROR_TRANSFERRING_OUT); + return 0; + } + + return OSSL_CMP_SRV_process_request(srv_ctx, req); +} diff --git a/crypto/cmp/cmp_status.c b/crypto/cmp/cmp_status.c index 7ebc57d37b..6232239237 100644 --- a/crypto/cmp/cmp_status.c +++ b/crypto/cmp/cmp_status.c @@ -28,17 +28,13 @@ /* CMP functions related to PKIStatus */ -int ossl_cmp_pkisi_get_pkistatus(const OSSL_CMP_PKISI *si) +int ossl_cmp_pkisi_get_status(const OSSL_CMP_PKISI *si) { if (!ossl_assert(si != NULL && si->status != NULL)) return -1; return ossl_cmp_asn1_get_int(si->status); } -/* - * return the declared identifier and a short explanation for the PKIStatus - * value as specified in RFC4210, Appendix F. - */ const char *ossl_cmp_PKIStatus_to_string(int status) { switch (status) { @@ -67,21 +63,13 @@ const char *ossl_cmp_PKIStatus_to_string(int status) } } -/* - * returns a pointer to the statusString contained in a PKIStatusInfo - * returns NULL on error - */ -OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusstring(const OSSL_CMP_PKISI *si) +OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusString(const OSSL_CMP_PKISI *si) { if (!ossl_assert(si != NULL)) return NULL; return si->statusString; } -/* - * returns the FailureInfo bits of the given PKIStatusInfo - * returns -1 on error - */ int ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si) { int i; @@ -95,12 +83,9 @@ int ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si) return res; } -/* - * internal function +/*- * convert PKIFailureInfo number to human-readable string - * - * returns pointer to static string - * returns NULL on error + * returns pointer to static string, or NULL on error */ static const char *CMP_PKIFAILUREINFO_to_string(int number) { @@ -164,11 +149,7 @@ static const char *CMP_PKIFAILUREINFO_to_string(int number) } } -/* - * checks PKIFailureInfo bits in a given PKIStatusInfo - * returns 1 if a given bit is set, 0 if not, -1 on error - */ -int ossl_cmp_pkisi_pkifailureinfo_check(const OSSL_CMP_PKISI *si, int bit_index) +int ossl_cmp_pkisi_check_pkifailureinfo(const OSSL_CMP_PKISI *si, int bit_index) { if (!ossl_assert(si != NULL && si->failInfo != NULL)) return -1; @@ -180,16 +161,17 @@ int ossl_cmp_pkisi_pkifailureinfo_check(const OSSL_CMP_PKISI *si, int bit_index) return ASN1_BIT_STRING_get_bit(si->failInfo, bit_index); } -/* +/*- * place human-readable error string created from PKIStatusInfo in given buffer * returns pointer to the same buffer containing the string, or NULL on error */ -char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf, - size_t bufsize) +static +char *snprint_PKIStatusInfo_parts(int status, int fail_info, + const OSSL_CMP_PKIFREETEXT *status_strings, + char *buf, size_t bufsize) { - int status, failure, fail_info; + int failure; const char *status_string, *failure_string; - OSSL_CMP_PKIFREETEXT *status_strings; ASN1_UTF8STRING *text; int i; int printed_chars; @@ -197,22 +179,22 @@ char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf, int n_status_strings; char *write_ptr = buf; -#define ADVANCE_BUFFER \ - if (printed_chars < 0 || (size_t)printed_chars >= bufsize) \ - return NULL; \ - write_ptr += printed_chars; \ - bufsize -= printed_chars; - - if (ctx == NULL - || buf == NULL - || (status = OSSL_CMP_CTX_get_status(ctx)) < 0 + if (buf == NULL + || status < 0 || (status_string = ossl_cmp_PKIStatus_to_string(status)) == NULL) return NULL; + +#define ADVANCE_BUFFER \ + if (printed_chars < 0 || (size_t)printed_chars >= bufsize) \ + return NULL; \ + write_ptr += printed_chars; \ + bufsize -= printed_chars; + printed_chars = BIO_snprintf(write_ptr, bufsize, "%s", status_string); ADVANCE_BUFFER; /* failInfo is optional and may be empty */ - if ((fail_info = OSSL_CMP_CTX_get_failInfoCode(ctx)) > 0) { + if (fail_info != 0) { printed_chars = BIO_snprintf(write_ptr, bufsize, "; PKIFailureInfo: "); ADVANCE_BUFFER; for (failure = 0; failure <= OSSL_CMP_PKIFAILUREINFO_MAX; failure++) { @@ -220,7 +202,7 @@ char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf, failure_string = CMP_PKIFAILUREINFO_to_string(failure); if (failure_string != NULL) { printed_chars = BIO_snprintf(write_ptr, bufsize, "%s%s", - failure > 0 ? ", " : "", + failinfo_found ? ", " : "", failure_string); ADVANCE_BUFFER; failinfo_found = 1; @@ -235,7 +217,6 @@ char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf, } /* statusString sequence is optional and may be empty */ - status_strings = OSSL_CMP_CTX_get0_statusString(ctx); n_status_strings = sk_ASN1_UTF8STRING_num(status_strings); if (n_status_strings > 0) { printed_chars = BIO_snprintf(write_ptr, bufsize, "; StatusString%s: ", @@ -253,13 +234,44 @@ char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf, return buf; } -/* +char *OSSL_CMP_snprint_PKIStatusInfo(const OSSL_CMP_PKISI *statusInfo, + char *buf, size_t bufsize) +{ + int failure_info; + + if (statusInfo == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return NULL; + } + + failure_info = ossl_cmp_pkisi_get_pkifailureinfo(statusInfo); + + return snprint_PKIStatusInfo_parts(ASN1_INTEGER_get(statusInfo->status), + failure_info, + statusInfo->statusString, buf, bufsize); +} + +char *OSSL_CMP_CTX_snprint_PKIStatus(const OSSL_CMP_CTX *ctx, char *buf, + size_t bufsize) +{ + if (ctx == NULL) { + CMPerr(0, CMP_R_NULL_ARGUMENT); + return NULL; + } + + return snprint_PKIStatusInfo_parts(OSSL_CMP_CTX_get_status(ctx), + OSSL_CMP_CTX_get_failInfoCode(ctx), + OSSL_CMP_CTX_get0_statusString(ctx), + buf, bufsize); +} + +/*- * Creates a new PKIStatusInfo structure and fills it in * returns a pointer to the structure on success, NULL on error * note: strongly overlaps with TS_RESP_CTX_set_status_info() * and TS_RESP_CTX_add_failure_info() in ../ts/ts_rsp_sign.c */ -OSSL_CMP_PKISI *ossl_cmp_statusinfo_new(int status, int fail_info, +OSSL_CMP_PKISI *OSSL_CMP_STATUSINFO_new(int status, int fail_info, const char *text) { OSSL_CMP_PKISI *si = OSSL_CMP_PKISI_new(); diff --git a/crypto/cmp/cmp_util.c b/crypto/cmp/cmp_util.c index ad4ae66454..f53ff889e6 100644 --- a/crypto/cmp/cmp_util.c +++ b/crypto/cmp/cmp_util.c @@ -320,6 +320,26 @@ STACK_OF(X509) *ossl_cmp_build_cert_chain(STACK_OF(X509) *certs, X509 *cert) return result; } +int ossl_cmp_sk_ASN1_UTF8STRING_push_str(STACK_OF(ASN1_UTF8STRING) *sk, + const char *text) +{ + ASN1_UTF8STRING *utf8string; + + if (!ossl_assert(sk != NULL && text != NULL)) + return 0; + if ((utf8string = ASN1_UTF8STRING_new()) == NULL) + return 0; + if (!ASN1_STRING_set(utf8string, text, -1)) + goto err; + if (!sk_ASN1_UTF8STRING_push(sk, utf8string)) + goto err; + return 1; + + err: + ASN1_UTF8STRING_free(utf8string); + return 0; +} + int ossl_cmp_asn1_octet_string_set1(ASN1_OCTET_STRING **tgt, const ASN1_OCTET_STRING *src) { @@ -364,3 +384,39 @@ int ossl_cmp_asn1_octet_string_set1_bytes(ASN1_OCTET_STRING **tgt, *tgt = new; return 1; } + +/* + * calculate a digest of the given certificate, + * using the same hash algorithm as in the certificate signature. + */ +ASN1_OCTET_STRING *OSSL_CMP_X509_digest(const X509 *cert) +{ + unsigned int len; + unsigned char hash[EVP_MAX_MD_SIZE]; + int md_NID; + const EVP_MD *md = NULL; + ASN1_OCTET_STRING *new = NULL; + + if (!ossl_assert(cert != NULL)) + return NULL; + + /*- + * select hash algorithm, as stated in CMP RFC 4210 Appendix F. + * Compilable ASN.1 defs: + * the hash of the certificate, using the same hash algorithm + * as is used to create and verify the certificate signature + */ + if (!OBJ_find_sigid_algs(X509_get_signature_nid(cert), &md_NID, NULL) + || (md = EVP_get_digestbynid(md_NID)) == NULL) { + CMPerr(0, CMP_R_UNSUPPORTED_ALGORITHM); + return NULL; + } + if (!X509_digest(cert, md, hash, &len) + || (new = ASN1_OCTET_STRING_new()) == NULL) + return NULL; + if (!(ASN1_OCTET_STRING_set(new, hash, len))) { + ASN1_OCTET_STRING_free(new); + return NULL; + } + return new; +} diff --git a/crypto/crmf/crmf_err.c b/crypto/crmf/crmf_err.c index 87e6a2da60..80f71543ca 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-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2020 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 @@ -30,6 +30,14 @@ static const ERR_STRING_DATA CRMF_str_reasons[] = { "iterationcount below 100"}, {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_MALFORMED_IV), "malformed iv"}, {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_NULL_ARGUMENT), "null argument"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY), + "popo inconsistent public key"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_MISSING_PUBLIC_KEY), + "popo missing public key"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_MISSING_SUBJECT), + "popo missing subject"}, + {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED), + "popo raverified not accepted"}, {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_SETTING_MAC_ALGOR_FAILURE), "setting mac algor failure"}, {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_SETTING_OWF_ALGOR_FAILURE), @@ -44,8 +52,6 @@ static const ERR_STRING_DATA CRMF_str_reasons[] = { "unsupported method for creating popo"}, {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_UNSUPPORTED_POPO_METHOD), "unsupported popo method"}, - {ERR_PACK(ERR_LIB_CRMF, 0, CRMF_R_UNSUPPORTED_POPO_NOT_ACCEPTED), - "unsupported popo not accepted"}, {0, NULL} }; diff --git a/crypto/crmf/crmf_lib.c b/crypto/crmf/crmf_lib.c index 863d26f86e..acbc9af5cb 100644 --- a/crypto/crmf/crmf_lib.c +++ b/crypto/crmf/crmf_lib.c @@ -303,7 +303,7 @@ static int crmf_asn1_get_int(const ASN1_INTEGER *a) return (int)res; } -int OSSL_CRMF_MSG_get_certReqId(OSSL_CRMF_MSG *crm) +int OSSL_CRMF_MSG_get_certReqId(const OSSL_CRMF_MSG *crm) { if (crm == NULL || /* not really needed: */ crm->certReq == NULL) { CRMFerr(CRMF_F_OSSL_CRMF_MSG_GET_CERTREQID, CRMF_R_NULL_ARGUMENT); @@ -495,11 +495,17 @@ int OSSL_CRMF_MSGS_verify_popo(const OSSL_CRMF_MSGS *reqs, switch (req->popo->type) { case OSSL_CRMF_POPO_RAVERIFIED: - if (acceptRAVerified) - return 1; + if (!acceptRAVerified) { + CRMFerr(0, CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED); + return 0; + } break; case OSSL_CRMF_POPO_SIGNATURE: pubkey = req->certReq->certTemplate->publicKey; + if (pubkey == NULL) { + CRMFerr(0, CRMF_R_POPO_MISSING_PUBLIC_KEY); + return 0; + } sig = req->popo->value.signature; if (sig->poposkInput != NULL) { /* @@ -507,26 +513,34 @@ int OSSL_CRMF_MSGS_verify_popo(const OSSL_CRMF_MSGS *reqs, * the public key from the certificate template. This MUST be * exactly the same value as contained in the certificate template. */ - const ASN1_ITEM *rptr = ASN1_ITEM_rptr(OSSL_CRMF_POPOSIGNINGKEYINPUT); - - if (pubkey == NULL - || sig->poposkInput->publicKey == NULL - || X509_PUBKEY_cmp(pubkey, sig->poposkInput->publicKey) - || ASN1_item_verify(rptr, sig->algorithmIdentifier, - sig->signature, sig->poposkInput, - X509_PUBKEY_get0(pubkey)) < 1) - break; + if (sig->poposkInput->publicKey == NULL) { + CRMFerr(0, CRMF_R_POPO_MISSING_PUBLIC_KEY); + return 0; + } + if (X509_PUBKEY_cmp(pubkey, sig->poposkInput->publicKey) != 0) { + CRMFerr(0, CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY); + return 0; + } + /* + * TODO check the contents of the authInfo sub-field, + * see RFC 4211 https://tools.ietf.org/html/rfc4211#section-4.1 + */ + if (ASN1_item_verify(ASN1_ITEM_rptr(OSSL_CRMF_POPOSIGNINGKEYINPUT), + sig->algorithmIdentifier, sig->signature, + sig->poposkInput, + X509_PUBKEY_get0(pubkey)) < 1) + return 0; } else { - if (pubkey == NULL - || req->certReq->certTemplate->subject == NULL - || ASN1_item_verify(ASN1_ITEM_rptr(OSSL_CRMF_CERTREQUEST), - sig->algorithmIdentifier, - sig->signature, - req->certReq, - X509_PUBKEY_get0(pubkey)) < 1) - break; + if (req->certReq->certTemplate->subject == NULL) { + CRMFerr(0, CRMF_R_POPO_MISSING_SUBJECT); + return 0; + } + if (ASN1_item_verify(ASN1_ITEM_rptr(OSSL_CRMF_CERTREQUEST), + sig->algorithmIdentifier, sig->signature, + req->certReq, X509_PUBKEY_get0(pubkey)) < 1) + return 0; } - return 1; + break; case OSSL_CRMF_POPO_KEYENC: /* * TODO: when OSSL_CMP_certrep_new() supports encrypted certs, @@ -540,19 +554,19 @@ int OSSL_CRMF_MSGS_verify_popo(const OSSL_CRMF_MSGS *reqs, CRMF_R_UNSUPPORTED_POPO_METHOD); return 0; } - CRMFerr(CRMF_F_OSSL_CRMF_MSGS_VERIFY_POPO, - CRMF_R_UNSUPPORTED_POPO_NOT_ACCEPTED); - return 0; + return 1; } /* retrieves the serialNumber of the given cert template or NULL on error */ -ASN1_INTEGER *OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(OSSL_CRMF_CERTTEMPLATE *tmpl) +ASN1_INTEGER +*OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(const OSSL_CRMF_CERTTEMPLATE *tmpl) { return tmpl != NULL ? tmpl->serialNumber : NULL; } /* retrieves the issuer name of the given cert template or NULL on error */ -X509_NAME *OSSL_CRMF_CERTTEMPLATE_get0_issuer(OSSL_CRMF_CERTTEMPLATE *tmpl) +X509_NAME +*OSSL_CRMF_CERTTEMPLATE_get0_issuer(const OSSL_CRMF_CERTTEMPLATE *tmpl) { return tmpl != NULL ? tmpl->issuer : NULL; } @@ -606,7 +620,7 @@ int OSSL_CRMF_CERTTEMPLATE_fill(OSSL_CRMF_CERTTEMPLATE *tmpl, * returns a pointer to the decrypted certificate * returns NULL on error or if no certificate available */ -X509 *OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(OSSL_CRMF_ENCRYPTEDVALUE *ecert, +X509 *OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(const OSSL_CRMF_ENCRYPTEDVALUE *ecert, EVP_PKEY *pkey) { X509 *cert = NULL; /* decrypted certificate */ diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 8689e34925..c35d235e18 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -2076,8 +2076,10 @@ BN_R_TOO_MANY_ITERATIONS:113:too many iterations BN_R_TOO_MANY_TEMPORARY_VARIABLES:109:too many temporary variables CMP_R_ALGORITHM_NOT_SUPPORTED:139:algorithm not supported CMP_R_BAD_REQUEST_ID:108:bad request id +CMP_R_CERTHASH_UNMATCHED:156:certhash unmatched CMP_R_CERTID_NOT_FOUND:109:certid not found CMP_R_CERTIFICATE_NOT_FOUND:112:certificate not found +CMP_R_CERTREQMSG_NOT_FOUND:157:certreqmsg not found CMP_R_CERTRESPONSE_NOT_FOUND:113:certresponse not found CMP_R_CERT_AND_KEY_DO_NOT_MATCH:114:cert and key do not match CMP_R_ERROR_CALCULATING_PROTECTION:115:error calculating protection @@ -2093,8 +2095,11 @@ CMP_R_ERROR_CREATING_POLLREQ:124:error creating pollreq CMP_R_ERROR_CREATING_RP:125:error creating rp CMP_R_ERROR_CREATING_RR:126:error creating rr CMP_R_ERROR_PARSING_PKISTATUS:107:error parsing pkistatus +CMP_R_ERROR_PROCESSING_MSG:158:error processing msg CMP_R_ERROR_PROTECTING_MESSAGE:127:error protecting message CMP_R_ERROR_SETTING_CERTHASH:128:error setting certhash +CMP_R_ERROR_TRANSFERRING_OUT:159:error transferring out +CMP_R_ERROR_UNEXPECTED_CERTCONF:160:error unexpected certconf CMP_R_ERROR_VALIDATING_PROTECTION:140:error validating protection CMP_R_FAILED_EXTRACTING_PUBKEY:141:failed extracting pubkey CMP_R_FAILURE_OBTAINING_RANDOM:110:failure obtaining random @@ -2107,6 +2112,7 @@ CMP_R_MISSING_PRIVATE_KEY:131:missing private key CMP_R_MISSING_PROTECTION:143:missing protection CMP_R_MISSING_SENDER_IDENTIFICATION:111:missing sender identification CMP_R_MISSING_TRUST_STORE:144:missing trust store +CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED:161:multiple requests not supported CMP_R_MULTIPLE_SAN_SOURCES:102:multiple san sources CMP_R_NO_STDIO:194:no stdio CMP_R_NO_SUITABLE_SENDER_CERT:145:no suitable sender cert @@ -2256,6 +2262,10 @@ 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 CRMF_R_NULL_ARGUMENT:109:null argument +CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY:117:popo inconsistent public key +CRMF_R_POPO_MISSING_PUBLIC_KEY:118:popo missing public key +CRMF_R_POPO_MISSING_SUBJECT:119:popo missing subject +CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED:120:popo raverified not accepted CRMF_R_SETTING_MAC_ALGOR_FAILURE:110:setting mac algor failure CRMF_R_SETTING_OWF_ALGOR_FAILURE:111:setting owf algor failure CRMF_R_UNSUPPORTED_ALGORITHM:112:unsupported algorithm @@ -2264,7 +2274,6 @@ CRMF_R_UNSUPPORTED_CIPHER:114:unsupported cipher CRMF_R_UNSUPPORTED_METHOD_FOR_CREATING_POPO:115:\ unsupported method for creating popo CRMF_R_UNSUPPORTED_POPO_METHOD:116:unsupported popo method -CRMF_R_UNSUPPORTED_POPO_NOT_ACCEPTED:117:unsupported popo not accepted CRYPTO_R_BAD_ALGORITHM_NAME:117:bad algorithm name CRYPTO_R_CONFLICTING_NAMES:118:conflicting names CRYPTO_R_FIPS_MODE_NOT_SUPPORTED:101:fips mode not supported diff --git a/doc/internal/man3/ossl_cmp_hdr_init.pod b/doc/internal/man3/ossl_cmp_hdr_init.pod index a7a4d87f09..31468a567b 100644 --- a/doc/internal/man3/ossl_cmp_hdr_init.pod +++ b/doc/internal/man3/ossl_cmp_hdr_init.pod @@ -14,7 +14,7 @@ ossl_cmp_hdr_push1_freeText, ossl_cmp_hdr_generalinfo_item_push0, ossl_cmp_hdr_generalinfo_items_push1, ossl_cmp_hdr_set_implicitConfirm, -ossl_cmp_hdr_check_implicitConfirm, +ossl_cmp_hdr_has_implicitConfirm, ossl_cmp_hdr_init - functions manipulating CMP message headers @@ -41,7 +41,7 @@ ossl_cmp_hdr_init int ossl_cmp_hdr_push1_freeText(OSSL_CMP_PKIHEADER *hdr, ASN1_UTF8STRING *text); int ossl_cmp_hdr_set_implicitConfirm(OSSL_CMP_PKIHEADER *hdr); - int ossl_cmp_hdr_check_implicitConfirm(OSSL_CMP_PKIHEADER *hdr); + int ossl_cmp_hdr_has_implicitConfirm(OSSL_CMP_PKIHEADER *hdr); int ossl_cmp_hdr_init(OSSL_CMP_CTX *ctx, OSSL_CMP_PKIHEADER *hdr); =head1 DESCRIPTION @@ -85,7 +85,7 @@ pointer. ossl_cmp_hdr_set_implicitConfirm() sets implicitConfirm in the generalInfo field of the PKIMessage header. -ossl_cmp_hdr_check_implicitConfirm() returns 1 if implicitConfirm is +ossl_cmp_hdr_has_implicitConfirm() returns 1 if implicitConfirm is set int generalInfo field of the given PKIMessage header, 0 if not. ossl_cmp_hdr_init() initializes a PKIHeader structure based on the diff --git a/doc/internal/man3/ossl_cmp_mock_srv_new.pod b/doc/internal/man3/ossl_cmp_mock_srv_new.pod new file mode 100644 index 0000000000..da1f44b391 --- /dev/null +++ b/doc/internal/man3/ossl_cmp_mock_srv_new.pod @@ -0,0 +1,85 @@ +=pod + +=head1 NAME + +ossl_cmp_mock_srv_new, +ossl_cmp_mock_srv_free, +ossl_cmp_mock_srv_set1_certOut, +ossl_cmp_mock_srv_set1_chainOut, +ossl_cmp_mock_srv_set1_caPubsOut, +ossl_cmp_mock_srv_set_statusInfo, +ossl_cmp_mock_srv_set_send_error, +ossl_cmp_mock_srv_set_pollCount, +ossl_cmp_mock_srv_set_checkAfterTime +- functions used for testing with CMP mock server + +=head1 SYNOPSIS + + #include + + OSSL_CMP_SRV_CTX *ossl_cmp_mock_srv_new(void); + void ossl_cmp_mock_srv_free(OSSL_CMP_SRV_CTX *srv_ctx); + + 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); + int ossl_cmp_mock_srv_set1_caPubsOut(OSSL_CMP_SRV_CTX *srv_ctx, + STACK_OF(X509) *caPubs); + int ossl_cmp_mock_srv_set_statusInfo(OSSL_CMP_SRV_CTX *srv_ctx, int status, + int fail_info, const char *text); + int ossl_cmp_mock_srv_set_send_error(OSSL_CMP_SRV_CTX *srv_ctx, int val); + int ossl_cmp_mock_srv_set_pollCount(OSSL_CMP_SRV_CTX *srv_ctx, int count); + int ossl_cmp_mock_srv_set_checkAfterTime(OSSL_CMP_SRV_CTX *srv_ctx, int sec); + +=head1 DESCRIPTION + +ossl_cmp_mock_srv_new() allocates the contexts for the CMP mock server. + +ossl_cmp_mock_srv_free() deallocates the contexts for the CMP mock server. + +OSSL_CMP_SRV_CTX_set1_certOut() sets the certificate to be returned in +cp/ip/kup. + +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. + +OSSL_CMP_SRV_CTX_set1_caPubsOut() sets the caPubs to be returned in an ip. + +OSSL_CMP_SRV_CTX_set_statusInfo() sets the status info to be returned. + +OSSL_CMP_SRV_CTX_set_send_error() enables enforcement of error responses. + +OSSL_CMP_SRV_CTX_set_pollCount() sets the number of polls before cert response. + +OSSL_CMP_SRV_CTX_set_checkAfterTime() sets the number of seconds +the client should wait for the next poll. + + +=head1 NOTES + +CMP is defined in RFC 4210 (and CRMF in RFC 4211). + +=head1 RETURN VALUES + +ossl_cmp_mock_srv() returns a B structure on success, +NULL on error. + +ossl_cmp_mock_srv_free() does not return a value. + +All other functions return 1 on success, 0 on error. + +=head1 HISTORY + +The OpenSSL CMP support was added in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2007-2020 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/internal/man3/ossl_cmp_statusinfo_new.pod b/doc/internal/man3/ossl_cmp_pkisi_get_status.pod similarity index 58% rename from doc/internal/man3/ossl_cmp_statusinfo_new.pod rename to doc/internal/man3/ossl_cmp_pkisi_get_status.pod index ee7dd35cf5..deca1aa2bb 100644 --- a/doc/internal/man3/ossl_cmp_statusinfo_new.pod +++ b/doc/internal/man3/ossl_cmp_pkisi_get_status.pod @@ -2,13 +2,11 @@ =head1 NAME -ossl_cmp_statusinfo_new, -ossl_cmp_pkisi_pkistatus_get, -ossl_cmp_pkisi_pkifailureinfo_get, -ossl_cmp_pkisi_pkifailureinfo_check, -ossl_cmp_pkisi_failinfo_get0, -ossl_cmp_pkisi_statusstring_get0, -ossl_pkisi_snprint +ossl_cmp_pkisi_get_status, +ossl_cmp_PKIStatus_to_string, +ossl_cmp_pkisi_get0_statusString, +ossl_cmp_pkisi_get_pkifailureinfo, +ossl_cmp_pkisi_check_pkifailureinfo - functions for managing PKI status information =head1 SYNOPSIS @@ -44,40 +42,27 @@ ossl_pkisi_snprint # define OSSL_CMP_PKIFAILUREINFO_duplicateCertReq 26 # define OSSL_CMP_PKIFAILUREINFO_MAX 26 - OSSL_CMP_PKISI *ossl_cmp_statusinfo_new(int status, int fail_info, - const char *text); - int ossl_cmp_pkisi_pkistatus_get(OSSL_CMP_PKISI *si); - int ossl_cmp_pkisi_pkifailureinfo_get(OSSL_CMP_PKISI *si); - int ossl_cmp_pkisi_pkifailureinfo_check(OSSL_CMP_PKISI *si, int bit_index); - OSSL_CMP_PKIFAILUREINFO *ossl_cmp_pkisi_failinfo_get0(const OSSL_CMP_PKISI *si); - OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_statusstring_get0(const OSSL_CMP_PKISI *si); - char *ossl_pkisi_snprint(OSSL_CMP_PKISI *si, char *buf, int bufsize); + int ossl_cmp_pkisi_get_status(const OSSL_CMP_PKISI *si); + const char *ossl_cmp_PKIStatus_to_string(int status); + OSSL_CMP_PKIFREETEXT *ossl_cmp_pkisi_get0_statusString(const OSSL_CMP_PKISI *si); + int ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si); + int ossl_cmp_pkisi_check_pkifailureinfo(const OSSL_CMP_PKISI *si, int index); =head1 DESCRIPTION -ossl_cmp_statusinfo_new() creates a new PKIStatusInfo structure and fills it -with the given values. It sets the status field to B. -If B is not NULL, it is copied to statusString. -B is is interpreted as bit pattern for the failInfo field. -Returns a pointer to the structure on success, or NULL on error. +ossl_cmp_pkisi_get_status() returns the PKIStatus of B, or -1 on error. -ossl_cmp_pkisi_pkistatus_get() returns the PKIStatus of B, or -1 on error. +ossl_cmp_PKIStatus_to_string() returns a human-readable string representing +the PKIStatus values as specified in RFC 4210, Appendix F. -ossl_cmp_pkisi_pkifailureinfo_get() returns the PKIFailureInfo bits -of B, encoded as integer, or -1 on error. - -ossl_cmp_pkisi_pkifailureinfo_check() returns the state of the bit (0 or 1) -with index B in the PKIFailureInfo of the B, or -1 on error. - -ossl_cmp_pkisi_failinfo_get0() returns a direct pointer to the failInfo -field contained in B, or NULL on error. - -ossl_cmp_pkisi_statusstring_get0() returns a direct pointer to the statusString +ossl_cmp_pkisi_get0_statusString() returns a direct pointer to the statusString field contained in B. -ossl_pkisi_snprint() places at max B characters of human-readable -error string of B in pre-allocated B. Returns pointer to the same -B containing the string, or NULL on error. +ossl_cmp_pkisi_get_pkifailureinfo() returns the PKIFailureInfo bits +of B, encoded as integer, or -1 on error. + +ossl_cmp_pkisi_check_pkifailureinfo() returns the state of the bit (0 or 1) +with index B in the PKIFailureInfo of the B, or -1 on error. =head1 NOTES diff --git a/doc/man3/OSSL_CMP_CTX_new.pod b/doc/man3/OSSL_CMP_CTX_new.pod index b10cfc4801..626f7d65af 100644 --- a/doc/man3/OSSL_CMP_CTX_new.pod +++ b/doc/man3/OSSL_CMP_CTX_new.pod @@ -239,7 +239,7 @@ The following options can be set: OSSL_CMP_OPT_MAC_ALGNID The MAC algorithm NID to be used in RFC 4210's MSG_MAC_ALG, - if applicable used for message protection. + if applicable used for message protection. Default is HMAC-SHA1 as per RFC 4210. =item B @@ -404,20 +404,40 @@ The reference counts of those certificates handled successfully are increased. OSSL_CMP_CTX_get0_untrusted_certs(OSSL_CMP_CTX *ctx) returns a pointer to the list of untrusted certs, which my be empty if unset. -OSSL_CMP_CTX_set1_clCert() sets the client certificate in the given -OSSL_CMP_CTX structure. The client certificate will then be used by the -functions to set the "sender" field for outgoing messages and it will be -included in the extraCerts field. - -OSSL_CMP_CTX_set1_pkey() sets the private key corresponding to the client -certificate set with B in the given CMP context. -Used to create the protection in case of MSG_SIG_ALG. - -OSSL_CMP_CTX_set1_referenceValue() sets the given referenceValue in the given -B or clears it if the B argument is NULL. - -OSSL_CMP_CTX_set1_secretValue() sets the B with the length B in the -given B or clears it if the B argument is NULL. +OSSL_CMP_CTX_set1_clCert() sets the client certificate in the given B. +The public key of this B must correspond to +the private key set via B. +When using signature-based protection of CMP request messages +this "protection certificate" will be included first in the extraCerts field. +The subject of this B will be used as the "sender" field +of outgoing CMP messages, with the fallback being +the B set via B. +The B argument may be NULL to clear the entry. + +OSSL_CMP_CTX_set1_pkey() sets the private key corresponding to +the client certificate B set via B. +This key is used create signature-based protection (protectionAlg = MSG_SIG_ALG) +of outgoing messages +unless a PBM secret has been set via B. +The B argument may be NULL to clear the entry. + +OSSL_CMP_CTX_set1_secretValue() sets the byte string B with length B +as PBM secret in the given B or clears it if the B argument is NULL. +If present, this secret is used to create PBM-based protection of outgoing +messages and to verify any PBM-based protection of incoming messages +(protectionAlg = MSG_MAC_ALG). PBM stands for Password-Based MAC. +PBM-based protection takes precedence over signature-based protection. + +OSSL_CMP_CTX_set1_referenceValue() sets the given referenceValue B with +length B in the given B or clears it if the B argument is NULL. +According to RFC 4210 section 5.1.1, if no value for the "sender" field in +CMP message headers can be determined (i.e., no B and no B +is given) then the "sender" field will contain the NULL-DN +and the senderKID field of the CMP message header must be set. +When signature-based protection is used the senderKID will be set to +the subjectKeyIdentifier of the as far as present. +If not present or when PBM-based protection is used +the B value is taken as the fallback value for the senderKID. OSSL_CMP_CTX_set1_recipient() sets the recipient name that will be used in the PKIHeader of a request message, i.e. the X509 name of the (CA) server. diff --git a/doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod b/doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod deleted file mode 100644 index 3ae6831ee2..0000000000 --- a/doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod +++ /dev/null @@ -1,46 +0,0 @@ -=pod - -=head1 NAME - -OSSL_CMP_CTX_snprint_PKIStatus -- function(s) for managing the CMP PKIStatus - -=head1 SYNOPSIS - - #include - - char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf, int bufsize); - -=head1 DESCRIPTION - -This is the PKIStatus API for using CMP (Certificate Management Protocol) with -OpenSSL. - -OSSL_CMP_CTX_snprint_PKIStatus() takes the PKIStatusInfo components contained -in the given CMP context and places a human-readable string created from them -in the given buffer, with the given maximal length. -On success it returns a copy of the buffer pointer containing the string. - -=head1 NOTES - -CMP is defined in RFC 4210 (and CRMF in RFC 4211). - -=head1 RETURN VALUES - -OSSL_CMP_CTX_snprint_PKIStatus() -returns the intended pointer value as described above or NULL on error. - -=head1 HISTORY - -The OpenSSL CMP support was added in OpenSSL 3.0. - -=head1 COPYRIGHT - -Copyright 2007-2019 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_MSG_get0_header.pod b/doc/man3/OSSL_CMP_MSG_get0_header.pod index 3ed1140082..cee99cd00b 100644 --- a/doc/man3/OSSL_CMP_MSG_get0_header.pod +++ b/doc/man3/OSSL_CMP_MSG_get0_header.pod @@ -2,7 +2,9 @@ =head1 NAME -OSSL_CMP_MSG_get0_header +OSSL_CMP_MSG_get0_header, +OSSL_d2i_CMP_MSG_bio, +OSSL_i2d_CMP_MSG_bio - function(s) manipulating CMP messages =head1 SYNOPSIS @@ -10,20 +12,31 @@ OSSL_CMP_MSG_get0_header #include OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg); + OSSL_CMP_MSG *OSSL_d2i_CMP_MSG_bio(BIO *bio, OSSL_CMP_MSG **msg); + int OSSL_i2d_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg); =head1 DESCRIPTION OSSL_CMP_MSG_get0_header returns the header of the given CMP message. +OSSL_d2i_CMP_MSG_bio parses an ASN.1-encoded OSSL_CMP_MSG from the BIO I. +It assigns a pointer to the new structure to I<*msg> if I is not NULL. + +OSSL_i2d_CMP_MSG_bio writes the OSSL_CMP_MSG I in ASN.1 encoding to BIO I. + =head1 NOTES CMP is defined in RFC 4210. =head1 RETURN VALUES -CMP_MSG_get0_header() returns the intended pointer value as described above +OSSL_CMP_MSG_get0_header() returns the intended pointer value as described above or NULL if the respective entry does not exist and on error. +OSSL_d2i_CMP_MSG_bio() returns the parsed message or NULL on error. + +OSSL_i2d_CMP_MSG_bio() returns 1 on success or 0 on error. + =head1 HISTORY The OpenSSL CMP support was added in OpenSSL 3.0. diff --git a/doc/man3/OSSL_CMP_SRV_CTX_new.pod b/doc/man3/OSSL_CMP_SRV_CTX_new.pod new file mode 100644 index 0000000000..45ac0174b7 --- /dev/null +++ b/doc/man3/OSSL_CMP_SRV_CTX_new.pod @@ -0,0 +1,159 @@ +=pod + +=head1 NAME + +OSSL_CMP_SRV_process_request, +OSSL_CMP_CTX_server_perform, +OSSL_CMP_SRV_CTX_new, +OSSL_CMP_SRV_CTX_free, +OSSL_CMP_SRV_cert_request_cb_t, +OSSL_CMP_SRV_rr_cb_t, +OSSL_CMP_SRV_certConf_cb_t, +OSSL_CMP_SRV_genm_cb_t, +OSSL_CMP_SRV_error_cb_t, +OSSL_CMP_SRV_pollReq_cb_t, +OSSL_CMP_SRV_CTX_init, +OSSL_CMP_SRV_CTX_get0_cmp_ctx, +OSSL_CMP_SRV_CTX_get0_custom_ctx, +OSSL_CMP_SRV_CTX_set_send_unprotected_errors, +OSSL_CMP_SRV_CTX_set_accept_unprotected, +OSSL_CMP_SRV_CTX_set_accept_raverified, +OSSL_CMP_SRV_CTX_set_grant_implicit_confirm +- generic functions to set up and control a CMP server + +=head1 SYNOPSIS + + #include + + OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req); + OSSL_CMP_MSG *OSSL_CMP_CTX_server_perform(OSSL_CMP_CTX *client_ctx, + const OSSL_CMP_MSG *req); + OSSL_CMP_SRV_CTX *OSSL_CMP_SRV_CTX_new(void); + void OSSL_CMP_SRV_CTX_free(OSSL_CMP_SRV_CTX *srv_ctx); + + typedef OSSL_CMP_PKISI *(*OSSL_CMP_SRV_cert_request_cb_t)( + OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req, + int certReqId, + const OSSL_CRMF_MSG *crm, + const X509_REQ *p10cr, + X509 **certOut, + STACK_OF(X509) **chainOut, + STACK_OF(X509) **caPubs); + typedef OSSL_CMP_PKISI *(*OSSL_CMP_SRV_rr_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req, + const X509_NAME *issuer, + const ASN1_INTEGER *serial); + typedef int (*OSSL_CMP_SRV_genm_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req, + STACK_OF(OSSL_CMP_ITAV) *in, + STACK_OF(OSSL_CMP_ITAV) **out); + typedef void (*OSSL_CMP_SRV_error_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req, + const OSSL_CMP_PKISI *statusInfo, + const ASN1_INTEGER *errorCode, + const OSSL_CMP_PKIFREETEXT *errorDetails); + typedef int (*OSSL_CMP_SRV_certConf_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req, + int certReqId, + const ASN1_OCTET_STRING *certHash, + const OSSL_CMP_PKISI *si); + typedef int (*OSSL_CMP_SRV_pollReq_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req, + int certReqId, + OSSL_CMP_MSG **certReq, + int64_t *check_after); + int OSSL_CMP_SRV_CTX_init(OSSL_CMP_SRV_CTX *srv_ctx, void *custom_ctx, + OSSL_CMP_SRV_cert_request_cb_t process_cert_request, + OSSL_CMP_SRV_rr_cb_t process_rr, + OSSL_CMP_SRV_genm_cb_t process_genm, + OSSL_CMP_SRV_error_cb_t process_error, + OSSL_CMP_SRV_certConf_cb_t process_certConf, + OSSL_CMP_SRV_pollReq_cb_t process_pollReq); + + OSSL_CMP_CTX *OSSL_CMP_SRV_CTX_get0_cmp_ctx(const OSSL_CMP_SRV_CTX *srv_ctx); + void *OSSL_CMP_SRV_CTX_get0_custom_ctx(const OSSL_CMP_SRV_CTX *srv_ctx); + + int OSSL_CMP_SRV_CTX_set_send_unprotected_errors(OSSL_CMP_SRV_CTX *srv_ctx, + int val); + 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); + +=head1 DESCRIPTION + +OSSL_CMP_SRV_process_request() implements the generic aspects of a CMP server. +It does the typical generic checks on the given request message, calls +the respective callback function (if present) for more specific processing, +and then assembles a result message, which may be a CMP error message. + +OSSL_CMP_CTX_server_perform() is an interface to +B that can be used by a CMP client +in the same way as B. +The B must be set as B of B. + +OSSL_CMP_SRV_CTX_new() creates and initializes an OSSL_CMP_SRV_CTX structure +and returns a pointer to it on success, NULL on error. + +OSSL_CMP_SRV_CTX_free() deletes the given B. + +OSSL_CMP_SRV_CTX_init() sets in the given B a custom server context +pointer as well as callback functions performing the specific processing of CMP +certificate requests, revocation requests, certificate confirmation requests, +general messages, error messages, and poll requests. +All arguments except B may be NULL. +If a callback for some message type is not given this means that the respective +type of CMP message is not supported by the server. + +OSSL_CMP_SRV_CTX_get0_cmp_ctx() returns the B from the B. + +OSSL_CMP_SRV_CTX_get0_custom_ctx() returns the custom server context from +B that has been set using B. + +OSSL_CMP_SRV_CTX_set_send_unprotected_errors() enables sending error messages +and other forms of negative responses unprotected. + +OSSL_CMP_SRV_CTX_set_accept_unprotected() enables acceptance of requests +without protection of with invalid protection. + +OSSL_CMP_SRV_CTX_set_accept_raverified() enables acceptance of ir/cr/kur +messages with POPO 'RAVerified'. + +OSSL_CMP_SRV_CTX_set_grant_implicit_confirm() enables granting implicit +confirmation of newly enrolled certificates if requested. + +=head1 NOTES + +CMP is defined in RFC 4210 (and CRMF in RFC 4211). + +=head1 RETURN VALUES + +OSSL_CMP_SRV_CTX_new() returns a B structure on success, +NULL on error. + +OSSL_CMP_SRV_CTX_free() does not return a value. + +OSSL_CMP_SRV_CTX_get0_cmp_ctx() returns a B structure on success, +NULL on error. + +OSSL_CMP_SRV_CTX_get0_custom_ctx() returns the custom server context +that has been set using B. + +All other functions return 1 on success, 0 on error. + +=head1 HISTORY + +The OpenSSL CMP support was added in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2007-2019 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_STATUSINFO_new.pod b/doc/man3/OSSL_CMP_STATUSINFO_new.pod new file mode 100644 index 0000000000..520a104d7e --- /dev/null +++ b/doc/man3/OSSL_CMP_STATUSINFO_new.pod @@ -0,0 +1,66 @@ +=pod + +=head1 NAME + +OSSL_CMP_STATUSINFO_new, +OSSL_CMP_snprint_PKIStatusInfo, +OSSL_CMP_CTX_snprint_PKIStatus +- function(s) for managing the CMP PKIStatus + +=head1 SYNOPSIS + + #include + + OSSL_CMP_PKISI *OSSL_CMP_STATUSINFO_new(int status, int fail_info, + const char *text); + char *OSSL_CMP_snprint_PKIStatusInfo(const OSSL_CMP_PKISI *statusInfo, + char *buf, size_t bufsize); + char *OSSL_CMP_CTX_snprint_PKIStatus(const OSSL_CMP_CTX *ctx, char *buf, + size_t bufsize); + +=head1 DESCRIPTION + +This is the PKIStatus API for using CMP (Certificate Management Protocol) with +OpenSSL. + +OSSL_CMP_STATUSINFO_new() creates a new PKIStatusInfo structure +and fills in the given values. +It sets the status field to B, +copies B (unless it is NULL) to statusString, +and interprets B as bit pattern for the failInfo field. + +OSSL_CMP_snprint_PKIStatusInfo() places a human-readable string +representing the given statusInfo +in the given buffer, with the given maximal length. + +OSSL_CMP_CTX_snprint_PKIStatus() places a human-readable string +representing the PKIStatusInfo components of the CMP context B +in the given buffer, with the given maximal length. + +=head1 NOTES + +CMP is defined in RFC 4210 (and CRMF in RFC 4211). + +=head1 RETURN VALUES + +OSSL_CMP_STATUSINFO_new() +returns a pointer to the structure on success, or NULL on error. + +OSSL_CMP_snprint_PKIStatusInfo() and +OSSL_CMP_CTX_snprint_PKIStatus() +return a copy of the buffer pointer containing the string or NULL on error. + +=head1 HISTORY + +The OpenSSL CMP support was added in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2007-2019 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_X509_digest.pod b/doc/man3/OSSL_CMP_X509_digest.pod new file mode 100644 index 0000000000..824d3497c3 --- /dev/null +++ b/doc/man3/OSSL_CMP_X509_digest.pod @@ -0,0 +1,36 @@ +=pod + +=head1 NAME + +OSSL_CMP_X509_digest +- CMP certificate utility functions + +=head1 SYNOPSIS + + #include + + ASN1_OCTET_STRING *OSSL_CMP_X509_digest(const X509 *cert); + +=head1 DESCRIPTION + +OSSL_CMP_X509_digest() calculates a digest of the given certificate +using the same hash algorithm as in the certificate signature. + +=head1 RETURN VALUES + +OSSL_CMP_X509_digest() returns an ASN1_OCTET_STRING on success, else NULL. + +=head1 HISTORY + +The OpenSSL CMP support was added in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2007-2019 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/X509_dup.pod b/doc/man3/X509_dup.pod index d7d8477896..cb1e9edf2c 100644 --- a/doc/man3/X509_dup.pod +++ b/doc/man3/X509_dup.pod @@ -122,13 +122,17 @@ OCSP_SIGNATURE_free, OCSP_SIGNATURE_new, OCSP_SINGLERESP_free, OCSP_SINGLERESP_new, +OSSL_CMP_ITAV_dup, OSSL_CMP_ITAV_free, +OSSL_CMP_MSG_dup, OSSL_CMP_MSG_it, OSSL_CMP_MSG_free, OSSL_CMP_PKIHEADER_free, OSSL_CMP_PKIHEADER_it, OSSL_CMP_PKIHEADER_new, +OSSL_CMP_PKISI_dup, OSSL_CMP_PKISI_free, +OSSL_CMP_PKISI_it, OSSL_CMP_PKISI_new, OSSL_CMP_PKISTATUS_it, OSSL_CRMF_CERTID_free, diff --git a/doc/man3/d2i_X509.pod b/doc/man3/d2i_X509.pod index d41d2e0c4b..354757387f 100644 --- a/doc/man3/d2i_X509.pod +++ b/doc/man3/d2i_X509.pod @@ -98,6 +98,7 @@ d2i_OCSP_SIGNATURE, d2i_OCSP_SINGLERESP, d2i_OSSL_CMP_MSG, d2i_OSSL_CMP_PKIHEADER, +d2i_OSSL_CMP_PKISI, d2i_OSSL_CRMF_CERTID, d2i_OSSL_CRMF_CERTTEMPLATE, d2i_OSSL_CRMF_ENCRYPTEDVALUE, @@ -289,6 +290,7 @@ i2d_OCSP_SIGNATURE, i2d_OCSP_SINGLERESP, i2d_OSSL_CMP_MSG, i2d_OSSL_CMP_PKIHEADER, +i2d_OSSL_CMP_PKISI, i2d_OSSL_CRMF_CERTID, i2d_OSSL_CRMF_CERTTEMPLATE, i2d_OSSL_CRMF_ENCRYPTEDVALUE, diff --git a/include/openssl/cmp.h b/include/openssl/cmp.h index 43dcc69993..54e756c501 100644 --- a/include/openssl/cmp.h +++ b/include/openssl/cmp.h @@ -207,13 +207,17 @@ typedef struct ossl_cmp_ctx_st OSSL_CMP_CTX; typedef struct ossl_cmp_pkiheader_st OSSL_CMP_PKIHEADER; DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKIHEADER) typedef struct ossl_cmp_msg_st OSSL_CMP_MSG; +DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_MSG) DECLARE_ASN1_ENCODE_FUNCTIONS(OSSL_CMP_MSG, OSSL_CMP_MSG, OSSL_CMP_MSG) typedef struct ossl_cmp_certstatus_st OSSL_CMP_CERTSTATUS; DEFINE_STACK_OF(OSSL_CMP_CERTSTATUS) typedef struct ossl_cmp_itav_st OSSL_CMP_ITAV; +DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_ITAV) DEFINE_STACK_OF(OSSL_CMP_ITAV) typedef struct ossl_cmp_revrepcontent_st OSSL_CMP_REVREPCONTENT; typedef struct ossl_cmp_pkisi_st OSSL_CMP_PKISI; +DECLARE_ASN1_FUNCTIONS(OSSL_CMP_PKISI) +DECLARE_ASN1_DUP_FUNCTION(OSSL_CMP_PKISI) DEFINE_STACK_OF(OSSL_CMP_PKISI) typedef struct ossl_cmp_certrepmessage_st OSSL_CMP_CERTREPMESSAGE; DEFINE_STACK_OF(OSSL_CMP_CERTREPMESSAGE) @@ -272,9 +276,9 @@ void OSSL_CMP_CTX_print_errors(OSSL_CMP_CTX *ctx); int OSSL_CMP_CTX_set1_serverPath(OSSL_CMP_CTX *ctx, const char *path); int OSSL_CMP_CTX_set1_serverName(OSSL_CMP_CTX *ctx, const char *name); int OSSL_CMP_CTX_set_serverPort(OSSL_CMP_CTX *ctx, int port); +# define OSSL_CMP_DEFAULT_PORT 80 int OSSL_CMP_CTX_set1_proxyName(OSSL_CMP_CTX *ctx, const char *name); int OSSL_CMP_CTX_set_proxyPort(OSSL_CMP_CTX *ctx, int port); -# define OSSL_CMP_DEFAULT_PORT 80 int OSSL_CMP_CTX_set_http_cb(OSSL_CMP_CTX *ctx, OSSL_HTTP_bio_cb_t cb); int OSSL_CMP_CTX_set_http_cb_arg(OSSL_CMP_CTX *ctx, void *arg); void *OSSL_CMP_CTX_get_http_cb_arg(const OSSL_CMP_CTX *ctx); @@ -329,32 +333,85 @@ int OSSL_CMP_CTX_get_failInfoCode(const OSSL_CMP_CTX *ctx); X509 *OSSL_CMP_CTX_get0_newCert(const OSSL_CMP_CTX *ctx); STACK_OF(X509) *OSSL_CMP_CTX_get1_caPubs(const OSSL_CMP_CTX *ctx); STACK_OF(X509) *OSSL_CMP_CTX_get1_extraCertsIn(const OSSL_CMP_CTX *ctx); -/* support application-level CMP debugging in cmp.c: */ int OSSL_CMP_CTX_set1_transactionID(OSSL_CMP_CTX *ctx, const ASN1_OCTET_STRING *id); int OSSL_CMP_CTX_set1_senderNonce(OSSL_CMP_CTX *ctx, const ASN1_OCTET_STRING *nonce); /* from cmp_status.c */ -char *OSSL_CMP_CTX_snprint_PKIStatus(OSSL_CMP_CTX *ctx, char *buf, +char *OSSL_CMP_CTX_snprint_PKIStatus(const OSSL_CMP_CTX *ctx, char *buf, size_t bufsize); +char *OSSL_CMP_snprint_PKIStatusInfo(const OSSL_CMP_PKISI *statusInfo, + char *buf, size_t bufsize); +OSSL_CMP_PKISI * +OSSL_CMP_STATUSINFO_new(int status, int fail_info, const char *text); /* from cmp_hdr.c */ -/* support application-level CMP debugging in cmp.c: */ ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_transactionID(const OSSL_CMP_PKIHEADER *hdr); ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr); /* from cmp_msg.c */ -/* support application-level CMP debugging in cmp.c: */ OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg); +OSSL_CMP_MSG *OSSL_d2i_CMP_MSG_bio(BIO *bio, OSSL_CMP_MSG **msg); +int OSSL_i2d_CMP_MSG_bio(BIO *bio, const OSSL_CMP_MSG *msg); /* from cmp_vfy.c */ int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg); int OSSL_CMP_validate_cert_path(OSSL_CMP_CTX *ctx, X509_STORE *trusted_store, X509 *cert); +/* from cmp_server.c */ +typedef struct ossl_cmp_srv_ctx_st OSSL_CMP_SRV_CTX; +OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req); +OSSL_CMP_MSG * OSSL_CMP_CTX_server_perform(OSSL_CMP_CTX *client_ctx, + const OSSL_CMP_MSG *req); +OSSL_CMP_SRV_CTX *OSSL_CMP_SRV_CTX_new(void); +void OSSL_CMP_SRV_CTX_free(OSSL_CMP_SRV_CTX *srv_ctx); +typedef OSSL_CMP_PKISI *(*OSSL_CMP_SRV_cert_request_cb_t) + (OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *req, int certReqId, + const OSSL_CRMF_MSG *crm, const X509_REQ *p10cr, + X509 **certOut, STACK_OF(X509) **chainOut, STACK_OF(X509) **caPubs); +typedef OSSL_CMP_PKISI *(*OSSL_CMP_SRV_rr_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req, + const X509_NAME *issuer, + const ASN1_INTEGER *serial); +typedef int (*OSSL_CMP_SRV_genm_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req, + const STACK_OF(OSSL_CMP_ITAV) *in, + STACK_OF(OSSL_CMP_ITAV) **out); +typedef void (*OSSL_CMP_SRV_error_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req, + const OSSL_CMP_PKISI *statusInfo, + const ASN1_INTEGER *errorCode, + const OSSL_CMP_PKIFREETEXT *errorDetails); +typedef int (*OSSL_CMP_SRV_certConf_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req, + int certReqId, + const ASN1_OCTET_STRING *certHash, + const OSSL_CMP_PKISI *si); +typedef int (*OSSL_CMP_SRV_pollReq_cb_t)(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *req, int certReqId, + OSSL_CMP_MSG **certReq, + int64_t *check_after); +int OSSL_CMP_SRV_CTX_init(OSSL_CMP_SRV_CTX *srv_ctx, void *custom_ctx, + OSSL_CMP_SRV_cert_request_cb_t process_cert_request, + OSSL_CMP_SRV_rr_cb_t process_rr, + OSSL_CMP_SRV_genm_cb_t process_genm, + OSSL_CMP_SRV_error_cb_t process_error, + OSSL_CMP_SRV_certConf_cb_t process_certConf, + OSSL_CMP_SRV_pollReq_cb_t process_pollReq); +OSSL_CMP_CTX *OSSL_CMP_SRV_CTX_get0_cmp_ctx(const OSSL_CMP_SRV_CTX *srv_ctx); +void *OSSL_CMP_SRV_CTX_get0_custom_ctx(const OSSL_CMP_SRV_CTX *srv_ctx); +int OSSL_CMP_SRV_CTX_set_send_unprotected_errors(OSSL_CMP_SRV_CTX *srv_ctx, + int val); +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); + # ifdef __cplusplus } # endif -# endif /* !defined OPENSSL_NO_CMP */ -#endif /* !defined OPENSSL_CMP_H */ +# endif /* !defined(OPENSSL_NO_CMP) */ +#endif /* !defined(OPENSSL_CMP_H) */ diff --git a/include/openssl/cmp_util.h b/include/openssl/cmp_util.h index 56fb49e188..3177893a34 100644 --- a/include/openssl/cmp_util.h +++ b/include/openssl/cmp_util.h @@ -47,8 +47,10 @@ int OSSL_CMP_print_to_bio(BIO *bio, const char *component, const char *file, /* use of the logging callback for outputting error queue */ void OSSL_CMP_print_errors_cb(OSSL_cmp_log_cb_t log_fn); +ASN1_OCTET_STRING *OSSL_CMP_X509_digest(const X509 *cert); + # ifdef __cplusplus } # endif -# endif /* !defined OPENSSL_NO_CMP */ -#endif /* !defined OPENSSL_CMP_UTIL_H */ +# endif /* !defined(OPENSSL_NO_CMP) */ +#endif /* !defined(OPENSSL_CMP_UTIL_H) */ diff --git a/include/openssl/cmperr.h b/include/openssl/cmperr.h index 51795a52ab..f868cc104f 100644 --- a/include/openssl/cmperr.h +++ b/include/openssl/cmperr.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2020 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,7 +19,7 @@ # ifndef OPENSSL_NO_CMP -# ifdef __cplusplus +# ifdef __cplusplus extern "C" # endif int ERR_load_CMP_strings(void); @@ -27,16 +27,18 @@ int ERR_load_CMP_strings(void); /* * CMP function codes. */ -# ifndef OPENSSL_NO_DEPRECATED_3_0 -# endif +# ifndef OPENSSL_NO_DEPRECATED_3_0 +# endif /* * CMP reason codes. */ # define CMP_R_ALGORITHM_NOT_SUPPORTED 139 # define CMP_R_BAD_REQUEST_ID 108 +# define CMP_R_CERTHASH_UNMATCHED 156 # define CMP_R_CERTID_NOT_FOUND 109 # define CMP_R_CERTIFICATE_NOT_FOUND 112 +# define CMP_R_CERTREQMSG_NOT_FOUND 157 # define CMP_R_CERTRESPONSE_NOT_FOUND 113 # define CMP_R_CERT_AND_KEY_DO_NOT_MATCH 114 # define CMP_R_ERROR_CALCULATING_PROTECTION 115 @@ -52,8 +54,11 @@ int ERR_load_CMP_strings(void); # define CMP_R_ERROR_CREATING_RP 125 # define CMP_R_ERROR_CREATING_RR 126 # define CMP_R_ERROR_PARSING_PKISTATUS 107 +# define CMP_R_ERROR_PROCESSING_MSG 158 # define CMP_R_ERROR_PROTECTING_MESSAGE 127 # define CMP_R_ERROR_SETTING_CERTHASH 128 +# define CMP_R_ERROR_TRANSFERRING_OUT 159 +# define CMP_R_ERROR_UNEXPECTED_CERTCONF 160 # define CMP_R_ERROR_VALIDATING_PROTECTION 140 # define CMP_R_FAILED_EXTRACTING_PUBKEY 141 # define CMP_R_FAILURE_OBTAINING_RANDOM 110 @@ -65,6 +70,7 @@ int ERR_load_CMP_strings(void); # define CMP_R_MISSING_PROTECTION 143 # define CMP_R_MISSING_SENDER_IDENTIFICATION 111 # define CMP_R_MISSING_TRUST_STORE 144 +# define CMP_R_MULTIPLE_REQUESTS_NOT_SUPPORTED 161 # define CMP_R_MULTIPLE_SAN_SOURCES 102 # define CMP_R_NO_STDIO 194 # define CMP_R_NO_SUITABLE_SENDER_CERT 145 diff --git a/include/openssl/crmf.h b/include/openssl/crmf.h index 09b57f6bce..b578906a67 100644 --- a/include/openssl/crmf.h +++ b/include/openssl/crmf.h @@ -106,7 +106,7 @@ int OSSL_CRMF_MSG_set1_regInfo_certReq(OSSL_CRMF_MSG *msg, int OSSL_CRMF_MSG_set_validity(OSSL_CRMF_MSG *crm, time_t from, time_t to); int OSSL_CRMF_MSG_set_certReqId(OSSL_CRMF_MSG *crm, int rid); -int OSSL_CRMF_MSG_get_certReqId(OSSL_CRMF_MSG *crm); +int OSSL_CRMF_MSG_get_certReqId(const OSSL_CRMF_MSG *crm); int OSSL_CRMF_MSG_set0_extensions(OSSL_CRMF_MSG *crm, X509_EXTENSIONS *exts); int OSSL_CRMF_MSG_push0_extension(OSSL_CRMF_MSG *crm, X509_EXTENSION *ext); @@ -120,8 +120,10 @@ int OSSL_CRMF_MSG_create_popo(OSSL_CRMF_MSG *crm, EVP_PKEY *pkey, int OSSL_CRMF_MSGS_verify_popo(const OSSL_CRMF_MSGS *reqs, int rid, int acceptRAVerified); OSSL_CRMF_CERTTEMPLATE *OSSL_CRMF_MSG_get0_tmpl(const OSSL_CRMF_MSG *crm); -ASN1_INTEGER *OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(OSSL_CRMF_CERTTEMPLATE *t); -X509_NAME *OSSL_CRMF_CERTTEMPLATE_get0_issuer(OSSL_CRMF_CERTTEMPLATE *tmpl); +ASN1_INTEGER +*OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(const OSSL_CRMF_CERTTEMPLATE *tmpl); +X509_NAME +*OSSL_CRMF_CERTTEMPLATE_get0_issuer(const OSSL_CRMF_CERTTEMPLATE *tmpl); X509_NAME *OSSL_CRMF_CERTID_get0_issuer(const OSSL_CRMF_CERTID *cid); ASN1_INTEGER *OSSL_CRMF_CERTID_get0_serialNumber(const OSSL_CRMF_CERTID *cid); int OSSL_CRMF_CERTTEMPLATE_fill(OSSL_CRMF_CERTTEMPLATE *tmpl, @@ -129,11 +131,12 @@ int OSSL_CRMF_CERTTEMPLATE_fill(OSSL_CRMF_CERTTEMPLATE *tmpl, const X509_NAME *subject, const X509_NAME *issuer, const ASN1_INTEGER *serial); -X509 *OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(OSSL_CRMF_ENCRYPTEDVALUE *ecert, - EVP_PKEY *pkey); +X509 +*OSSL_CRMF_ENCRYPTEDVALUE_get1_encCert(const OSSL_CRMF_ENCRYPTEDVALUE *ecert, + EVP_PKEY *pkey); # ifdef __cplusplus } # endif -# endif /* !defined OPENSSL_NO_CRMF */ -#endif /* !defined OPENSSL_CRMF_H */ +# endif /* !defined(OPENSSL_NO_CRMF) */ +#endif /* !defined(OPENSSL_CRMF_H) */ diff --git a/include/openssl/crmferr.h b/include/openssl/crmferr.h index 97a3028ce2..f7b5b906e2 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-2019 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2020 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,7 +19,7 @@ # ifndef OPENSSL_NO_CRMF -# ifdef __cplusplus +# ifdef __cplusplus extern "C" # endif int ERR_load_CRMF_strings(void); @@ -27,7 +27,7 @@ int ERR_load_CRMF_strings(void); /* * CRMF function codes. */ -# ifndef OPENSSL_NO_DEPRECATED_3_0 +# ifndef OPENSSL_NO_DEPRECATED_3_0 # define CRMF_F_CRMF_POPOSIGNINGKEY_INIT 0 # define CRMF_F_OSSL_CRMF_CERTID_GEN 0 # define CRMF_F_OSSL_CRMF_CERTTEMPLATE_FILL 0 @@ -47,7 +47,7 @@ int ERR_load_CRMF_strings(void); # define CRMF_F_OSSL_CRMF_MSG_SET_VALIDITY 0 # define CRMF_F_OSSL_CRMF_PBMP_NEW 0 # define CRMF_F_OSSL_CRMF_PBM_NEW 0 -# endif +# endif /* * CRMF reason codes. @@ -62,6 +62,10 @@ int ERR_load_CRMF_strings(void); # define CRMF_R_ITERATIONCOUNT_BELOW_100 108 # define CRMF_R_MALFORMED_IV 101 # define CRMF_R_NULL_ARGUMENT 109 +# define CRMF_R_POPO_INCONSISTENT_PUBLIC_KEY 117 +# define CRMF_R_POPO_MISSING_PUBLIC_KEY 118 +# define CRMF_R_POPO_MISSING_SUBJECT 119 +# define CRMF_R_POPO_RAVERIFIED_NOT_ACCEPTED 120 # define CRMF_R_SETTING_MAC_ALGOR_FAILURE 110 # define CRMF_R_SETTING_OWF_ALGOR_FAILURE 111 # define CRMF_R_UNSUPPORTED_ALGORITHM 112 @@ -69,7 +73,6 @@ int ERR_load_CRMF_strings(void); # define CRMF_R_UNSUPPORTED_CIPHER 114 # define CRMF_R_UNSUPPORTED_METHOD_FOR_CREATING_POPO 115 # define CRMF_R_UNSUPPORTED_POPO_METHOD 116 -# define CRMF_R_UNSUPPORTED_POPO_NOT_ACCEPTED 117 # endif #endif diff --git a/test/build.info b/test/build.info index 1573087c28..fcf2ac57ac 100644 --- a/test/build.info +++ b/test/build.info @@ -438,7 +438,8 @@ IF[{- !$disabled{tests} -}] IF[{- !$disabled{cmp} -}] PROGRAMS{noinst}=cmp_asn_test cmp_ctx_test cmp_status_test cmp_hdr_test \ - cmp_protect_test cmp_msg_test cmp_vfy_test + cmp_protect_test cmp_msg_test cmp_vfy_test \ + cmp_server_test ENDIF SOURCE[cmp_asn_test]=cmp_asn_test.c cmp_testlib.c @@ -465,10 +466,14 @@ IF[{- !$disabled{tests} -}] INCLUDE[cmp_msg_test]=.. ../include ../apps/include DEPEND[cmp_msg_test]=../libcrypto.a libtestutil.a - SOURCE[cmp_vfy_test]=cmp_status_test.c cmp_testlib.c + SOURCE[cmp_vfy_test]=cmp_vfy_test.c cmp_testlib.c INCLUDE[cmp_vfy_test]=.. ../include ../apps/include DEPEND[cmp_vfy_test]=../libcrypto.a libtestutil.a + SOURCE[cmp_server_test]=cmp_server_test.c cmp_testlib.c + INCLUDE[cmp_server_test]=.. ../include ../apps/include + DEPEND[cmp_server_test]=../libcrypto.a libtestutil.a + # Internal test programs. These are essentially a collection of internal # test routines. Some of them need to reach internal symbols that aren't # available through the shared library (at least on Linux, Solaris, Windows diff --git a/test/cmp_ctx_test.c b/test/cmp_ctx_test.c index 26c65778b9..903e204622 100644 --- a/test/cmp_ctx_test.c +++ b/test/cmp_ctx_test.c @@ -118,6 +118,7 @@ static int msg_total_size_log_cb(const char *func, const char *file, int line, OSSL_CMP_severity level, const char *msg) { msg_total_size += strlen(msg); + TEST_note("total=%d len=%ld msg='%s'\n", msg_total_size, strlen(msg), msg); return 1; } diff --git a/test/cmp_hdr_test.c b/test/cmp_hdr_test.c index c12b72f29e..25d0dad9f6 100644 --- a/test/cmp_hdr_test.c +++ b/test/cmp_hdr_test.c @@ -350,9 +350,9 @@ static int execute_HDR_set_and_check_implicitConfirm_test(CMP_HDR_TEST_FIXTURE * fixture) { - return TEST_false(ossl_cmp_hdr_check_implicitConfirm(fixture->hdr)) + return TEST_false(ossl_cmp_hdr_has_implicitConfirm(fixture->hdr)) && TEST_true(ossl_cmp_hdr_set_implicitConfirm(fixture->hdr)) - && TEST_true(ossl_cmp_hdr_check_implicitConfirm(fixture->hdr)); + && TEST_true(ossl_cmp_hdr_has_implicitConfirm(fixture->hdr)); } static int test_HDR_set_and_check_implicit_confirm(void) diff --git a/test/cmp_msg_test.c b/test/cmp_msg_test.c index 8f95865869..3919480610 100644 --- a/test/cmp_msg_test.c +++ b/test/cmp_msg_test.c @@ -91,8 +91,7 @@ static int execute_errormsg_create_test(CMP_MSG_TEST_FIXTURE *fixture) { EXECUTE_MSG_CREATION_TEST(ossl_cmp_error_new(fixture->cmp_ctx, fixture->si, fixture->err_code, - NULL /* fixture->free_text */, - 0)); + "details", 0)); } static int execute_rr_create_test(CMP_MSG_TEST_FIXTURE *fixture) @@ -317,7 +316,7 @@ static int test_cmp_create_certconf_fail_info_max(void) static int test_cmp_create_error_msg(void) { SETUP_TEST_FIXTURE(CMP_MSG_TEST_FIXTURE, set_up); - fixture->si = ossl_cmp_statusinfo_new(OSSL_CMP_PKISTATUS_rejection, + fixture->si = OSSL_CMP_STATUSINFO_new(OSSL_CMP_PKISTATUS_rejection, OSSL_CMP_PKIFAILUREINFO_systemFailure, NULL); fixture->err_code = -1; @@ -419,7 +418,7 @@ static int test_cmp_create_certrep(void) static int execute_rp_create(CMP_MSG_TEST_FIXTURE *fixture) { - OSSL_CMP_PKISI *si = ossl_cmp_statusinfo_new(33, 44, "a text"); + OSSL_CMP_PKISI *si = OSSL_CMP_STATUSINFO_new(33, 44, "a text"); X509_NAME *issuer = X509_NAME_new(); ASN1_INTEGER *serial = ASN1_INTEGER_new(); OSSL_CRMF_CERTID *cid = NULL; @@ -439,8 +438,7 @@ static int execute_rp_create(CMP_MSG_TEST_FIXTURE *fixture) if (!TEST_ptr(ossl_cmp_revrepcontent_get_CertId(rpmsg->body->value.rp, 0))) goto err; - if (!TEST_ptr(ossl_cmp_revrepcontent_get_pkistatusinfo(rpmsg->body-> - value.rp, 0))) + if (!TEST_ptr(ossl_cmp_revrepcontent_get_pkisi(rpmsg->body->value.rp, 0))) goto err; res = 1; diff --git a/test/cmp_server_test.c b/test/cmp_server_test.c new file mode 100644 index 0000000000..13159299e9 --- /dev/null +++ b/test/cmp_server_test.c @@ -0,0 +1,160 @@ +/* + * Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved. + * Copyright Nokia 2007-2020 + * Copyright Siemens AG 2015-2020 + * + * 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 + */ + +#include "cmp_testlib.h" + +typedef struct test_fixture { + const char *test_case_name; + int expected; + OSSL_CMP_SRV_CTX *srv_ctx; + OSSL_CMP_MSG *req; +} CMP_SRV_TEST_FIXTURE; + +static OSSL_CMP_MSG *request = NULL; + +static void tear_down(CMP_SRV_TEST_FIXTURE *fixture) +{ + OSSL_CMP_SRV_CTX_free(fixture->srv_ctx); + OPENSSL_free(fixture); +} + +static CMP_SRV_TEST_FIXTURE *set_up(const char *const test_case_name) +{ + CMP_SRV_TEST_FIXTURE *fixture; + + if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture)))) + return NULL; + fixture->test_case_name = test_case_name; + if (!TEST_ptr(fixture->srv_ctx = OSSL_CMP_SRV_CTX_new())) + goto err; + return fixture; + + err: + tear_down(fixture); + return NULL; +} + +static int dummy_errorCode = CMP_R_MULTIPLE_SAN_SOURCES; /* any reason code */ + +static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx, + const OSSL_CMP_MSG *cert_req, + int certReqId, + const OSSL_CRMF_MSG *crm, + const X509_REQ *p10cr, + X509 **certOut, + STACK_OF(X509) **chainOut, + STACK_OF(X509) **caPubs) +{ + CMPerr(0, dummy_errorCode); + return NULL; +} + +static int execute_test_handle_request(CMP_SRV_TEST_FIXTURE *fixture) +{ + OSSL_CMP_SRV_CTX *ctx = fixture->srv_ctx; + OSSL_CMP_CTX *client_ctx; + OSSL_CMP_CTX *cmp_ctx; + char *dummy_custom_ctx = "@test_dummy", *custom_ctx; + OSSL_CMP_MSG *rsp = NULL; + OSSL_CMP_ERRORMSGCONTENT *errorContent; + int res = 0; + + if (!TEST_ptr(client_ctx = OSSL_CMP_CTX_new()) + || !TEST_true(OSSL_CMP_CTX_set_transfer_cb_arg(client_ctx, ctx))) + goto end; + + if (!TEST_true(OSSL_CMP_SRV_CTX_init(ctx, dummy_custom_ctx, + process_cert_request, NULL, NULL, + NULL, NULL, NULL)) + || !TEST_ptr(custom_ctx = OSSL_CMP_SRV_CTX_get0_custom_ctx(ctx)) + || !TEST_int_eq(strcmp(custom_ctx, dummy_custom_ctx), 0)) + goto end; + + if (!TEST_true(OSSL_CMP_SRV_CTX_set_send_unprotected_errors(ctx, 0)) + || !TEST_true(OSSL_CMP_SRV_CTX_set_accept_unprotected(ctx, 0)) + || !TEST_true(OSSL_CMP_SRV_CTX_set_accept_raverified(ctx, 1)) + || !TEST_true(OSSL_CMP_SRV_CTX_set_grant_implicit_confirm(ctx, 1))) + goto end; + + if (!TEST_ptr(cmp_ctx = OSSL_CMP_SRV_CTX_get0_cmp_ctx(ctx)) + || !OSSL_CMP_CTX_set1_referenceValue(cmp_ctx, + (unsigned char *)"server", 6) + || !OSSL_CMP_CTX_set1_secretValue(cmp_ctx, + (unsigned char *)"1234", 4)) + goto end; + + if (!TEST_ptr(rsp = OSSL_CMP_CTX_server_perform(client_ctx, fixture->req)) + || !TEST_int_eq(ossl_cmp_msg_get_bodytype(rsp), + OSSL_CMP_PKIBODY_ERROR) + || !TEST_ptr(errorContent = rsp->body->value.error) + || !TEST_int_eq(ASN1_INTEGER_get(errorContent->errorCode), + dummy_errorCode)) + goto end; + + res = 1; + + end: + OSSL_CMP_MSG_free(rsp); + OSSL_CMP_CTX_free(client_ctx); + return res; +} + +static int test_handle_request(void) +{ + SETUP_TEST_FIXTURE(CMP_SRV_TEST_FIXTURE, set_up); + fixture->req = request; + fixture->expected = 1; + EXECUTE_TEST(execute_test_handle_request, tear_down); + return result; +} + +void cleanup_tests(void) +{ + OSSL_CMP_MSG_free(request); + return; +} + +int setup_tests(void) +{ + const char *request_f; + + if (!test_skip_common_options()) { + TEST_error("Error parsing test options\n"); + return 0; + } + + if (!TEST_ptr(request_f = test_get_argument(0))) { + TEST_error("usage: cmp_server_test CR_protected_PBM_1234.der\n"); + return 0; + } + + if (!TEST_ptr(request = load_pkimsg(request_f))) { + cleanup_tests(); + return 0; + } + + /* + * this (indirectly) calls + * OSSL_CMP_SRV_CTX_new(), + * OSSL_CMP_SRV_CTX_free(), + * OSSL_CMP_CTX_server_perform(), + * OSSL_CMP_SRV_process_request(), + * OSSL_CMP_SRV_CTX_init(), + * OSSL_CMP_SRV_CTX_get0_cmp_ctx(), + * OSSL_CMP_SRV_CTX_get0_custom_ctx(), + * OSSL_CMP_SRV_CTX_set_send_unprotected_errors(), + * OSSL_CMP_SRV_CTX_set_accept_unprotected(), + * OSSL_CMP_SRV_CTX_set_accept_raverified(), and + * OSSL_CMP_SRV_CTX_set_grant_implicit_confirm() + */ + ADD_TEST(test_handle_request); + return 1; +} diff --git a/test/cmp_status_test.c b/test/cmp_status_test.c index 7311c2e444..15cd6a5fd0 100644 --- a/test/cmp_status_test.c +++ b/test/cmp_status_test.c @@ -45,18 +45,18 @@ static int execute_PKISI_test(CMP_STATUS_TEST_FIXTURE *fixture) ASN1_UTF8STRING *statusString = NULL; int res = 0, i; - if (!TEST_ptr(si = ossl_cmp_statusinfo_new(fixture->pkistatus, + if (!TEST_ptr(si = OSSL_CMP_STATUSINFO_new(fixture->pkistatus, fixture->pkifailure, fixture->text))) goto end; - status = ossl_cmp_pkisi_get_pkistatus(si); + status = ossl_cmp_pkisi_get_status(si); if (!TEST_int_eq(fixture->pkistatus, status) || !TEST_str_eq(fixture->str, ossl_cmp_PKIStatus_to_string(status))) goto end; if (!TEST_ptr(statusString = - sk_ASN1_UTF8STRING_value(ossl_cmp_pkisi_get0_statusstring(si), + sk_ASN1_UTF8STRING_value(ossl_cmp_pkisi_get0_statusString(si), 0)) || !TEST_str_eq(fixture->text, (char *)statusString->data)) goto end; @@ -66,7 +66,7 @@ static int execute_PKISI_test(CMP_STATUS_TEST_FIXTURE *fixture) goto end; for (i = 0; i <= OSSL_CMP_PKIFAILUREINFO_MAX; i++) if (!TEST_int_eq((fixture->pkifailure >> i) & 1, - ossl_cmp_pkisi_pkifailureinfo_check(si, i))) + ossl_cmp_pkisi_check_pkifailureinfo(si, i))) goto end; res = 1; @@ -99,12 +99,12 @@ int setup_tests(void) { /*- * this tests all of: - * ossl_cmp_statusinfo_new() - * ossl_cmp_pkisi_get_pkistatus() + * OSSL_CMP_STATUSINFO_new() + * ossl_cmp_pkisi_get_status() * ossl_cmp_PKIStatus_to_string() - * ossl_cmp_pkisi_get0_statusstring() + * ossl_cmp_pkisi_get0_statusString() * ossl_cmp_pkisi_get_pkifailureinfo() - * ossl_cmp_pkisi_pkifailureinfo_check() + * ossl_cmp_pkisi_check_pkifailureinfo() */ ADD_TEST(test_PKISI); return 1; diff --git a/test/cmp_vfy_test.c b/test/cmp_vfy_test.c index 41ddad86ba..f52efa9855 100644 --- a/test/cmp_vfy_test.c +++ b/test/cmp_vfy_test.c @@ -69,7 +69,7 @@ static CMP_VFY_TEST_FIXTURE *set_up(const char *const test_case_name) return NULL; } X509_VERIFY_PARAM_set_time(X509_STORE_get0_param(ts), test_time_valid); - X509_STORE_set_verify_cb(ts, OSSL_CMP_print_cert_verify_cb); + X509_STORE_set_verify_cb(ts, X509_STORE_CTX_print_verify_cb); return fixture; } @@ -437,8 +437,7 @@ static void setup_check_received(CMP_VFY_TEST_FIXTURE **fixture, int expected, nonce_data, nonce_len))) { tear_down((*fixture)); (*fixture) = NULL; - } - else if (trid_data != NULL) { + } else if (trid_data != NULL) { ASN1_OCTET_STRING *trid = ASN1_OCTET_STRING_new(); if (trid == NULL || !ASN1_OCTET_STRING_set(trid, trid_data, @@ -549,6 +548,11 @@ int setup_tests(void) ts.tm_year += 10; /* February 18th 2028 */ test_time_after_expiration = mktime(&ts); + if (!test_skip_common_options()) { + TEST_error("Error parsing test options\n"); + return 0; + } + RAND_bytes(rand_data, OSSL_CMP_TRANSACTIONID_LENGTH); if (!TEST_ptr(server_f = test_get_argument(0)) || !TEST_ptr(client_f = test_get_argument(1)) diff --git a/test/recipes/65-test_cmp_server.t b/test/recipes/65-test_cmp_server.t new file mode 100644 index 0000000000..87dbdb10b2 --- /dev/null +++ b/test/recipes/65-test_cmp_server.t @@ -0,0 +1,26 @@ +#! /usr/bin/env perl +# Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved. +# Copyright Nokia 2007-2020 +# Copyright Siemens AG 2015-2020 +# +# 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 + +use strict; +use OpenSSL::Test qw/:DEFAULT data_file/; +use OpenSSL::Test::Utils; + +setup("test_cmp_server"); + +plan skip_all => "This test is not supported in a no-cmp build" + if disabled("cmp"); + +plan skip_all => "This test is not supported in a no-ec build" + if disabled("ec"); + +plan tests => 1; + +ok(run(test(["cmp_server_test", + data_file("CR_protected_PBM_1234.der")]))); diff --git a/test/recipes/65-test_cmp_server_data/CR_protected_PBM_1234.der b/test/recipes/65-test_cmp_server_data/CR_protected_PBM_1234.der new file mode 100644 index 0000000000..fc1c0aff9b Binary files /dev/null and b/test/recipes/65-test_cmp_server_data/CR_protected_PBM_1234.der differ diff --git a/util/libcrypto.num b/util/libcrypto.num index d7a94f8adf..76c3832d5f 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4956,3 +4956,27 @@ OSSL_SELF_TEST_onbegin ? 3_0_0 EXIST::FUNCTION: OSSL_SELF_TEST_oncorrupt_byte ? 3_0_0 EXIST::FUNCTION: OSSL_SELF_TEST_onend ? 3_0_0 EXIST::FUNCTION: OSSL_PROVIDER_set_default_search_path ? 3_0_0 EXIST::FUNCTION: +OSSL_CMP_MSG_dup ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_ITAV_dup ? 3_0_0 EXIST::FUNCTION:CMP +d2i_OSSL_CMP_PKISI ? 3_0_0 EXIST::FUNCTION:CMP +i2d_OSSL_CMP_PKISI ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_PKISI_free ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_PKISI_new ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_PKISI_it ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_PKISI_dup ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_snprint_PKIStatusInfo ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_STATUSINFO_new ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_d2i_CMP_MSG_bio ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_i2d_CMP_MSG_bio ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_SRV_process_request ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_CTX_server_perform ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_SRV_CTX_new ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_SRV_CTX_free ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_SRV_CTX_init ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_SRV_CTX_get0_cmp_ctx ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_SRV_CTX_get0_custom_ctx ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_SRV_CTX_set_send_unprotected_errors ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_SRV_CTX_set_accept_unprotected ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_SRV_CTX_set_accept_raverified ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_SRV_CTX_set_grant_implicit_confirm ? 3_0_0 EXIST::FUNCTION:CMP +OSSL_CMP_X509_digest ? 3_0_0 EXIST::FUNCTION:CMP diff --git a/util/other.syms b/util/other.syms index 4996dd874b..1d2a2689ef 100644 --- a/util/other.syms +++ b/util/other.syms @@ -367,6 +367,12 @@ OSSL_CMP_severity datatype OSSL_cmp_certConf_cb_t datatype OSSL_cmp_log_cb_t datatype OSSL_cmp_transfer_cb_t datatype +OSSL_CMP_SRV_cert_request_cb_t datatype +OSSL_CMP_SRV_rr_cb_t datatype +OSSL_CMP_SRV_certConf_cb_t datatype +OSSL_CMP_SRV_genm_cb_t datatype +OSSL_CMP_SRV_error_cb_t datatype +OSSL_CMP_SRV_pollReq_cb_t datatype OSSL_PARAM_TYPE define OSSL_PARAM_octet_ptr define OSSL_PARAM_octet_string define