Browse Source

Chunk 9 of CMP contribution to OpenSSL: CMP client and related tests

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/11300)
master
Dr. David von Oheimb 2 years ago
parent
commit
7e765f46a6
37 changed files with 1860 additions and 126 deletions
  1. +6
    -5
      apps/cmp_mock_srv.c
  2. +1
    -1
      crypto/cmp/build.info
  3. +881
    -0
      crypto/cmp/cmp_client.c
  4. +21
    -21
      crypto/cmp/cmp_ctx.c
  5. +33
    -4
      crypto/cmp/cmp_err.c
  6. +11
    -5
      crypto/cmp/cmp_local.h
  7. +2
    -1
      crypto/cmp/cmp_msg.c
  8. +11
    -7
      crypto/cmp/cmp_server.c
  9. +1
    -1
      crypto/cmp/cmp_status.c
  10. +1
    -1
      crypto/cmp/cmp_util.c
  11. +20
    -19
      crypto/cmp/cmp_vfy.c
  12. +20
    -2
      crypto/err/openssl.txt
  13. +86
    -0
      doc/internal/man3/ossl_cmp_msg_check_received.pod
  14. +1
    -2
      doc/internal/man3/ossl_cmp_msg_create.pod
  15. +19
    -19
      doc/man3/OSSL_CMP_CTX_new.pod
  16. +3
    -0
      doc/man3/OSSL_CMP_SRV_CTX_new.pod
  17. +172
    -0
      doc/man3/OSSL_CMP_exec_IR_ses.pod
  18. +4
    -4
      doc/man3/OSSL_CMP_log_open.pod
  19. +26
    -11
      include/openssl/cmp.h
  20. +2
    -2
      include/openssl/cmp_util.h
  21. +20
    -2
      include/openssl/cmperr.h
  22. +5
    -1
      test/build.info
  23. +393
    -0
      test/cmp_client_test.c
  24. +3
    -3
      test/cmp_ctx_test.c
  25. +2
    -2
      test/cmp_msg_test.c
  26. +6
    -0
      test/cmp_testlib.c
  27. +2
    -0
      test/cmp_testlib.h
  28. +0
    -6
      test/cmp_vfy_test.c
  29. +27
    -0
      test/recipes/65-test_cmp_client.t
  30. +13
    -0
      test/recipes/65-test_cmp_client_data/client.crt
  31. BIN
      test/recipes/65-test_cmp_client_data/client.csr
  32. +7
    -0
      test/recipes/65-test_cmp_client_data/client.key
  33. +17
    -0
      test/recipes/65-test_cmp_client_data/server.crt
  34. +27
    -0
      test/recipes/65-test_cmp_client_data/server.key
  35. +9
    -1
      util/libcrypto.num
  36. +0
    -3
      util/missingcrypto.txt
  37. +8
    -3
      util/other.syms

+ 6
- 5
apps/cmp_mock_srv.c View File

@ -187,7 +187,7 @@ static OSSL_CMP_PKISI *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
return NULL;
}
if (ctx->sendError) {
CMPerr(0, CMP_R_ERROR_PROCESSING_MSG);
CMPerr(0, CMP_R_ERROR_PROCESSING_MESSAGE);
return NULL;
}
@ -238,7 +238,7 @@ static OSSL_CMP_PKISI *process_rr(OSSL_CMP_SRV_CTX *srv_ctx,
return NULL;
}
if (ctx->sendError || ctx->certOut == NULL) {
CMPerr(0, CMP_R_ERROR_PROCESSING_MSG);
CMPerr(0, CMP_R_ERROR_PROCESSING_MESSAGE);
return NULL;
}
@ -264,7 +264,7 @@ static int process_genm(OSSL_CMP_SRV_CTX *srv_ctx,
return 0;
}
if (ctx->sendError) {
CMPerr(0, CMP_R_ERROR_PROCESSING_MSG);
CMPerr(0, CMP_R_ERROR_PROCESSING_MESSAGE);
return 0;
}
@ -306,6 +306,7 @@ static void process_error(OSSL_CMP_SRV_CTX *srv_ctx, const OSSL_CMP_MSG *error,
if (sk_ASN1_UTF8STRING_num(errorDetails) <= 0) {
BIO_printf(bio_err, "errorDetails absent\n");
} else {
/* TODO could use sk_ASN1_UTF8STRING2text() if exported */
BIO_printf(bio_err, "errorDetails: ");
for (i = 0; i < sk_ASN1_UTF8STRING_num(errorDetails); i++) {
if (i > 0)
@ -332,7 +333,7 @@ static int process_certConf(OSSL_CMP_SRV_CTX *srv_ctx,
return 0;
}
if (ctx->sendError || ctx->certOut == NULL) {
CMPerr(0, CMP_R_ERROR_PROCESSING_MSG);
CMPerr(0, CMP_R_ERROR_PROCESSING_MESSAGE);
return 0;
}
@ -366,7 +367,7 @@ static int process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx,
}
if (ctx->sendError || ctx->certReq == NULL) {
*certReq = NULL;
CMPerr(0, CMP_R_ERROR_PROCESSING_MSG);
CMPerr(0, CMP_R_ERROR_PROCESSING_MESSAGE);
return 0;
}


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

@ -1,4 +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_server.c
cmp_server.c cmp_client.c

+ 881
- 0
crypto/cmp/cmp_client.c View File

@ -0,0 +1,881 @@
/*
* 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
*/
#include "cmp_local.h"
#include "internal/cryptlib.h"
/* explicit #includes not strictly needed since implied by the above: */
#include <openssl/bio.h>
#include <openssl/cmp.h>
#include <openssl/err.h>
#include <openssl/evp.h>
#include <openssl/x509v3.h>
#include "openssl/cmp_util.h"
#define IS_CREP(t) ((t) == OSSL_CMP_PKIBODY_IP || (t) == OSSL_CMP_PKIBODY_CP \
|| (t) == OSSL_CMP_PKIBODY_KUP)
/*-
* Evaluate whether there's an exception (violating the standard) configured for
* handling negative responses without protection or with invalid protection.
* Returns 1 on acceptance, 0 on rejection, or -1 on (internal) error.
*/
static int unprotected_exception(const OSSL_CMP_CTX *ctx,
const OSSL_CMP_MSG *rep,
int invalid_protection,
int expected_type /* ignored here */)
{
int rcvd_type = ossl_cmp_msg_get_bodytype(rep /* may be NULL */);
const char *msg_type = NULL;
if (!ossl_assert(ctx != NULL && rep != NULL))
return -1;
if (!ctx->unprotectedErrors)
return 0;
switch (rcvd_type) {
case OSSL_CMP_PKIBODY_ERROR:
msg_type = "error response";
break;
case OSSL_CMP_PKIBODY_RP:
{
OSSL_CMP_PKISI *si =
ossl_cmp_revrepcontent_get_pkisi(rep->body->value.rp,
OSSL_CMP_REVREQSID);
if (si == NULL)
return -1;
if (ossl_cmp_pkisi_get_status(si) == OSSL_CMP_PKISTATUS_rejection)
msg_type = "revocation response message with rejection status";
break;
}
case OSSL_CMP_PKIBODY_PKICONF:
msg_type = "PKI Confirmation message";
break;
default:
if (IS_CREP(rcvd_type)) {
OSSL_CMP_CERTREPMESSAGE *crepmsg = rep->body->value.ip;
OSSL_CMP_CERTRESPONSE *crep =
ossl_cmp_certrepmessage_get0_certresponse(crepmsg,
-1 /* any rid */);
if (sk_OSSL_CMP_CERTRESPONSE_num(crepmsg->response) > 1)
return -1;
/* TODO: handle potentially multiple CertResponses in CertRepMsg */
if (crep == NULL)
return -1;
if (ossl_cmp_pkisi_get_status(crep->status)
== OSSL_CMP_PKISTATUS_rejection)
msg_type = "CertRepMessage with rejection status";
}
}
if (msg_type == NULL)
return 0;
ossl_cmp_log2(WARN, ctx, "ignoring %s protection of %s",
invalid_protection ? "invalid" : "missing", msg_type);
return 1;
}
/* Save error info from PKIStatusInfo field of a certresponse into ctx */
static int save_statusInfo(OSSL_CMP_CTX *ctx, OSSL_CMP_PKISI *si)
{
int i;
OSSL_CMP_PKIFREETEXT *ss;
if (!ossl_assert(ctx != NULL && si != NULL))
return 0;
if ((ctx->status = ossl_cmp_pkisi_get_status(si)) < 0)
return 0;
ctx->failInfoCode = 0;
if (si->failInfo != NULL) {
for (i = 0; i <= OSSL_CMP_PKIFAILUREINFO_MAX; i++) {
if (ASN1_BIT_STRING_get_bit(si->failInfo, i))
ctx->failInfoCode |= (1 << i);
}
}
if (!ossl_cmp_ctx_set0_statusString(ctx, sk_ASN1_UTF8STRING_new_null())
|| (ctx->statusString == NULL))
return 0;
ss = si->statusString; /* may be NULL */
for (i = 0; i < sk_ASN1_UTF8STRING_num(ss); i++) {
ASN1_UTF8STRING *str = sk_ASN1_UTF8STRING_value(ss, i);
if (!sk_ASN1_UTF8STRING_push(ctx->statusString, ASN1_STRING_dup(str)))
return 0;
}
return 1;
}
/*-
* Perform the generic aspects of sending a request and receiving a response.
* Returns 1 on success and provides the received PKIMESSAGE in *rep.
* Returns 0 on error.
* Regardless of success, caller is responsible for freeing *rep (unless NULL).
*/
static int send_receive_check(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *req,
OSSL_CMP_MSG **rep, int expected_type)
{
const char *req_type_str =
ossl_cmp_bodytype_to_string(ossl_cmp_msg_get_bodytype(req));
const char *expected_type_str = ossl_cmp_bodytype_to_string(expected_type);
int msg_timeout;
int bt;
time_t now = time(NULL);
int time_left;
OSSL_CMP_transfer_cb_t transfer_cb = ctx->transfer_cb;
if (transfer_cb == NULL)
transfer_cb = NULL; /* TODO: will be OSSL_CMP_MSG_http_perform of chunk 10 */
*rep = NULL;
msg_timeout = ctx->msg_timeout; /* backup original value */
if ((IS_CREP(expected_type) || expected_type == OSSL_CMP_PKIBODY_POLLREP)
&& ctx->total_timeout > 0 /* timeout is not infinite */) {
if (now >= ctx->end_time) {
CMPerr(0, CMP_R_TOTAL_TIMEOUT);
return 0;
}
if (!ossl_assert(ctx->end_time - time(NULL) < INT_MAX)) {
/* cannot really happen due to the assignment in do_certreq_seq() */
CMPerr(0, CMP_R_INVALID_ARGS);
return 0;
}
time_left = (int)(ctx->end_time - now);
if (ctx->msg_timeout == 0 || time_left < ctx->msg_timeout)
ctx->msg_timeout = time_left;
}
/* should print error queue since transfer_cb may call ERR_clear_error() */
OSSL_CMP_CTX_print_errors(ctx);
ossl_cmp_log1(INFO, ctx, "sending %s", req_type_str);
*rep = (*transfer_cb)(ctx, req);
ctx->msg_timeout = msg_timeout; /* restore original value */
if (*rep == NULL) {
CMPerr(0, CMP_R_TRANSFER_ERROR); /* or receiving response */
ERR_add_error_data(1, req_type_str);
ERR_add_error_data(2, ", expected response: ", expected_type_str);
return 0;
}
bt = ossl_cmp_msg_get_bodytype(*rep);
/*
* The body type in the 'bt' variable is not yet verified.
* Still we use this preliminary value already for a progress report because
* the following msg verification may also produce log entries and may fail.
*/
ossl_cmp_log1(INFO, ctx, "received %s", ossl_cmp_bodytype_to_string(bt));
if ((bt = ossl_cmp_msg_check_received(ctx, *rep, unprotected_exception,
expected_type)) < 0)
return 0;
if (bt == expected_type
/* as an answer to polling, there could be IP/CP/KUP: */
|| (IS_CREP(bt) && expected_type == OSSL_CMP_PKIBODY_POLLREP))
return 1;
/* received message type is not one of the expected ones (e.g., error) */
CMPerr(0, bt == OSSL_CMP_PKIBODY_ERROR ? CMP_R_RECEIVED_ERROR :
CMP_R_UNEXPECTED_PKIBODY); /* in next line for mkerr.pl */
if (bt != OSSL_CMP_PKIBODY_ERROR) {
ERR_add_error_data(3, "message type is '",
ossl_cmp_bodytype_to_string(bt), "'");
} else {
OSSL_CMP_ERRORMSGCONTENT *emc = (*rep)->body->value.error;
OSSL_CMP_PKISI *si = emc->pKIStatusInfo;
char buf[OSSL_CMP_PKISI_BUFLEN];
if (save_statusInfo(ctx, si)
&& OSSL_CMP_CTX_snprint_PKIStatus(ctx, buf, sizeof(buf)) != NULL)
ERR_add_error_data(1, buf);
if (emc->errorCode != NULL
&& BIO_snprintf(buf, sizeof(buf), "; errorCode: %ld",
ASN1_INTEGER_get(emc->errorCode)) > 0)
ERR_add_error_data(1, buf);
if (emc->errorDetails != NULL) {
char *text = sk_ASN1_UTF8STRING2text(emc->errorDetails, ", ",
OSSL_CMP_PKISI_BUFLEN - 1);
if (text != NULL)
ERR_add_error_data(2, "; errorDetails: ", text);
OPENSSL_free(text);
}
if (ctx->status != OSSL_CMP_PKISTATUS_rejection) {
CMPerr(0, CMP_R_UNEXPECTED_PKISTATUS);
if (ctx->status == OSSL_CMP_PKISTATUS_waiting)
ctx->status = OSSL_CMP_PKISTATUS_rejection;
}
}
return 0;
}
/*-
* When a 'waiting' PKIStatus has been received, this function is used to
* poll, which should yield a pollRep or finally a CertRepMessage in ip/cp/kup.
* On receiving a pollRep, which includes a checkAfter value, it return this
* value if sleep == 0, else it sleeps as long as indicated and retries.
*
* A transaction timeout is enabled if ctx->total_timeout is > 0.
* In this case polling will continue until the timeout is reached and then
* polling is done a last time even if this is before the "checkAfter" time.
*
* Returns -1 on receiving pollRep if sleep == 0, setting the checkAfter value.
* Returns 1 on success and provides the received PKIMESSAGE in *rep.
* In this case the caller is responsible for freeing *rep.
* Returns 0 on error (which includes the case that timeout has been reached).
*/
static int poll_for_response(OSSL_CMP_CTX *ctx, int sleep, int rid,
OSSL_CMP_MSG **rep, int *checkAfter)
{
OSSL_CMP_MSG *preq = NULL;
OSSL_CMP_MSG *prep = NULL;
ossl_cmp_info(ctx,
"received 'waiting' PKIStatus, starting to poll for response");
*rep = NULL;
for (;;) {
/* TODO: handle potentially multiple poll requests per message */
if ((preq = ossl_cmp_pollReq_new(ctx, rid)) == NULL)
goto err;
if (!send_receive_check(ctx, preq, &prep, OSSL_CMP_PKIBODY_POLLREP))
goto err;
/* handle potential pollRep */
if (ossl_cmp_msg_get_bodytype(prep) == OSSL_CMP_PKIBODY_POLLREP) {
OSSL_CMP_POLLREPCONTENT *prc = prep->body->value.pollRep;
OSSL_CMP_POLLREP *pollRep = NULL;
int64_t check_after;
char str[OSSL_CMP_PKISI_BUFLEN];
int len;
/* TODO: handle potentially multiple elements in pollRep */
if (sk_OSSL_CMP_POLLREP_num(prc) > 1) {
CMPerr(0, CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED);
goto err;
}
pollRep = ossl_cmp_pollrepcontent_get0_pollrep(prc, rid);
if (pollRep == NULL)
goto err;
if (!ASN1_INTEGER_get_int64(&check_after, pollRep->checkAfter)) {
CMPerr(0, CMP_R_BAD_CHECKAFTER_IN_POLLREP);
goto err;
}
if (check_after < 0 || (uint64_t)check_after
> (sleep ? ULONG_MAX / 1000 : INT_MAX)) {
CMPerr(0, CMP_R_CHECKAFTER_OUT_OF_RANGE);
if (BIO_snprintf(str, OSSL_CMP_PKISI_BUFLEN, "value = %ld",
check_after) >= 0)
ERR_add_error_data(1, str);
goto err;
}
if (ctx->total_timeout > 0) { /* timeout is not infinite */
const int exp = 5; /* expected max time per msg round trip */
int64_t time_left = (int64_t)(ctx->end_time - exp - time(NULL));
if (time_left <= 0) {
CMPerr(0, CMP_R_TOTAL_TIMEOUT);
goto err;
}
if (time_left < check_after)
check_after = time_left;
/* poll one last time just when timeout was reached */
}
if (pollRep->reason == NULL
|| (len = BIO_snprintf(str, OSSL_CMP_PKISI_BUFLEN,
" with reason = '")) < 0) {
*str = '\0';
} else {
char *text = sk_ASN1_UTF8STRING2text(pollRep->reason, ", ",
sizeof(str) - len - 2);
if (text == NULL
|| BIO_snprintf(str + len, sizeof(str) - len,
"%s'", text) < 0)
*str = '\0';
OPENSSL_free(text);
}
ossl_cmp_log2(INFO, ctx,
"received polling response%s; checkAfter = %ld seconds",
str, check_after);
OSSL_CMP_MSG_free(preq);
preq = NULL;
OSSL_CMP_MSG_free(prep);
prep = NULL;
if (sleep) {
ossl_sleep((unsigned long)(1000 * check_after));
} else {
if (checkAfter != NULL)
*checkAfter = (int)check_after;
return -1; /* exits the loop */
}
} else {
ossl_cmp_info(ctx, "received ip/cp/kup after polling");
/* any other body type has been rejected by send_receive_check() */
break;
}
}
if (prep == NULL)
goto err;
OSSL_CMP_MSG_free(preq);
*rep = prep;
return 1;
err:
OSSL_CMP_MSG_free(preq);
OSSL_CMP_MSG_free(prep);
return 0;
}
/* Send certConf for IR, CR or KUR sequences and check response */
int ossl_cmp_exchange_certConf(OSSL_CMP_CTX *ctx, int fail_info,
const char *txt)
{
OSSL_CMP_MSG *certConf;
OSSL_CMP_MSG *PKIconf = NULL;
int res = 0;
/* OSSL_CMP_certConf_new() also checks if all necessary options are set */
if ((certConf = ossl_cmp_certConf_new(ctx, fail_info, txt)) == NULL)
goto err;
res = send_receive_check(ctx, certConf, &PKIconf, OSSL_CMP_PKIBODY_PKICONF);
err:
OSSL_CMP_MSG_free(certConf);
OSSL_CMP_MSG_free(PKIconf);
return res;
}
/* Send given error and check response */
int ossl_cmp_exchange_error(OSSL_CMP_CTX *ctx, int status, int fail_info,
const char *txt, int errorCode, const char *details)
{
OSSL_CMP_MSG *error = NULL;
OSSL_CMP_PKISI *si = NULL;
OSSL_CMP_MSG *PKIconf = NULL;
int res = 0;
if ((si = OSSL_CMP_STATUSINFO_new(status, fail_info, txt)) == NULL)
goto err;
/* ossl_cmp_error_new() also checks if all necessary options are set */
if ((error = ossl_cmp_error_new(ctx, si, errorCode, details, 0)) == NULL)
goto err;
res = send_receive_check(ctx, error, &PKIconf, OSSL_CMP_PKIBODY_PKICONF);
err:
OSSL_CMP_MSG_free(error);
OSSL_CMP_PKISI_free(si);
OSSL_CMP_MSG_free(PKIconf);
return res;
}
/*-
* Retrieve a copy of the certificate, if any, from the given CertResponse.
* Take into account PKIStatusInfo of CertResponse in ctx, report it on error.
* Returns NULL if not found or on error.
*/
static X509 *get1_cert_status(OSSL_CMP_CTX *ctx, int bodytype,
OSSL_CMP_CERTRESPONSE *crep)
{
char buf[OSSL_CMP_PKISI_BUFLEN];
X509 *crt = NULL;
EVP_PKEY *privkey;
if (!ossl_assert(ctx != NULL && crep != NULL))
return NULL;
privkey = OSSL_CMP_CTX_get0_newPkey(ctx, 1);
switch (ossl_cmp_pkisi_get_status(crep->status)) {
case OSSL_CMP_PKISTATUS_waiting:
ossl_cmp_err(ctx,
"received \"waiting\" status for cert when actually aiming to extract cert");
CMPerr(0, CMP_R_ENCOUNTERED_WAITING);
goto err;
case OSSL_CMP_PKISTATUS_grantedWithMods:
ossl_cmp_warn(ctx, "received \"grantedWithMods\" for certificate");
crt = ossl_cmp_certresponse_get1_certificate(privkey, crep);
break;
case OSSL_CMP_PKISTATUS_accepted:
crt = ossl_cmp_certresponse_get1_certificate(privkey, crep);
break;
/* get all information in case of a rejection before going to error */
case OSSL_CMP_PKISTATUS_rejection:
ossl_cmp_err(ctx, "received \"rejection\" status rather than cert");
CMPerr(0, CMP_R_REQUEST_REJECTED_BY_SERVER);
goto err;
case OSSL_CMP_PKISTATUS_revocationWarning:
ossl_cmp_warn(ctx,
"received \"revocationWarning\" - a revocation of the cert is imminent");
crt = ossl_cmp_certresponse_get1_certificate(privkey, crep);
break;
case OSSL_CMP_PKISTATUS_revocationNotification:
ossl_cmp_warn(ctx,
"received \"revocationNotification\" - a revocation of the cert has occurred");
crt = ossl_cmp_certresponse_get1_certificate(privkey, crep);
break;
case OSSL_CMP_PKISTATUS_keyUpdateWarning:
if (bodytype != OSSL_CMP_PKIBODY_KUR) {
CMPerr(0, CMP_R_ENCOUNTERED_KEYUPDATEWARNING);
goto err;
}
crt = ossl_cmp_certresponse_get1_certificate(privkey, crep);
break;
default:
ossl_cmp_log1(ERROR, ctx,
"received unsupported PKIStatus %d for certificate",
ctx->status);
CMPerr(0, CMP_R_UNKNOWN_PKISTATUS);
goto err;
}
if (crt == NULL) /* according to PKIStatus, we can expect a cert */
CMPerr(0, CMP_R_CERTIFICATE_NOT_FOUND);
return crt;
err:
if (OSSL_CMP_CTX_snprint_PKIStatus(ctx, buf, sizeof(buf)) != NULL)
ERR_add_error_data(1, buf);
return NULL;
}
/*-
* Callback fn validating that the new certificate can be verified, using
* ctx->certConf_cb_arg, which has been initialized using opt_out_trusted, and
* ctx->untrusted_certs, which at this point already contains ctx->extraCertsIn.
* Returns 0 on acceptance, else a bit field reflecting PKIFailureInfo.
* Quoting from RFC 4210 section 5.1. Overall PKI Message:
* The extraCerts field can contain certificates that may be useful to
* the recipient. For example, this can be used by a CA or RA to
* present an end entity with certificates that it needs to verify its
* own new certificate (if, for example, the CA that issued the end
* entity's certificate is not a root CA for the end entity). Note that
* this field does not necessarily contain a certification path; the
* recipient may have to sort, select from, or otherwise process the
* extra certificates in order to use them.
* Note: While often handy, there is no hard requirement by CMP that
* an EE must be able to validate the certificates it gets enrolled.
*/
int OSSL_CMP_certConf_cb(OSSL_CMP_CTX *ctx, X509 *cert, int fail_info,
const char **text)
{
X509_STORE *out_trusted = OSSL_CMP_CTX_get_certConf_cb_arg(ctx);
(void)text; /* make (artificial) use of var to prevent compiler warning */
if (fail_info != 0) /* accept any error flagged by CMP core library */
return fail_info;
if (out_trusted != NULL
&& !OSSL_CMP_validate_cert_path(ctx, out_trusted, cert))
fail_info = 1 << OSSL_CMP_PKIFAILUREINFO_incorrectData;
return fail_info;
}
/*-
* Perform the generic handling of certificate responses for IR/CR/KUR/P10CR.
* Returns -1 on receiving pollRep if sleep == 0, setting the checkAfter value.
* Returns 1 on success and provides the received PKIMESSAGE in *resp.
* Returns 0 on error (which includes the case that timeout has been reached).
* Regardless of success, caller is responsible for freeing *resp (unless NULL).
*/
static int cert_response(OSSL_CMP_CTX *ctx, int sleep, int rid,
OSSL_CMP_MSG **resp, int *checkAfter,
int req_type, int expected_type)
{
EVP_PKEY *rkey = OSSL_CMP_CTX_get0_newPkey(ctx /* may be NULL */, 0);
int fail_info = 0; /* no failure */
const char *txt = NULL;
OSSL_CMP_CERTREPMESSAGE *crepmsg;
OSSL_CMP_CERTRESPONSE *crep;
X509 *cert;
char *subj = NULL;
int ret = 1;
retry:
crepmsg = (*resp)->body->value.ip; /* same for cp and kup */
if (sk_OSSL_CMP_CERTRESPONSE_num(crepmsg->response) > 1) {
CMPerr(0, CMP_R_MULTIPLE_RESPONSES_NOT_SUPPORTED);
return 0;
}
/* TODO: handle potentially multiple CertResponses in CertRepMsg */
crep = ossl_cmp_certrepmessage_get0_certresponse(crepmsg, rid);
if (crep == NULL)
return 0;
if (!save_statusInfo(ctx, crep->status))
return 0;
if (rid == -1) {
/* for OSSL_CMP_PKIBODY_P10CR learn CertReqId from response */
rid = ossl_cmp_asn1_get_int(crep->certReqId);
if (rid == -1) {
CMPerr(0, CMP_R_BAD_REQUEST_ID);
return 0;
}
}
if (ossl_cmp_pkisi_get_status(crep->status) == OSSL_CMP_PKISTATUS_waiting) {
OSSL_CMP_MSG_free(*resp);
*resp = NULL;
if ((ret = poll_for_response(ctx, sleep, rid, resp, checkAfter)) != 0) {
if (ret == -1) /* at this point implies sleep == 0 */
return ret; /* waiting */
goto retry; /* got ip/cp/kup, which may still indicate 'waiting' */
} else {
CMPerr(0, CMP_R_POLLING_FAILED);
return 0;
}
}
cert = get1_cert_status(ctx, (*resp)->body->type, crep);
if (cert == NULL) {
ERR_add_error_data(1, "; cannot extract certificate from response");
return 0;
}
if (!ossl_cmp_ctx_set0_newCert(ctx, cert))
return 0;
/*
* if the CMP server returned certificates in the caPubs field, copy them
* to the context so that they can be retrieved if necessary
*/
if (crepmsg->caPubs != NULL
&& !ossl_cmp_ctx_set1_caPubs(ctx, crepmsg->caPubs))
return 0;
/* copy received extraCerts to ctx->extraCertsIn so they can be retrieved */
if (!ossl_cmp_ctx_set1_extraCertsIn(ctx, (*resp)->extraCerts))
return 0;
subj = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0);
if (rkey != NULL
/* X509_check_private_key() also works if rkey is just public key */
&& !(X509_check_private_key(ctx->newCert, rkey))) {
fail_info = 1 << OSSL_CMP_PKIFAILUREINFO_incorrectData;
txt = "public key in new certificate does not match our enrollment key";
/*-
* not callling (void)ossl_cmp_exchange_error(ctx,
* OSSL_CMP_PKISTATUS_rejection, fail_info, txt)
* not throwing CMP_R_CERTIFICATE_NOT_ACCEPTED with txt
* not returning 0
* since we better leave this for any ctx->certConf_cb to decide
*/
}
/*
* Execute the certification checking callback function possibly set in ctx,
* which can determine whether to accept a newly enrolled certificate.
* It may overrule the pre-decision reflected in 'fail_info' and '*txt'.
*/
if (ctx->certConf_cb
&& (fail_info = ctx->certConf_cb(ctx, ctx->newCert,
fail_info, &txt)) != 0) {
if (txt == NULL)
txt = "CMP client application did not accept it";
}
if (fail_info != 0) /* immediately log error before any certConf exchange */
ossl_cmp_log1(ERROR, ctx,
"rejecting newly enrolled cert with subject: %s", subj);
/*
* TODO: better move certConf exchange to do_certreq_seq() such that
* also more low-level errors with CertReqMessages get reported to server
*/
if (!ctx->disableConfirm
&& !ossl_cmp_hdr_has_implicitConfirm((*resp)->header)) {
if (!ossl_cmp_exchange_certConf(ctx, fail_info, txt))
ret = 0;
}
/* not throwing failure earlier as transfer_cb may call ERR_clear_error() */
if (fail_info != 0) {
CMPerr(0, CMP_R_CERTIFICATE_NOT_ACCEPTED);
ERR_add_error_data(2, "rejecting newly enrolled cert with subject: ",
subj);
if (txt != NULL)
ERR_add_error_txt("; ", txt);
ret = 0;
}
OPENSSL_free(subj);
return ret;
}
int OSSL_CMP_try_certreq(OSSL_CMP_CTX *ctx, int req_type, int *checkAfter)
{
OSSL_CMP_MSG *req = NULL;
OSSL_CMP_MSG *rep = NULL;
int is_p10 = req_type == OSSL_CMP_PKIBODY_P10CR;
int rid = is_p10 ? -1 : OSSL_CMP_CERTREQID;
int rep_type = is_p10 ? OSSL_CMP_PKIBODY_CP : req_type + 1;
int res = 0;
if (ctx == NULL) {
CMPerr(0, CMP_R_NULL_ARGUMENT);
return 0;
}
if (ctx->status != OSSL_CMP_PKISTATUS_waiting) { /* not polling already */
ctx->status = -1;
if (!ossl_cmp_ctx_set0_newCert(ctx, NULL))
return 0;
if (ctx->total_timeout > 0) /* else ctx->end_time is not used */
ctx->end_time = time(NULL) + ctx->total_timeout;
req = ossl_cmp_certReq_new(ctx, req_type, 0 /* req_err */);
if (req == NULL) /* also checks if all necessary options are set */
return 0;
if (!send_receive_check(ctx, req, &rep, rep_type))
goto err;
} else {
if (req_type < 0)
return ossl_cmp_exchange_error(ctx, OSSL_CMP_PKISTATUS_rejection,
0 /* TODO better fail_info value? */,
"polling aborted", 0 /* errorCode */,
"by application");
res = poll_for_response(ctx, 0 /* no sleep */, rid, &rep, checkAfter);
if (res <= 0) /* waiting or error */
return res;
}
res = cert_response(ctx, 0 /* no sleep */, rid, &rep, checkAfter,
req_type, rep_type);
err:
OSSL_CMP_MSG_free(req);
OSSL_CMP_MSG_free(rep);
return res;
}
/*-
* Do the full sequence CR/IR/KUR/P10CR, CP/IP/KUP/CP,
* certConf, PKIconf, and polling if required.
* Will sleep as long as indicated by the server (according to checkAfter).
* All enrollment options need to be present in the context.
* TODO: another function to request two certificates at once should be created.
* Returns pointer to received certificate, or NULL if none was received.
*/
static X509 *do_certreq_seq(OSSL_CMP_CTX *ctx, int req_type, int req_err,
int rep_type)
{
OSSL_CMP_MSG *req = NULL;
OSSL_CMP_MSG *rep = NULL;
int rid = (req_type == OSSL_CMP_PKIBODY_P10CR) ? -1 : OSSL_CMP_CERTREQID;
X509 *result = NULL;
if (ctx == NULL) {
CMPerr(0, CMP_R_NULL_ARGUMENT);
return NULL;
}
ctx->status = -1;
if (!ossl_cmp_ctx_set0_newCert(ctx, NULL))
return NULL;
if (ctx->total_timeout > 0) /* else ctx->end_time is not used */
ctx->end_time = time(NULL) + ctx->total_timeout;
/* OSSL_CMP_certreq_new() also checks if all necessary options are set */
if ((req = ossl_cmp_certReq_new(ctx, req_type, req_err)) == NULL)
goto err;
if (!send_receive_check(ctx, req, &rep, rep_type))
goto err;
if (cert_response(ctx, 1 /* sleep */, rid, &rep, NULL, req_type, rep_type)
<= 0)
goto err;
result = ctx->newCert;
err:
OSSL_CMP_MSG_free(req);
OSSL_CMP_MSG_free(rep);
return result;
}
X509 *OSSL_CMP_exec_IR_ses(OSSL_CMP_CTX *ctx)
{
return do_certreq_seq(ctx, OSSL_CMP_PKIBODY_IR,
CMP_R_ERROR_CREATING_IR, OSSL_CMP_PKIBODY_IP);
}
X509 *OSSL_CMP_exec_CR_ses(OSSL_CMP_CTX *ctx)
{
return do_certreq_seq(ctx, OSSL_CMP_PKIBODY_CR,
CMP_R_ERROR_CREATING_CR, OSSL_CMP_PKIBODY_CP);
}
X509 *OSSL_CMP_exec_KUR_ses(OSSL_CMP_CTX *ctx)
{
return do_certreq_seq(ctx, OSSL_CMP_PKIBODY_KUR,
CMP_R_ERROR_CREATING_KUR, OSSL_CMP_PKIBODY_KUP);
}
X509 *OSSL_CMP_exec_P10CR_ses(OSSL_CMP_CTX *ctx)
{
return do_certreq_seq(ctx, OSSL_CMP_PKIBODY_P10CR,
CMP_R_ERROR_CREATING_P10CR, OSSL_CMP_PKIBODY_CP);
}
X509 *OSSL_CMP_exec_RR_ses(OSSL_CMP_CTX *ctx)
{
OSSL_CMP_MSG *rr = NULL;
OSSL_CMP_MSG *rp = NULL;
const int num_RevDetails = 1;
const int rsid = OSSL_CMP_REVREQSID;
OSSL_CMP_REVREPCONTENT *rrep = NULL;
OSSL_CMP_PKISI *si = NULL;
char buf[OSSL_CMP_PKISI_BUFLEN];
X509 *result = NULL;
if (ctx == NULL) {
CMPerr(0, CMP_R_INVALID_ARGS);
return 0;
}
ctx->status = -1;
/* OSSL_CMP_rr_new() also checks if all necessary options are set */
if ((rr = ossl_cmp_rr_new(ctx)) == NULL)
goto end;
if (!send_receive_check(ctx, rr, &rp, OSSL_CMP_PKIBODY_RP))
goto end;
rrep = rp->body->value.rp;
if (sk_OSSL_CMP_PKISI_num(rrep->status) != num_RevDetails) {
CMPerr(0, CMP_R_WRONG_RP_COMPONENT_COUNT);
goto end;
}
/* evaluate PKIStatus field */
si = ossl_cmp_revrepcontent_get_pkisi(rrep, rsid);
if (!save_statusInfo(ctx, si))
goto err;
switch (ossl_cmp_pkisi_get_status(si)) {
case OSSL_CMP_PKISTATUS_accepted:
ossl_cmp_info(ctx, "revocation accepted (PKIStatus=accepted)");
result = ctx->oldCert;
break;
case OSSL_CMP_PKISTATUS_grantedWithMods:
ossl_cmp_info(ctx, "revocation accepted (PKIStatus=grantedWithMods)");
result = ctx->oldCert;
break;
case OSSL_CMP_PKISTATUS_rejection:
CMPerr(0, CMP_R_REQUEST_REJECTED_BY_SERVER);
goto err;
case OSSL_CMP_PKISTATUS_revocationWarning:
ossl_cmp_info(ctx, "revocation accepted (PKIStatus=revocationWarning)");
result = ctx->oldCert;
break;
case OSSL_CMP_PKISTATUS_revocationNotification:
/* interpretation as warning or error depends on CA */
ossl_cmp_warn(ctx,
"revocation accepted (PKIStatus=revocationNotification)");
result = ctx->oldCert;
break;
case OSSL_CMP_PKISTATUS_waiting:
case OSSL_CMP_PKISTATUS_keyUpdateWarning:
CMPerr(0, CMP_R_UNEXPECTED_PKISTATUS);
goto err;
default:
CMPerr(0, CMP_R_UNKNOWN_PKISTATUS);
goto err;
}
/* check any present CertId in optional revCerts field */
if (rrep->revCerts != NULL) {
OSSL_CRMF_CERTID *cid;
OSSL_CRMF_CERTTEMPLATE *tmpl =
sk_OSSL_CMP_REVDETAILS_value(rr->body->value.rr, rsid)->certDetails;
const X509_NAME *issuer = OSSL_CRMF_CERTTEMPLATE_get0_issuer(tmpl);
ASN1_INTEGER *serial = OSSL_CRMF_CERTTEMPLATE_get0_serialNumber(tmpl);
if (sk_OSSL_CRMF_CERTID_num(rrep->revCerts) != num_RevDetails) {
CMPerr(0, CMP_R_WRONG_RP_COMPONENT_COUNT);
result = NULL;
goto err;
}
if ((cid = ossl_cmp_revrepcontent_get_CertId(rrep, rsid)) == NULL) {
result = NULL;
goto err;
}
if (X509_NAME_cmp(issuer, OSSL_CRMF_CERTID_get0_issuer(cid)) != 0) {
CMPerr(0, CMP_R_WRONG_CERTID_IN_RP);
result = NULL;
goto err;
}
if (ASN1_INTEGER_cmp(serial,
OSSL_CRMF_CERTID_get0_serialNumber(cid)) != 0) {
CMPerr(0, CMP_R_WRONG_SERIAL_IN_RP);
result = NULL;
goto err;
}
}
/* check number of any optionally present crls */
if (rrep->crls != NULL && sk_X509_CRL_num(rrep->crls) != num_RevDetails) {
CMPerr(0, CMP_R_WRONG_RP_COMPONENT_COUNT);
result = NULL;
goto err;
}
err:
if (result == NULL
&& OSSL_CMP_CTX_snprint_PKIStatus(ctx, buf, sizeof(buf)) != NULL)
ERR_add_error_data(1, buf);
end:
OSSL_CMP_MSG_free(rr);
OSSL_CMP_MSG_free(rp);
return result;
}
STACK_OF(OSSL_CMP_ITAV) *OSSL_CMP_exec_GENM_ses(OSSL_CMP_CTX *ctx)
{
OSSL_CMP_MSG *genm;
OSSL_CMP_MSG *genp = NULL;
STACK_OF(OSSL_CMP_ITAV) *rcvd_itavs = NULL;
if (ctx == NULL) {
CMPerr(0, CMP_R_INVALID_ARGS);
return 0;
}
if ((genm = ossl_cmp_genm_new(ctx)) == NULL)
goto err;
if (!send_receive_check(ctx, genm, &genp, OSSL_CMP_PKIBODY_GENP))
goto err;
/* received stack of itavs not to be freed with the genp */
rcvd_itavs = genp->body->value.genp;
genp->body->value.genp = NULL;
err:
OSSL_CMP_MSG_free(genm);
OSSL_CMP_MSG_free(genp);
return rcvd_itavs; /* recv_itavs == NULL indicates an error */
}

+ 21
- 21
crypto/cmp/cmp_ctx.c View File

@ -103,7 +103,7 @@ OSSL_CMP_CTX *OSSL_CMP_CTX_new(void)
ctx->serverPort = OSSL_CMP_DEFAULT_PORT;
ctx->proxyPort = OSSL_CMP_DEFAULT_PORT;
ctx->msgtimeout = 2 * 60;
ctx->msg_timeout = 2 * 60;
if ((ctx->untrusted_certs = sk_X509_new_null()) == NULL)
goto err;
@ -257,7 +257,7 @@ int ossl_cmp_ctx_set0_validatedSrvCert(OSSL_CMP_CTX *ctx, X509 *cert)
* it be rejected.
* Returns 1 on success, 0 on error
*/
int OSSL_CMP_CTX_set_certConf_cb(OSSL_CMP_CTX *ctx, OSSL_cmp_certConf_cb_t cb)
int OSSL_CMP_CTX_set_certConf_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_certConf_cb_t cb)
{
if (ctx == NULL) {
CMPerr(0, CMP_R_NULL_ARGUMENT);
@ -384,7 +384,7 @@ int ossl_cmp_print_log(OSSL_CMP_severity level, const OSSL_CMP_CTX *ctx,
* Set a callback function for error reporting and logging messages.
* Returns 1 on success, 0 on error
*/
int OSSL_CMP_CTX_set_log_cb(OSSL_CMP_CTX *ctx, OSSL_cmp_log_cb_t cb)
int OSSL_CMP_CTX_set_log_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_log_cb_t cb)
{
if (ctx == NULL) {
CMPerr(0, CMP_R_NULL_ARGUMENT);
@ -911,7 +911,7 @@ void *OSSL_CMP_CTX_get_http_cb_arg(const OSSL_CMP_CTX *ctx)
* Set callback function for sending CMP request and receiving response.
* Returns 1 on success, 0 on error
*/
int OSSL_CMP_CTX_set_transfer_cb(OSSL_CMP_CTX *ctx, OSSL_cmp_transfer_cb_t cb)
int OSSL_CMP_CTX_set_transfer_cb(OSSL_CMP_CTX *ctx, OSSL_CMP_transfer_cb_t cb)
{
if (ctx == NULL) {
CMPerr(0, CMP_R_NULL_ARGUMENT);
@ -1010,7 +1010,7 @@ int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val)
case OSSL_CMP_OPT_REVOCATION_REASON:
min_val = OCSP_REVOKED_STATUS_NOSTATUS;
break;
case OSSL_CMP_OPT_POPOMETHOD:
case OSSL_CMP_OPT_POPO_METHOD:
min_val = OSSL_CRMF_POPO_NONE;
break;
default:
@ -1030,10 +1030,10 @@ int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val)
}
ctx->log_verbosity = val;
break;
case OSSL_CMP_OPT_IMPLICITCONFIRM:
case OSSL_CMP_OPT_IMPLICIT_CONFIRM:
ctx->implicitConfirm = val;
break;
case OSSL_CMP_OPT_DISABLECONFIRM:
case OSSL_CMP_OPT_DISABLE_CONFIRM:
ctx->disableConfirm = val;
break;
case OSSL_CMP_OPT_UNPROTECTED_SEND:
@ -1042,7 +1042,7 @@ int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val)
case OSSL_CMP_OPT_UNPROTECTED_ERRORS:
ctx->unprotectedErrors = val;
break;
case OSSL_CMP_OPT_VALIDITYDAYS:
case OSSL_CMP_OPT_VALIDITY_DAYS:
ctx->days = val;
break;
case OSSL_CMP_OPT_SUBJECTALTNAME_NODEFAULT:
@ -1057,7 +1057,7 @@ int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val)
case OSSL_CMP_OPT_IGNORE_KEYUSAGE:
ctx->ignore_keyusage = val;
break;
case OSSL_CMP_OPT_POPOMETHOD:
case OSSL_CMP_OPT_POPO_METHOD:
if (val > OSSL_CRMF_POPO_KEYAGREE) {
CMPerr(0, CMP_R_INVALID_ARGS);
return 0;
@ -1073,11 +1073,11 @@ int OSSL_CMP_CTX_set_option(OSSL_CMP_CTX *ctx, int opt, int val)
case OSSL_CMP_OPT_MAC_ALGNID:
ctx->pbm_mac = val;
break;
case OSSL_CMP_OPT_MSGTIMEOUT:
ctx->msgtimeout = val;
case OSSL_CMP_OPT_MSG_TIMEOUT:
ctx->msg_timeout = val;
break;
case OSSL_CMP_OPT_TOTALTIMEOUT:
ctx->totaltimeout = val;
case OSSL_CMP_OPT_TOTAL_TIMEOUT:
ctx->total_timeout = val;
break;
case OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR:
ctx->permitTAInExtraCertsForIR = val;
@ -1111,15 +1111,15 @@ int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt)
switch (opt) {
case OSSL_CMP_OPT_LOG_VERBOSITY:
return ctx->log_verbosity;
case OSSL_CMP_OPT_IMPLICITCONFIRM:
case OSSL_CMP_OPT_IMPLICIT_CONFIRM:
return ctx->implicitConfirm;
case OSSL_CMP_OPT_DISABLECONFIRM:
case OSSL_CMP_OPT_DISABLE_CONFIRM:
return ctx->disableConfirm;
case OSSL_CMP_OPT_UNPROTECTED_SEND:
return ctx->unprotectedSend;
case OSSL_CMP_OPT_UNPROTECTED_ERRORS:
return ctx->unprotectedErrors;
case OSSL_CMP_OPT_VALIDITYDAYS:
case OSSL_CMP_OPT_VALIDITY_DAYS:
return ctx->days;
case OSSL_CMP_OPT_SUBJECTALTNAME_NODEFAULT:
return ctx->SubjectAltName_nodefault;
@ -1129,7 +1129,7 @@ int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt)
return ctx->setPoliciesCritical;
case OSSL_CMP_OPT_IGNORE_KEYUSAGE:
return ctx->ignore_keyusage;
case OSSL_CMP_OPT_POPOMETHOD:
case OSSL_CMP_OPT_POPO_METHOD:
return ctx->popoMethod;
case OSSL_CMP_OPT_DIGEST_ALGNID:
return ctx->digest;
@ -1137,10 +1137,10 @@ int OSSL_CMP_CTX_get_option(const OSSL_CMP_CTX *ctx, int opt)
return ctx->pbm_owf;
case OSSL_CMP_OPT_MAC_ALGNID:
return ctx->pbm_mac;
case OSSL_CMP_OPT_MSGTIMEOUT:
return ctx->msgtimeout;
case OSSL_CMP_OPT_TOTALTIMEOUT:
return ctx->totaltimeout;
case OSSL_CMP_OPT_MSG_TIMEOUT:
return ctx->msg_timeout;
case OSSL_CMP_OPT_TOTAL_TIMEOUT:
return ctx->total_timeout;
case OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR:
return ctx->permitTAInExtraCertsForIR;
case OSSL_CMP_OPT_REVOCATION_REASON:


+ 33
- 4
crypto/cmp/cmp_err.c View File

@ -16,9 +16,13 @@
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_CHECKAFTER_IN_POLLREP),
"bad checkafter in pollrep"},
{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_ACCEPTED),
"certificate not accepted"},
{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),
@ -27,18 +31,27 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
"certresponse not found"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERT_AND_KEY_DO_NOT_MATCH),
"cert and key do not match"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CHECKAFTER_OUT_OF_RANGE),
"checkafter out of range"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ENCOUNTERED_KEYUPDATEWARNING),
"encountered keyupdatewarning"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ENCOUNTERED_WAITING),
"encountered waiting"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CALCULATING_PROTECTION),
"error calculating protection"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_CERTCONF),
"error creating certconf"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_CERTREP),
"error creating certrep"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_CR), "error creating cr"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_ERROR),
"error creating error"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_GENM),
"error creating genm"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_GENP),
"error creating genp"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_IR), "error creating ir"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_KUR), "error creating kur"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_P10CR),
"error creating p10cr"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_CREATING_PKICONF),
@ -51,14 +64,14 @@ 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_PARSING_PKISTATUS),
"error parsing pkistatus"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_ERROR_PROCESSING_MESSAGE),
"error processing message"},
{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),
@ -83,6 +96,8 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
"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_RESPONSES_NOT_SUPPORTED),
"multiple responses 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"},
@ -92,23 +107,33 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_PKIBODY_ERROR), "pkibody error"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_PKISTATUSINFO_NOT_FOUND),
"pkistatusinfo not found"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_POLLING_FAILED), "polling failed"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_POTENTIALLY_INVALID_CERTIFICATE),
"potentially invalid certificate"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_RECEIVED_ERROR),
"received error"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_RECIPNONCE_UNMATCHED),
"recipnonce unmatched"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_REQUEST_NOT_ACCEPTED),
"request not accepted"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_REQUEST_REJECTED_BY_SERVER),
"request rejected by server"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED),
"sender generalname type not supported"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG),
"srvcert does not validate msg"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_TOTAL_TIMEOUT), "total timeout"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_TRANSACTIONID_UNMATCHED),
"transactionid unmatched"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_TRANSFER_ERROR), "transfer error"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKIBODY), "unexpected pkibody"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKISTATUS),
"unexpected pkistatus"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PVNO), "unexpected pvno"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNKNOWN_ALGORITHM_ID),
"unknown algorithm id"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNKNOWN_CERT_TYPE), "unknown cert type"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNKNOWN_PKISTATUS), "unknown pkistatus"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_ALGORITHM),
"unsupported algorithm"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_KEY_TYPE),
@ -117,7 +142,11 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
"unsupported protection alg dhbasedmac"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_WRONG_ALGORITHM_OID),
"wrong algorithm oid"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_WRONG_CERTID_IN_RP), "wrong certid in rp"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_WRONG_PBM_VALUE), "wrong pbm value"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_WRONG_RP_COMPONENT_COUNT),
"wrong rp component count"},
{ERR_PACK(ERR_LIB_CMP, 0, CMP_R_WRONG_SERIAL_IN_RP), "wrong serial in rp"},
{0, NULL}
};


+ 11
- 5
crypto/cmp/cmp_local.h View File

@ -28,11 +28,11 @@
* this structure is used to store the context for CMP sessions
*/
struct ossl_cmp_ctx_st {
OSSL_cmp_log_cb_t log_cb; /* log callback for error/debug/etc. output */
OSSL_CMP_log_cb_t log_cb; /* log callback for error/debug/etc. output */
OSSL_CMP_severity log_verbosity; /* level of verbosity of log output */
/* message transfer */
OSSL_cmp_transfer_cb_t transfer_cb; /* default: OSSL_CMP_MSG_http_perform */
OSSL_CMP_transfer_cb_t transfer_cb; /* default: OSSL_CMP_MSG_http_perform */
void *transfer_cb_arg; /* allows to store optional argument to cb */
/* HTTP-based transfer */
char *serverPath;
@ -40,8 +40,8 @@ struct ossl_cmp_ctx_st {
int serverPort;
char *proxyName;
int proxyPort;
int msgtimeout; /* max seconds to wait for each CMP message round trip */
int totaltimeout; /* maximum number seconds an enrollment may take, incl. */
int msg_timeout; /* max seconds to wait for each CMP message round trip */
int total_timeout; /* max number of seconds an enrollment may take, incl. */
/* attempts polling for a response if a 'waiting' PKIStatus is received */
time_t end_time; /* session start time + totaltimeout */
OSSL_HTTP_bio_cb_t http_cb;
@ -122,7 +122,7 @@ struct ossl_cmp_ctx_st {
STACK_OF(X509) *extraCertsIn; /* extraCerts received from server */
/* certificate confirmation */
OSSL_cmp_certConf_cb_t certConf_cb; /* callback for app checking new cert */
OSSL_CMP_certConf_cb_t certConf_cb; /* callback for app checking new cert */
void *certConf_cb_arg; /* allows to store an argument individual to cb */
} /* OSSL_CMP_CTX */;
@ -912,4 +912,10 @@ 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);
/* from cmp_client.c */
int ossl_cmp_exchange_certConf(OSSL_CMP_CTX *ctx, int fail_info,
const char *txt);
int ossl_cmp_exchange_error(OSSL_CMP_CTX *ctx, int status, int fail_info,
const char *txt, int errorCode, const char *details);
#endif /* !defined(OSSL_CRYPTO_CMP_LOCAL_H) */

+ 2
- 1
crypto/cmp/cmp_msg.c View File

@ -348,7 +348,8 @@ OSSL_CMP_MSG *ossl_cmp_certReq_new(OSSL_CMP_CTX *ctx, int type, int err_code)
return msg;
err:
CMPerr(0, err_code);
if (err_code != 0)
CMPerr(0, err_code);
OSSL_CRMF_MSG_free(crm);
OSSL_CMP_MSG_free(msg);
return NULL;


+ 11
- 7
crypto/cmp/cmp_server.c View File

@ -215,8 +215,8 @@ static OSSL_CMP_MSG *process_cert_request(OSSL_CMP_SRV_CTX *srv_ctx,
&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,
/* set OSSL_CMP_OPT_IMPLICIT_CONFIRM if and only if transaction ends */
if (!OSSL_CMP_CTX_set_option(srv_ctx->ctx, OSSL_CMP_OPT_IMPLICIT_CONFIRM,
ossl_cmp_hdr_has_implicitConfirm(hdr)
&& srv_ctx->grantImplicitConfirm
/* do not set if polling starts: */
@ -264,7 +264,7 @@ static OSSL_CMP_MSG *process_rr(OSSL_CMP_SRV_CTX *srv_ctx,
if ((details = sk_OSSL_CMP_REVDETAILS_value(req->body->value.rr,
OSSL_CMP_REVREQSID)) == NULL) {
CMPerr(0, CMP_R_ERROR_PROCESSING_MSG);
CMPerr(0, CMP_R_ERROR_PROCESSING_MESSAGE);
return NULL;
}
@ -341,7 +341,7 @@ static OSSL_CMP_MSG *process_certConf(OSSL_CMP_SRV_CTX *srv_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) {
if (OSSL_CMP_CTX_get_option(ctx, OSSL_CMP_OPT_IMPLICIT_CONFIRM) == 1) {
CMPerr(0, CMP_R_ERROR_UNEXPECTED_CERTCONF);
return NULL;
}
@ -415,13 +415,17 @@ static OSSL_CMP_MSG *process_pollReq(OSSL_CMP_SRV_CTX *srv_ctx,
}
/*
* Determines whether missing protection is allowed
* Determine whether missing/invalid protection of request message is allowed.
* Return 1 on acceptance, 0 on rejection, or -1 on (internal) error.
*/
static int unprotected_exception(const OSSL_CMP_CTX *ctx,
const OSSL_CMP_MSG *req,
int invalid_protection,
int accept_unprotected_requests)
{
if (!ossl_assert(ctx != NULL && req != NULL))
return -1;
if (accept_unprotected_requests) {
ossl_cmp_log1(WARN, ctx, "ignoring %s protection of request message",
invalid_protection ? "invalid" : "missing");
@ -574,7 +578,7 @@ OSSL_CMP_MSG *OSSL_CMP_SRV_process_request(OSSL_CMP_SRV_CTX *srv_ctx,
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)
if (OSSL_CMP_CTX_get_option(ctx, OSSL_CMP_OPT_IMPLICIT_CONFIRM) == 0)
break;
/* fall through */
@ -607,7 +611,7 @@ OSSL_CMP_MSG * OSSL_CMP_CTX_server_perform(OSSL_CMP_CTX *client_ctx,
}
if ((srv_ctx = OSSL_CMP_CTX_get_transfer_cb_arg(client_ctx)) == NULL) {
CMPerr(0, CMP_R_ERROR_TRANSFERRING_OUT);
CMPerr(0, CMP_R_TRANSFER_ERROR);
return 0;
}


+ 1
- 1
crypto/cmp/cmp_status.c View File

@ -75,7 +75,7 @@ int ossl_cmp_pkisi_get_pkifailureinfo(const OSSL_CMP_PKISI *si)
int i;
int res = 0;
if (!ossl_assert(si != NULL && si->failInfo != NULL))
if (!ossl_assert(si != NULL))
return -1;
for (i = 0; i <= OSSL_CMP_PKIFAILUREINFO_MAX; i++)
if (ASN1_BIT_STRING_get_bit(si->failInfo, i))


+ 1
- 1
crypto/cmp/cmp_util.c View File

@ -144,7 +144,7 @@ int OSSL_CMP_print_to_bio(BIO *bio, const char *component, const char *file,
#define ERR_PRINT_BUF_SIZE 4096
/* this is similar to ERR_print_errors_cb, but uses the CMP-specific cb type */
void OSSL_CMP_print_errors_cb(OSSL_cmp_log_cb_t log_fn)
void OSSL_CMP_print_errors_cb(OSSL_CMP_log_cb_t log_fn)
{
unsigned long err;
char msg[ERR_PRINT_BUF_SIZE];


+ 20
- 19
crypto/cmp/cmp_vfy.c View File

@ -426,7 +426,7 @@ static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg)
char *sname = NULL;
char *skid_str = NULL;
const ASN1_OCTET_STRING *skid = msg->header->senderKID;
OSSL_cmp_log_cb_t backup_log_cb = ctx->log_cb;
OSSL_CMP_log_cb_t backup_log_cb = ctx->log_cb;
int res = 0;
if (sender == NULL || msg->body == NULL)
@ -633,8 +633,8 @@ int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg)
*
* Ensures that:
* it has a valid body type
* its protection is valid or absent (allowed only if callback function is
* present and function yields non-zero result using also supplied argument)
* its protection is valid (or invalid/absent, but only if a callback function
* is present and yields a positive result using also the supplied argument)
* its transaction ID matches the previous transaction ID stored in ctx (if any)
* its recipNonce matches the previous senderNonce stored in the ctx (if any)
*
@ -660,35 +660,29 @@ int ossl_cmp_msg_check_received(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg,
if (msg->header->protectionAlg != 0) {
/* detect explicitly permitted exceptions for invalid protection */
if (!OSSL_CMP_validate_msg(ctx, msg)
&& (cb == NULL || !(*cb)(ctx, msg, 1, cb_arg))) {
&& (cb == NULL || (*cb)(ctx, msg, 1, cb_arg) <= 0)) {
CMPerr(0, CMP_R_ERROR_VALIDATING_PROTECTION);
return -1;
}
} else {
/* detect explicitly permitted exceptions for missing protection */
if (cb == NULL || !(*cb)(ctx, msg, 0, cb_arg)) {
if (cb == NULL || (*cb)(ctx, msg, 0, cb_arg) <= 0) {
CMPerr(0, CMP_R_MISSING_PROTECTION);
return -1;
}
}
/*
* Store any provided extraCerts in ctx for future use,
* such that they are available to ctx->certConf_cb and
* the peer does not need to send them again in the same transaction.
* For efficiency, the extraCerts are prepended so they get used first.
*/
if (!ossl_cmp_sk_X509_add1_certs(ctx->untrusted_certs, msg->extraCerts,
0 /* this allows self-issued certs */,
1 /* no_dups */, 1 /* prepend */))
return -1;
/* check CMP version number in header */
if (ossl_cmp_hdr_get_pvno(OSSL_CMP_MSG_get0_header(msg)) != OSSL_CMP_PVNO) {
CMPerr(0, CMP_R_UNEXPECTED_PVNO);
return -1;
}
if ((rcvd_type = ossl_cmp_msg_get_bodytype(msg)) < 0) {
CMPerr(0, CMP_R_PKIBODY_ERROR);
return -1;
}
/* compare received transactionID with the expected one in previous msg */
if (ctx->transactionID != NULL
&& (msg->header->transactionID == NULL
@ -720,10 +714,17 @@ int ossl_cmp_msg_check_received(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg,
&& !OSSL_CMP_CTX_set1_transactionID(ctx, msg->header->transactionID))
return -1;
if ((rcvd_type = ossl_cmp_msg_get_bodytype(msg)) < 0) {
CMPerr(0, CMP_R_PKIBODY_ERROR);
/*
* Store any provided extraCerts in ctx for future use,
* such that they are available to ctx->certConf_cb and
* the peer does not need to send them again in the same transaction.
* For efficiency, the extraCerts are prepended so they get used first.
*/
if (!ossl_cmp_sk_X509_add1_certs(ctx->untrusted_certs, msg->extraCerts,
0 /* this allows self-issued certs */,
1 /* no_dups */, 1 /* prepend */))
return -1;
}
return rcvd_type;
}


+ 20
- 2
crypto/err/openssl.txt View File

@ -2078,19 +2078,27 @@ BN_R_P_IS_NOT_PRIME:112:p is not prime
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_CHECKAFTER_IN_POLLREP:167:bad checkafter in pollrep
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_ACCEPTED:169:certificate not accepted
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_CHECKAFTER_OUT_OF_RANGE:181:checkafter out of range
CMP_R_ENCOUNTERED_KEYUPDATEWARNING:176:encountered keyupdatewarning
CMP_R_ENCOUNTERED_WAITING:162:encountered waiting
CMP_R_ERROR_CALCULATING_PROTECTION:115:error calculating protection
CMP_R_ERROR_CREATING_CERTCONF:116:error creating certconf
CMP_R_ERROR_CREATING_CERTREP:117:error creating certrep
CMP_R_ERROR_CREATING_CR:163:error creating cr
CMP_R_ERROR_CREATING_ERROR:118:error creating error