Browse Source

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 <matt@openssl.org>
Reviewed-by: David von Oheimb <david.von.oheimb@siemens.com>
(Merged from https://github.com/openssl/openssl/pull/11142)
master
Dr. David von Oheimb 2 years ago
parent
commit
62dcd2aa17
41 changed files with 2102 additions and 351 deletions
  1. +3
    -0
      apps/build.info
  2. +406
    -0
      apps/cmp_mock_srv.c
  3. +34
    -0
      apps/cmp_mock_srv.h
  4. +2
    -1
      crypto/cmp/build.info
  5. +12
    -1
      crypto/cmp/cmp_err.c
  6. +5
    -23
      crypto/cmp/cmp_hdr.c
  7. +25
    -39
      crypto/cmp/cmp_local.h
  8. +64
    -67
      crypto/cmp/cmp_msg.c
  9. +615
    -0
      crypto/cmp/cmp_server.c
  10. +55
    -43
      crypto/cmp/cmp_status.c
  11. +56
    -0
      crypto/cmp/cmp_util.c
  12. +9
    -3
      crypto/crmf/crmf_err.c
  13. +41
    -27
      crypto/crmf/crmf_lib.c
  14. +10
    -1
      crypto/err/openssl.txt
  15. +3
    -3
      doc/internal/man3/ossl_cmp_hdr_init.pod
  16. +85
    -0
      doc/internal/man3/ossl_cmp_mock_srv_new.pod
  17. +19
    -34
      doc/internal/man3/ossl_cmp_pkisi_get_status.pod
  18. +35
    -15
      doc/man3/OSSL_CMP_CTX_new.pod
  19. +0
    -46
      doc/man3/OSSL_CMP_CTX_snprint_PKIStatus.pod
  20. +15
    -2
      doc/man3/OSSL_CMP_MSG_get0_header.pod
  21. +159
    -0
      doc/man3/OSSL_CMP_SRV_CTX_new.pod
  22. +66
    -0
      doc/man3/OSSL_CMP_STATUSINFO_new.pod
  23. +36
    -0
      doc/man3/OSSL_CMP_X509_digest.pod
  24. +4
    -0
      doc/man3/X509_dup.pod
  25. +2
    -0
      doc/man3/d2i_X509.pod
  26. +64
    -7
      include/openssl/cmp.h
  27. +4
    -2
      include/openssl/cmp_util.h
  28. +10
    -4
      include/openssl/cmperr.h
  29. +10
    -7
      include/openssl/crmf.h
  30. +8
    -5
      include/openssl/crmferr.h
  31. +7
    -2
      test/build.info
  32. +1
    -0
      test/cmp_ctx_test.c
  33. +2
    -2
      test/cmp_hdr_test.c
  34. +4
    -6
      test/cmp_msg_test.c
  35. +160
    -0
      test/cmp_server_test.c
  36. +8
    -8
      test/cmp_status_test.c
  37. +7
    -3
      test/cmp_vfy_test.c
  38. +26
    -0
      test/recipes/65-test_cmp_server.t
  39. BIN
      test/recipes/65-test_cmp_server_data/CR_protected_PBM_1234.der
  40. +24
    -0
      util/libcrypto.num
  41. +6
    -0
      util/other.syms

+ 3
- 0
apps/build.info View File

@ -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


+ 406
- 0
apps/cmp_mock_srv.c View File

@ -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 <openssl/cmp.h>
#include <openssl/err.h>
#include <openssl/cmperr.h>
/* 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: "<invalid>");
}
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);
}

+ 34
- 0
apps/cmp_mock_srv.h View File

@ -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 <openssl/opensslconf.h>
# ifndef OPENSSL_NO_CMP
# include <openssl/cmp.h>
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) */

+ 2
- 1
crypto/cmp/build.info View File

@ -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

+ 12
- 1
crypto/cmp/cmp_err.c View File

@ -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"},


+ 5
- 23
crypto/cmp/cmp_hdr.c View File

@ -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.


+ 25
- 39
crypto/cmp/cmp_local.h View File

@ -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) */

+ 64
- 67
crypto/cmp/cmp_msg.c View File

@ -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);
}

+ 615
- 0
crypto/cmp/cmp_server.c View File

@ -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 <openssl/asn1t.h>
#include "cmp_local.h"
/* explicit #includes not strictly needed since implied by the above: */
#include <openssl/cmp.h>
#include <openssl/err.h>
/* 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 =