chunk 7 of CMP contribution to OpenSSL
authorDr. David von Oheimb <David.von.Oheimb@siemens.com>
Sat, 15 Feb 2020 13:57:32 +0000 (14:57 +0100)
committerDr. David von Oheimb <David.von.Oheimb@siemens.com>
Mon, 17 Feb 2020 06:43:58 +0000 (07:43 +0100)
add CMP message validation and related tests; while doing so:
* add ERR_add_error_mem_bio() to crypto/err/err_prn.c
* move ossl_cmp_add_error_txt() as ERR_add_error_txt() to crypto/err/err_prn.c
* add X509_STORE_CTX_print_verify_cb() to crypto/x509/t_x509.c,
  adding internally x509_print_ex_brief(), print_certs(), and print_store_certs()
* move {ossl_cmp_,}X509_STORE_get1_certs() to crypto/x509/x509_lu.c

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Bernd Edlinger <bernd.edlinger@hotmail.de>
(Merged from https://github.com/openssl/openssl/pull/10620)

45 files changed:
crypto/cmp/build.info
crypto/cmp/cmp_err.c
crypto/cmp/cmp_local.h
crypto/cmp/cmp_util.c
crypto/cmp/cmp_vfy.c [new file with mode: 0644]
crypto/err/err_prn.c
crypto/err/openssl.txt
crypto/x509/t_x509.c
crypto/x509/x509_err.c
crypto/x509/x509_lu.c
doc/internal/man3/ossl_cmp_print_log.pod
doc/man3/ERR_put_error.pod
doc/man3/OSSL_CMP_validate_msg.pod [new file with mode: 0644]
doc/man3/X509_STORE_CTX_set_verify_cb.pod
doc/man3/X509_STORE_get0_param.pod
include/crypto/x509.h
include/openssl/cmp.h
include/openssl/cmperr.h
include/openssl/err.h
include/openssl/x509_vfy.h
include/openssl/x509err.h
test/build.info
test/cmp_ctx_test.c
test/cmp_protect_test.c
test/cmp_vfy_test.c [new file with mode: 0644]
test/recipes/65-test_cmp_vfy.t [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/EndEntity1.crt [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/EndEntity2.crt [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/IP_waitingStatus_PBM.der [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/IP_waitingStatus_PBM.txt [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/IR_protected.der [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/IR_protected_0_extraCerts.der [new file with mode: 0755]
test/recipes/65-test_cmp_vfy_data/IR_protected_2_extraCerts.der [new file with mode: 0755]
test/recipes/65-test_cmp_vfy_data/IR_rmprotection.der [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/IR_unprotected.der [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/Intermediate_CA.crt [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/Root_CA.crt [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/chain.txt [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/client.crt [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/insta.cert.pem [new file with mode: 0755]
test/recipes/65-test_cmp_vfy_data/insta.priv.pem [new file with mode: 0755]
test/recipes/65-test_cmp_vfy_data/insta_ca.cert.pem [new file with mode: 0755]
test/recipes/65-test_cmp_vfy_data/server.crt [new file with mode: 0644]
test/recipes/65-test_cmp_vfy_data/server.key [new file with mode: 0644]
util/libcrypto.num

index 760c342..41a5899 100644 (file)
@@ -1,3 +1,3 @@
 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_status.c cmp_hdr.c cmp_protect.c cmp_msg.c cmp_vfy.c
index a6d59f9..f82ef9e 100644 (file)
@@ -14,6 +14,8 @@
 #ifndef OPENSSL_NO_ERR
 
 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_CERTID_NOT_FOUND), "certid not found"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_CERTIFICATE_NOT_FOUND),
@@ -50,6 +52,10 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
     "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_VALIDATING_PROTECTION),
+    "error validating protection"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILED_EXTRACTING_PUBKEY),
+    "failed extracting pubkey"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAILURE_OBTAINING_RANDOM),
     "failure obtaining random"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_FAIL_INFO_OUT_OF_RANGE),
@@ -57,19 +63,38 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_INVALID_ARGS), "invalid args"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION),
     "missing key input for creating protection"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE),
+    "missing key usage digitalsignature"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_PRIVATE_KEY),
     "missing private key"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_PROTECTION), "missing protection"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_MISSING_SENDER_IDENTIFICATION),
     "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_SAN_SOURCES),
     "multiple san sources"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_NO_STDIO), "no stdio"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_NO_SUITABLE_SENDER_CERT),
+    "no suitable sender cert"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_NULL_ARGUMENT), "null argument"},
+    {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_POTENTIALLY_INVALID_CERTIFICATE),
     "potentially invalid certificate"},
+    {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_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_TRANSACTIONID_UNMATCHED),
+    "transactionid unmatched"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNEXPECTED_PKIBODY), "unexpected pkibody"},
+    {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"},
@@ -77,8 +102,11 @@ static const ERR_STRING_DATA CMP_str_reasons[] = {
     "unsupported algorithm"},
     {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_KEY_TYPE),
     "unsupported key type"},
+    {ERR_PACK(ERR_LIB_CMP, 0, CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC),
+    "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_PBM_VALUE), "wrong pbm value"},
     {0, NULL}
 };
 
index 1e62d45..015a3d4 100644 (file)
@@ -746,10 +746,8 @@ int ossl_cmp_asn1_get_int(const ASN1_INTEGER *a);
 const char *ossl_cmp_log_parse_metadata(const char *buf,
                                         OSSL_CMP_severity *level, char **func,
                                         char **file, int *line);
-/* workaround for 4096 bytes limitation of ERR_print_errors_cb() */
-void ossl_cmp_add_error_txt(const char *separator, const char *txt);
-# define ossl_cmp_add_error_data(txt) ossl_cmp_add_error_txt(" : ", txt)
-# define ossl_cmp_add_error_line(txt) ossl_cmp_add_error_txt("\n", txt)
+# define ossl_cmp_add_error_data(txt) ERR_add_error_txt(" : ", txt)
+# define ossl_cmp_add_error_line(txt) ERR_add_error_txt("\n", txt)
 /* functions manipulating lists of certificates etc could be generally useful */
 int ossl_cmp_sk_X509_add1_cert(STACK_OF(X509) *sk, X509 *cert,
                                int no_dup, int prepend);
@@ -919,4 +917,12 @@ ASN1_BIT_STRING *ossl_cmp_calc_protection(const OSSL_CMP_MSG *msg,
 int ossl_cmp_msg_add_extraCerts(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
 int ossl_cmp_msg_protect(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
 
+/* from cmp_vfy.c */
+typedef int (*ossl_cmp_allow_unprotected_cb_t)(const OSSL_CMP_CTX *ctx,
+                                               const OSSL_CMP_MSG *msg,
+                                               int invalid_protection, int arg);
+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 */
index a68f701..ad4ae66 100644 (file)
@@ -142,100 +142,12 @@ int OSSL_CMP_print_to_bio(BIO *bio, const char *component, const char *file,
                       level_string, msg) >= 0;
 }
 
-/*
- * auxiliary function for incrementally reporting texts via the error queue
- */
-static void put_error(int lib, const char *func, int reason,
-                      const char *file, int line)
-{
-    ERR_new();
-    ERR_set_debug(file, line, func);
-    ERR_set_error(lib, reason, NULL /* no data here, so fmt is NULL */);
-}
-
-#define ERR_print_errors_cb_LIMIT 4096 /* size of char buf[] variable there */
-#define TYPICAL_MAX_OUTPUT_BEFORE_DATA 100
-#define MAX_DATA_LEN (ERR_print_errors_cb_LIMIT-TYPICAL_MAX_OUTPUT_BEFORE_DATA)
-void ossl_cmp_add_error_txt(const char *separator, const char *txt)
-{
-    const char *file = NULL;
-    int line;
-    const char *func = NULL;
-    const char *data = NULL;
-    int flags;
-    unsigned long err = ERR_peek_last_error();
-
-    if (separator == NULL)
-        separator = "";
-    if (err == 0)
-        put_error(ERR_LIB_CMP, NULL, 0, "", 0);
-
-    do {
-        size_t available_len, data_len;
-        const char *curr = txt, *next = txt;
-        char *tmp;
-
-        ERR_peek_last_error_all(&file, &line, &func, &data, &flags);
-        if ((flags & ERR_TXT_STRING) == 0) {
-            data = "";
-            separator = "";
-        }
-        data_len = strlen(data);
-
-        /* workaround for limit of ERR_print_errors_cb() */
-        if (data_len >= MAX_DATA_LEN
-                || strlen(separator) >= (size_t)(MAX_DATA_LEN - data_len))
-            available_len = 0;
-        else
-            available_len = MAX_DATA_LEN - data_len - strlen(separator) - 1;
-        /* MAX_DATA_LEN > available_len >= 0 */
-
-        if (separator[0] == '\0') {
-            const size_t len_next = strlen(next);
-
-            if (len_next <= available_len) {
-                next += len_next;
-                curr = NULL; /* no need to split */
-            }
-            else {
-                next += available_len;
-                curr = next; /* will split at this point */
-            }
-        } else {
-            while (*next != '\0' && (size_t)(next - txt) <= available_len) {
-                curr = next;
-                next = strstr(curr, separator);
-                if (next != NULL)
-                    next += strlen(separator);
-                else
-                    next = curr + strlen(curr);
-            }
-            if ((size_t)(next - txt) <= available_len)
-                curr = NULL; /* the above loop implies *next == '\0' */
-        }
-        if (curr != NULL) {
-            /* split error msg at curr since error data would get too long */
-            if (curr != txt) {
-                tmp = OPENSSL_strndup(txt, curr - txt);
-                if (tmp == NULL)
-                    return;
-                ERR_add_error_data(2, separator, tmp);
-                OPENSSL_free(tmp);
-            }
-            put_error(ERR_LIB_CMP, func, err, file, line);
-            txt = curr;
-        } else {
-            ERR_add_error_data(2, separator, txt);
-            txt = next; /* finished */
-        }
-    } while (*txt != '\0');
-}
-
+#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)
 {
     unsigned long err;
-    char msg[ERR_print_errors_cb_LIMIT];
+    char msg[ERR_PRINT_BUF_SIZE];
     const char *file = NULL, *func = NULL, *data = NULL;
     int line, flags;
 
@@ -342,38 +254,6 @@ int ossl_cmp_X509_STORE_add1_certs(X509_STORE *store, STACK_OF(X509) *certs,
     return 1;
 }
 
-STACK_OF(X509) *ossl_cmp_X509_STORE_get1_certs(X509_STORE *store)
-{
-    int i;
-    STACK_OF(X509) *sk;
-    STACK_OF(X509_OBJECT) *objs;
-
-    if (store == NULL) {
-        CMPerr(0, CMP_R_NULL_ARGUMENT);
-        return 0;
-    }
-    if ((sk = sk_X509_new_null()) == NULL)
-        return NULL;
-    objs = X509_STORE_get0_objects(store);
-    for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
-        X509 *cert = X509_OBJECT_get0_X509(sk_X509_OBJECT_value(objs, i));
-
-        if (cert != NULL) {
-            if (!sk_X509_push(sk, cert))
-                goto err;
-            if (!X509_up_ref(cert)) {
-                (void)sk_X509_pop(sk);
-                goto err;
-            }
-        }
-    }
-    return sk;
-
- err:
-    sk_X509_pop_free(sk, X509_free);
-    return NULL;
-}
-
 /*-
  * Builds up the certificate chain of certs as high up as possible using
  * the given list of certs containing all possible intermediate certificates and
diff --git a/crypto/cmp/cmp_vfy.c b/crypto/cmp/cmp_vfy.c
new file mode 100644 (file)
index 0000000..437bc32
--- /dev/null
@@ -0,0 +1,754 @@
+/*
+ * Copyright 2007-2020 The OpenSSL Project Authors. All Rights Reserved.
+ * Copyright Nokia 2007-2020
+ * Copyright Siemens AG 2015-2020
+ *
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
+ */
+
+/* CMP functions for PKIMessage checking */
+
+#include "cmp_local.h"
+#include <openssl/cmp_util.h>
+
+/* explicit #includes not strictly needed since implied by the above: */
+#include <openssl/asn1t.h>
+#include <openssl/cmp.h>
+#include <openssl/crmf.h>
+#include <openssl/err.h>
+#include <openssl/x509.h>
+#include "crypto/x509.h"
+
+/*
+ * Verify a message protected by signature according to section 5.1.3.3
+ * (sha1+RSA/DSA or any other algorithm supported by OpenSSL).
+ *
+ * Returns 1 on successful validation and 0 otherwise.
+ */
+static int verify_signature(const OSSL_CMP_CTX *cmp_ctx,
+                            const OSSL_CMP_MSG *msg, X509 *cert)
+{
+    EVP_MD_CTX *ctx = NULL;
+    CMP_PROTECTEDPART prot_part;
+    int digest_nid, pk_nid;
+    const EVP_MD *digest = NULL;
+    EVP_PKEY *pubkey = NULL;
+    int len;
+    size_t prot_part_der_len = 0;
+    unsigned char *prot_part_der = NULL;
+    BIO *bio = BIO_new(BIO_s_mem()); /* may be NULL */
+    int res = 0;
+
+    if (!ossl_assert(cmp_ctx != NULL && msg != NULL && cert != NULL))
+        return 0;
+
+    /* verify that keyUsage, if present, contains digitalSignature */
+    if (!cmp_ctx->ignore_keyusage
+            && (X509_get_key_usage(cert) & X509v3_KU_DIGITAL_SIGNATURE) == 0) {
+        CMPerr(0, CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE);
+        goto sig_err;
+    }
+
+    pubkey = X509_get_pubkey(cert);
+    if (pubkey == NULL) {
+        CMPerr(0, CMP_R_FAILED_EXTRACTING_PUBKEY);
+        goto sig_err;
+    }
+
+    /* create the DER representation of protected part */
+    prot_part.header = msg->header;
+    prot_part.body = msg->body;
+
+    len = i2d_CMP_PROTECTEDPART(&prot_part, &prot_part_der);
+    if (len < 0 || prot_part_der == NULL)
+        goto end;
+    prot_part_der_len = (size_t) len;
+
+    /* verify signature of protected part */
+    if (!OBJ_find_sigid_algs(OBJ_obj2nid(msg->header->protectionAlg->algorithm),
+                             &digest_nid, &pk_nid)
+            || digest_nid == NID_undef || pk_nid == NID_undef
+            || (digest = EVP_get_digestbynid(digest_nid)) == NULL) {
+        CMPerr(0, CMP_R_ALGORITHM_NOT_SUPPORTED);
+        goto sig_err;
+    }
+
+    /* check msg->header->protectionAlg is consistent with public key type */
+    if (EVP_PKEY_type(pk_nid) != EVP_PKEY_base_id(pubkey)) {
+        CMPerr(0, CMP_R_WRONG_ALGORITHM_OID);
+        goto sig_err;
+    }
+    if ((ctx = EVP_MD_CTX_new()) == NULL)
+        goto end;
+    if (EVP_DigestVerifyInit(ctx, NULL, digest, NULL, pubkey)
+            && EVP_DigestVerify(ctx, msg->protection->data,
+                                msg->protection->length,
+                                prot_part_der, prot_part_der_len) == 1) {
+        res = 1;
+        goto end;
+    }
+
+ sig_err:
+    res = x509_print_ex_brief(bio, cert, X509_FLAG_NO_EXTENSIONS);
+    CMPerr(0, CMP_R_ERROR_VALIDATING_PROTECTION);
+    if (res)
+        ERR_add_error_mem_bio("\n", bio);
+    res = 0;
+
+ end:
+    EVP_MD_CTX_free(ctx);
+    OPENSSL_free(prot_part_der);
+    EVP_PKEY_free(pubkey);
+    BIO_free(bio);
+
+    return res;
+}
+
+/* Verify a message protected with PBMAC */
+static int verify_PBMAC(const OSSL_CMP_MSG *msg,
+                        const ASN1_OCTET_STRING *secret)
+{
+    ASN1_BIT_STRING *protection = NULL;
+    int valid = 0;
+
+    /* generate expected protection for the message */
+    if ((protection = ossl_cmp_calc_protection(msg, secret, NULL)) == NULL)
+        return 0; /* failed to generate protection string! */
+
+    valid = msg->protection != NULL && msg->protection->length >= 0
+            && msg->protection->type == protection->type
+            && msg->protection->length == protection->length
+            && CRYPTO_memcmp(msg->protection->data, protection->data,
+                             protection->length) == 0;
+    ASN1_BIT_STRING_free(protection);
+    if (!valid)
+        CMPerr(0, CMP_R_WRONG_PBM_VALUE);
+
+    return valid;
+}
+
+/*
+ * Attempt to validate certificate and path using any given store with trusted
+ * certs (possibly including CRLs and a cert verification callback function)
+ * and non-trusted intermediate certs from the given ctx.
+ *
+ * Returns 1 on successful validation and 0 otherwise.
+ */
+int OSSL_CMP_validate_cert_path(OSSL_CMP_CTX *ctx, X509_STORE *trusted_store,
+                                X509 *cert)
+{
+    int valid = 0;
+    X509_STORE_CTX *csc = NULL;
+    int err;
+
+    if (ctx == NULL || cert == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+
+    if (trusted_store == NULL) {
+        CMPerr(0, CMP_R_MISSING_TRUST_STORE);
+        return 0;
+    }
+
+    if ((csc = X509_STORE_CTX_new()) == NULL
+            || !X509_STORE_CTX_init(csc, trusted_store,
+                                    cert, ctx->untrusted_certs))
+        goto err;
+
+    valid = X509_verify_cert(csc) > 0;
+
+    /* make sure suitable error is queued even if callback did not do */
+    err = ERR_peek_last_error();
+    if (!valid && ERR_GET_REASON(err) != CMP_R_POTENTIALLY_INVALID_CERTIFICATE)
+        CMPerr(0, CMP_R_POTENTIALLY_INVALID_CERTIFICATE);
+
+ err:
+    X509_STORE_CTX_free(csc);
+    return valid;
+}
+
+/* Return 0 if expect_name != NULL and there is no matching actual_name */
+static int check_name(OSSL_CMP_CTX *ctx,
+                      const char *actual_desc, const X509_NAME *actual_name,
+                      const char *expect_desc, const X509_NAME *expect_name)
+{
+    char *str;
+
+    if (expect_name == NULL)
+        return 1; /* no expectation, thus trivially fulfilled */
+
+    /* make sure that a matching name is there */
+    if (actual_name == NULL) {
+        ossl_cmp_log1(WARN, ctx, "missing %s", actual_desc);
+        return 0;
+    }
+    if (X509_NAME_cmp(actual_name, expect_name) == 0)
+        return 1;
+
+    if ((str = X509_NAME_oneline(actual_name, NULL, 0)) != NULL)
+        ossl_cmp_log2(INFO, ctx, " actual name in %s = %s", actual_desc, str);
+    OPENSSL_free(str);
+    if ((str = X509_NAME_oneline(expect_name, NULL, 0)) != NULL)
+        ossl_cmp_log2(INFO, ctx, " does not match %s = %s", expect_desc, str);
+    OPENSSL_free(str);
+    return 0;
+}
+
+/* Return 0 if skid != NULL and there is no matching subject key ID in cert */
+static int check_kid(OSSL_CMP_CTX *ctx,
+                     X509 *cert, const ASN1_OCTET_STRING *skid)
+{
+    char *actual, *expect;
+    const ASN1_OCTET_STRING *ckid = X509_get0_subject_key_id(cert);
+
+    if (skid == NULL)
+        return 1; /* no expectation, thus trivially fulfilled */
+
+    /* make sure that the expected subject key identifier is there */
+    if (ckid == NULL) {
+        ossl_cmp_warn(ctx, "missing Subject Key Identifier in certificate");
+        return 0;
+    }
+    if (ASN1_OCTET_STRING_cmp(ckid, skid) == 0)
+        return 1;
+
+    if ((actual = OPENSSL_buf2hexstr(ckid->data, ckid->length)) != NULL)
+        ossl_cmp_log1(INFO, ctx, " cert Subject Key Identifier = %s", actual);
+    if ((expect = OPENSSL_buf2hexstr(skid->data, skid->length)) != NULL)
+        ossl_cmp_log1(INFO, ctx, " does not match senderKID    = %s", expect);
+    OPENSSL_free(expect);
+    OPENSSL_free(actual);
+    return 0;
+}
+
+static int already_checked(X509 *cert, const STACK_OF(X509) *already_checked)
+{
+    int i;
+
+    for (i = sk_X509_num(already_checked /* may be NULL */); i > 0; i--)
+        if (X509_cmp(sk_X509_value(already_checked, i - 1), cert) == 0)
+            return 1;
+    return 0;
+}
+
+/*
+ * Check if the given cert is acceptable as sender cert of the given message.
+ * The subject DN must match, the subject key ID as well if present in the msg,
+ * and the cert must be current (checked if ctx->trusted is not NULL).
+ * Note that cert revocation etc. is checked by OSSL_CMP_validate_cert_path().
+ *
+ * Returns 0 on error or not acceptable, else 1.
+ */
+static int cert_acceptable(OSSL_CMP_CTX *ctx,
+                           const char *desc1, const char *desc2, X509 *cert,
+                           const STACK_OF(X509) *already_checked1,
+                           const STACK_OF(X509) *already_checked2,
+                           const OSSL_CMP_MSG *msg)
+{
+    X509_STORE *ts = ctx->trusted;
+    char *sub, *iss;
+    X509_VERIFY_PARAM *vpm = ts != NULL ? X509_STORE_get0_param(ts) : NULL;
+    int time_cmp;
+
+    ossl_cmp_log2(INFO, ctx, " considering %s %s with..", desc1, desc2);
+    if ((sub = X509_NAME_oneline(X509_get_subject_name(cert), NULL, 0)) != NULL)
+        ossl_cmp_log1(INFO, ctx, "  subject = %s", sub);
+    if ((iss = X509_NAME_oneline(X509_get_issuer_name(cert), NULL, 0)) != NULL)
+        ossl_cmp_log1(INFO, ctx, "  issuer  = %s", iss);
+    OPENSSL_free(iss);
+    OPENSSL_free(sub);
+
+    if (already_checked(cert, already_checked1)
+            || already_checked(cert, already_checked2)) {
+        ossl_cmp_info(ctx, " cert has already been checked");
+        return 0;
+    }
+
+    time_cmp = X509_cmp_timeframe(vpm, X509_get0_notBefore(cert),
+                                  X509_get0_notAfter(cert));
+    if (time_cmp != 0) {
+        ossl_cmp_warn(ctx, time_cmp > 0 ? "cert has expired"
+                                        : "cert is not yet valid");
+        return 0;
+    }
+
+    if (!check_name(ctx,
+                    "cert subject", X509_get_subject_name(cert),
+                    "sender field", msg->header->sender->d.directoryName))
+        return 0;
+
+    if (!check_kid(ctx, cert, msg->header->senderKID))
+        return 0;
+    /* acceptable also if there is no senderKID in msg header */
+    ossl_cmp_info(ctx, " cert is acceptable");
+    return 1;
+}
+
+static int check_msg_valid_cert(OSSL_CMP_CTX *ctx, X509_STORE *store,
+                                X509 *scrt, const OSSL_CMP_MSG *msg)
+{
+    if (!verify_signature(ctx, msg, scrt)) {
+        ossl_cmp_warn(ctx, "msg signature verification failed");
+        return 0;
+    }
+    if (!OSSL_CMP_validate_cert_path(ctx, store, scrt)) {
+        ossl_cmp_warn(ctx, "cert path validation failed");
+        return 0;
+    }
+    return 1;
+}
+
+/*
+ * Exceptional handling for 3GPP TS 33.310 [3G/LTE Network Domain Security
+ * (NDS); Authentication Framework (AF)], only to use for IP and if the ctx
+ * option is explicitly set: use self-issued certificates from extraCerts as
+ * trust anchor to validate sender cert and msg -
+ * provided it also can validate the newly enrolled certificate
+ */
+static int check_msg_valid_cert_3gpp(OSSL_CMP_CTX *ctx, X509 *scrt,
+                                     const OSSL_CMP_MSG *msg)
+{
+    int valid = 0;
+    X509_STORE *store = X509_STORE_new();
+
+    if (store != NULL /* store does not include CRLs */
+            && ossl_cmp_X509_STORE_add1_certs(store, msg->extraCerts,
+                                              1 /* self-issued only */))
+        valid = check_msg_valid_cert(ctx, store, scrt, msg);
+    if (valid) {
+        /*
+         * verify that the newly enrolled certificate (which is assumed to have
+         * rid == 0) can also be validated with the same trusted store
+         */
+        EVP_PKEY *privkey = OSSL_CMP_CTX_get0_newPkey(ctx, 1);
+        OSSL_CMP_CERTRESPONSE *crep =
+            ossl_cmp_certrepmessage_get0_certresponse(msg->body->value.ip, 0);
+        X509 *newcrt = ossl_cmp_certresponse_get1_certificate(privkey, crep);
+        /*
+         * maybe better use get_cert_status() from cmp_client.c, which catches
+         * errors
+         */
+        valid = OSSL_CMP_validate_cert_path(ctx, store, newcrt);
+        X509_free(newcrt);
+    }
+    X509_STORE_free(store);
+    return valid;
+}
+
+/*
+ * Try all certs in given list for verifying msg, normally or in 3GPP mode.
+ * If already_checked1 == NULL then certs are assumed to be the msg->extraCerts.
+ */
+static int check_msg_with_certs(OSSL_CMP_CTX *ctx, STACK_OF(X509) *certs,
+                                const char *desc,
+                                const STACK_OF(X509) *already_checked1,
+                                const STACK_OF(X509) *already_checked2,
+                                const OSSL_CMP_MSG *msg, int mode_3gpp)
+{
+    int in_extraCerts = already_checked1 == NULL;
+    int n_acceptable_certs = 0;
+    int i;
+
+    if (sk_X509_num(certs) <= 0) {
+        ossl_cmp_log1(WARN, ctx, "no %s", desc);
+        return 0;
+    }
+
+    for (i = 0; i < sk_X509_num(certs); i++) { /* certs may be NULL */
+        X509 *cert = sk_X509_value(certs, i);
+
+        if (!ossl_assert(cert != NULL))
+            return 0;
+        if (!cert_acceptable(ctx, "cert from", desc, cert,
+                             already_checked1, already_checked2, msg))
+            continue;
+        n_acceptable_certs++;
+        if (mode_3gpp ? check_msg_valid_cert_3gpp(ctx, cert, msg)
+                      : check_msg_valid_cert(ctx, ctx->trusted, cert, msg)) {
+            /* store successful sender cert for further msgs in transaction */
+            if (!X509_up_ref(cert))
+                return 0;
+            if (!ossl_cmp_ctx_set0_validatedSrvCert(ctx, cert)) {
+                X509_free(cert);
+                return 0;
+            }
+            return 1;
+        }
+    }
+    if (in_extraCerts && n_acceptable_certs == 0)
+        ossl_cmp_warn(ctx, "no acceptable cert in extraCerts");
+    return 0;
+}
+
+/*
+ * Verify msg trying first ctx->untrusted_certs, which should include extraCerts
+ * at its front, then trying the trusted certs in truststore (if any) of ctx.
+ */
+static int check_msg_all_certs(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg,
+                               int mode_3gpp)
+{
+    int ret = 0;
+
+    ossl_cmp_info(ctx,
+                  mode_3gpp ? "failed; trying now 3GPP mode trusting extraCerts"
+                            : "trying first normal mode using trust store");
+    if (check_msg_with_certs(ctx, msg->extraCerts, "extraCerts",
+                             NULL, NULL, msg, mode_3gpp))
+        return 1;
+    if (check_msg_with_certs(ctx, ctx->untrusted_certs, "untrusted certs",
+                             msg->extraCerts, NULL, msg, mode_3gpp))
+        return 1;
+
+    if (ctx->trusted == NULL) {
+        ossl_cmp_warn(ctx, mode_3gpp ? "no self-issued extraCerts"
+                                     : "no trusted store");
+    } else {
+        STACK_OF(X509) *trusted = X509_STORE_get1_all_certs(ctx->trusted);
+        ret = check_msg_with_certs(ctx, trusted,
+                                   mode_3gpp ? "self-issued extraCerts"
+                                             : "certs in trusted store",
+                                   msg->extraCerts, ctx->untrusted_certs,
+                                   msg, mode_3gpp);
+        sk_X509_pop_free(trusted, X509_free);
+    }
+    return ret;
+}
+
+/* verify message signature with any acceptable and valid candidate cert */
+static int check_msg_find_cert(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg)
+{
+    X509 *scrt = ctx->validatedSrvCert; /* previous successful sender cert */
+    GENERAL_NAME *sender = msg->header->sender;
+    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;
+    int res = 0;
+
+    if (sender == NULL || msg->body == NULL)
+        return 0; /* other NULL cases already have been checked */
+    if (sender->type != GEN_DIRNAME) {
+        CMPerr(0, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED);
+        return 0;
+    }
+
+    /*
+     * try first cached scrt, used successfully earlier in same transaction,
+     * for validating this and any further msgs where extraCerts may be left out
+     */
+    (void)ERR_set_mark();
+    if (scrt != NULL
+            && cert_acceptable(ctx, "previously validated", "sender cert", scrt,
+                               NULL, NULL, msg)
+            && (check_msg_valid_cert(ctx, ctx->trusted, scrt, msg)
+                    || check_msg_valid_cert_3gpp(ctx, scrt, msg))) {
+        (void)ERR_pop_to_mark();
+        return 1;
+    }
+    (void)ERR_pop_to_mark();
+
+    /* release any cached sender cert that proved no more successfully usable */
+    (void)ossl_cmp_ctx_set0_validatedSrvCert(ctx, NULL);
+
+    /* enable clearing irrelevant errors in attempts to validate sender certs */
+    (void)ERR_set_mark();
+    ctx->log_cb = NULL; /* temporarily disable logging diagnostic info */
+
+    if (check_msg_all_certs(ctx, msg, 0 /* using ctx->trusted */)
+            || check_msg_all_certs(ctx, msg, 1 /* 3gpp */)) {
+        /* discard any diagnostic info on trying to use certs */
+        ctx->log_cb = backup_log_cb; /* restore any logging */
+        (void)ERR_pop_to_mark();
+        res = 1;
+        goto end;
+    }
+    /* failed finding a sender cert that verifies the message signature */
+    ctx->log_cb = backup_log_cb; /* restore any logging */
+    (void)ERR_clear_last_mark();
+
+    sname = X509_NAME_oneline(sender->d.directoryName, NULL, 0);
+    skid_str = skid == NULL ? NULL
+                            : OPENSSL_buf2hexstr(skid->data, skid->length);
+    if (ctx->log_cb != NULL) {
+        ossl_cmp_info(ctx, "verifying msg signature with valid cert that..");
+        if (sname != NULL)
+            ossl_cmp_log1(INFO, ctx, "matches msg sender name = %s", sname);
+        if (skid_str != NULL)
+            ossl_cmp_log1(INFO, ctx, "matches msg senderKID   = %s", skid_str);
+        else
+            ossl_cmp_info(ctx, "while msg header does not contain senderKID");
+        /* re-do the above checks (just) for adding diagnostic information */
+        check_msg_all_certs(ctx, msg, 0 /* using ctx->trusted */);
+        check_msg_all_certs(ctx, msg, 1 /* 3gpp */);
+    }
+
+    CMPerr(0, CMP_R_NO_SUITABLE_SENDER_CERT);
+    if (sname != NULL) {
+        ERR_add_error_txt(NULL, "for msg sender name = ");
+        ERR_add_error_txt(NULL, sname);
+    }
+    if (skid_str != NULL) {
+        ERR_add_error_txt(" and ", "for msg senderKID = ");
+        ERR_add_error_txt(NULL, skid_str);
+    }
+
+ end:
+    OPENSSL_free(sname);
+    OPENSSL_free(skid_str);
+    return res;
+}
+
+/*
+ * Validate the protection of the given PKIMessage using either password-
+ * based mac (PBM) or a signature algorithm. In the case of signature algorithm,
+ * the sender certificate can have been pinned by providing it in ctx->srvCert,
+ * else it is searched in msg->extraCerts, ctx->untrusted_certs, in ctx->trusted
+ * (in this order) and is path is validated against ctx->trusted.
+ *
+ * If ctx->permitTAInExtraCertsForIR is true and when validating a CMP IP msg,
+ * the trust anchor for validating the IP msg may be taken from msg->extraCerts
+ * if a self-issued certificate is found there that can be used to
+ * validate the enrolled certificate returned in the IP.
+ * This is according to the need given in 3GPP TS 33.310.
+ *
+ * Returns 1 on success, 0 on error or validation failed.
+ */
+int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg)
+{
+    X509_ALGOR *alg;
+    int nid = NID_undef, pk_nid = NID_undef;
+    const ASN1_OBJECT *algorOID = NULL;
+    X509 *scrt;
+
+    if (ctx == NULL || msg == NULL
+            || msg->header == NULL || msg->body == NULL) {
+        CMPerr(0, CMP_R_NULL_ARGUMENT);
+        return 0;
+    }
+
+    if ((alg = msg->header->protectionAlg) == NULL /* unprotected message */
+            || msg->protection == NULL || msg->protection->data == NULL) {
+        CMPerr(0, CMP_R_MISSING_PROTECTION);
+        return 0;
+    }
+
+    /* determine the nid for the used protection algorithm */
+    X509_ALGOR_get0(&algorOID, NULL, NULL, alg);
+    nid = OBJ_obj2nid(algorOID);
+
+    switch (nid) {
+        /* 5.1.3.1.  Shared Secret Information */
+    case NID_id_PasswordBasedMAC:
+        if (verify_PBMAC(msg, ctx->secretValue)) {
+            /*
+             * RFC 4210, 5.3.2: 'Note that if the PKI Message Protection is
+             * "shared secret information", then any certificate transported in
+             * the caPubs field may be directly trusted as a root CA
+             * certificate by the initiator.'
+             */
+            switch (ossl_cmp_msg_get_bodytype(msg)) {
+            case -1:
+                return 0;
+            case OSSL_CMP_PKIBODY_IP:
+            case OSSL_CMP_PKIBODY_CP:
+            case OSSL_CMP_PKIBODY_KUP:
+            case OSSL_CMP_PKIBODY_CCP:
+                if (ctx->trusted != NULL) {
+                    STACK_OF(X509) *certs = msg->body->value.ip->caPubs;
+                    /* value.ip is same for cp, kup, and ccp */
+
+                    if (!ossl_cmp_X509_STORE_add1_certs(ctx->trusted, certs, 0))
+                        /* adds both self-issued and not self-issued certs */
+                        return 0;
+                }
+                break;
+            default:
+                break;
+            }
+            return 1;
+        }
+        break;
+
+        /*
+         * 5.1.3.2 DH Key Pairs
+         * Not yet supported
+         */
+    case NID_id_DHBasedMac:
+        CMPerr(0, CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC);
+        break;
+
+        /*
+         * 5.1.3.3.  Signature
+         */
+    default:
+        if (!OBJ_find_sigid_algs(OBJ_obj2nid(alg->algorithm), NULL, &pk_nid)
+                || pk_nid == NID_undef) {
+            CMPerr(0, CMP_R_UNKNOWN_ALGORITHM_ID);
+            break;
+        }
+        /* validate sender name of received msg */
+        if (msg->header->sender->type != GEN_DIRNAME) {
+            CMPerr(0, CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED);
+            break; /* FR#42: support for more than X509_NAME */
+        }
+        /*
+         * Compare actual sender name of response with expected sender name.
+         * Expected name can be set explicitly or the subject of ctx->srvCert.
+         * Mitigates risk to accept misused certificate of an unauthorized
+         * entity of a trusted hierarchy.
+         */
+        if (!check_name(ctx, "sender DN field",
+                        msg->header->sender->d.directoryName,
+                        "expected sender", ctx->expected_sender))
+            break;
+        /* Note: if recipient was NULL-DN it could be learned here if needed */
+
+        scrt = ctx->srvCert;
+        if (scrt == NULL) {
+            if (check_msg_find_cert(ctx, msg))
+                return 1;
+        } else { /* use pinned sender cert */
+            /* use ctx->srvCert for signature check even if not acceptable */
+            if (verify_signature(ctx, msg, scrt))
+                return 1;
+            /* call cert_acceptable() for adding diagnostic information */
+            (void)cert_acceptable(ctx, "explicitly set", "sender cert", scrt,
+                                  NULL, NULL, msg);
+            ossl_cmp_warn(ctx, "msg signature verification failed");
+            CMPerr(0, CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG);
+        }
+        break;
+    }
+    return 0;
+}
+
+
+/*-
+ * Check received message (i.e., response by server or request from client)
+ * Any msg->extraCerts are prepended to ctx->untrusted_certs
+ *
+ * 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 transaction ID matches the previous transaction ID stored in ctx (if any)
+ * its recipNonce matches the previous senderNonce stored in the ctx (if any)
+ *
+ * If everything is fine:
+ * learns the senderNonce from the received message,
+ * learns the transaction ID if it is not yet in ctx.
+ *
+ * returns body type (which is >= 0) of the message on success, -1 on error
+ */
+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 rcvd_type;
+
+    if (!ossl_assert(ctx != NULL && msg != NULL))
+        return -1;
+
+    if (sk_X509_num(msg->extraCerts) > 10)
+        ossl_cmp_warn(ctx,
+                      "received CMP message contains more than 10 extraCerts");
+
+    /* validate message protection */
+    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))) {
+            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)) {
+            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;
+    }
+
+    /* compare received transactionID with the expected one in previous msg */
+    if (ctx->transactionID != NULL
+            && (msg->header->transactionID == NULL
+                || ASN1_OCTET_STRING_cmp(ctx->transactionID,
+                                         msg->header->transactionID) != 0)) {
+        CMPerr(0, CMP_R_TRANSACTIONID_UNMATCHED);
+        return -1;
+    }
+
+    /* compare received nonce with the one we sent */
+    if (ctx->senderNonce != NULL
+            && (msg->header->recipNonce == NULL
+                || ASN1_OCTET_STRING_cmp(ctx->senderNonce,
+                                         msg->header->recipNonce) != 0)) {
+        CMPerr(0, CMP_R_RECIPNONCE_UNMATCHED);
+        return -1;
+    }
+
+    /*
+     * RFC 4210 section 5.1.1 states: the recipNonce is copied from
+     * the senderNonce of the previous message in the transaction.
+     * --> Store for setting in next message
+     */
+    if (!ossl_cmp_ctx_set1_recipNonce(ctx, msg->header->senderNonce))
+        return -1;
+
+    /* if not yet present, learn transactionID */
+    if (ctx->transactionID == NULL
+        && !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);
+        return -1;
+    }
+    return rcvd_type;
+}
+
+int ossl_cmp_verify_popo(const OSSL_CMP_MSG *msg, int accept_RAVerified)
+{
+    if (!ossl_assert(msg != NULL && msg->body != NULL))
+        return 0;
+    switch (msg->body->type) {
+    case OSSL_CMP_PKIBODY_P10CR:
+        {
+            X509_REQ *req = msg->body->value.p10cr;
+
+            if (X509_REQ_verify(req, X509_REQ_get0_pubkey(req)) > 0)
+                return 1;
+            CMPerr(0, CMP_R_REQUEST_NOT_ACCEPTED);
+            return 0;
+        }
+    case OSSL_CMP_PKIBODY_IR:
+    case OSSL_CMP_PKIBODY_CR:
+    case OSSL_CMP_PKIBODY_KUR:
+        return OSSL_CRMF_MSGS_verify_popo(msg->body->value.ir,
+                                          OSSL_CMP_CERTREQID,
+                                          accept_RAVerified);
+    default:
+        CMPerr(0, CMP_R_PKIBODY_ERROR);
+        return 0;
+    }
+}
index e0184b0..9a58898 100644 (file)
 #include <openssl/err.h>
 #include "err_local.h"
 
+#define ERR_PRINT_BUF_SIZE 4096
 void ERR_print_errors_cb(int (*cb) (const char *str, size_t len, void *u),
                          void *u)
 {
     CRYPTO_THREAD_ID tid = CRYPTO_THREAD_get_current_id();
     unsigned long l;
-    char buf[4096], *hex;
+    char buf[ERR_PRINT_BUF_SIZE], *hex;
     const char *lib, *reason;
     const char *file, *data, *func;
     int line, flags;
@@ -44,6 +45,123 @@ void ERR_print_errors_cb(int (*cb) (const char *str, size_t len, void *u),
     }
 }
 
+/* auxiliary function for incrementally reporting texts via the error queue */
+static void put_error(int lib, const char *func, int reason,
+                      const char *file, int line)
+{
+    ERR_new();
+    ERR_set_debug(file, line, func);
+    ERR_set_error(lib, reason, NULL /* no data here, so fmt is NULL */);
+}
+
+#define TYPICAL_MAX_OUTPUT_BEFORE_DATA 100
+#define MAX_DATA_LEN (ERR_PRINT_BUF_SIZE - TYPICAL_MAX_OUTPUT_BEFORE_DATA)
+void ERR_add_error_txt(const char *separator, const char *txt)
+{
+    const char *file = NULL;
+    int line;
+    const char *func = NULL;
+    const char *data = NULL;
+    int flags;
+    unsigned long err = ERR_peek_last_error();
+
+    if (separator == NULL)
+        separator = "";
+    if (err == 0)
+        put_error(ERR_LIB_CMP, NULL, 0, "", 0);
+
+    do {
+        size_t available_len, data_len;
+        const char *curr = txt, *next = txt;
+        const char *leading_separator = separator;
+        int trailing_separator = 0;
+        char *tmp;
+
+        ERR_peek_last_error_all(&file, &line, &func, &data, &flags);
+        if ((flags & ERR_TXT_STRING) == 0) {
+            data = "";
+            leading_separator = "";
+        }
+        data_len = strlen(data);
+
+        /* workaround for limit of ERR_print_errors_cb() */
+        if (data_len >= MAX_DATA_LEN
+                || strlen(separator) >= (size_t)(MAX_DATA_LEN - data_len))
+            available_len = 0;
+        else
+            available_len = MAX_DATA_LEN - data_len - strlen(separator) - 1;
+        /* MAX_DATA_LEN > available_len >= 0 */
+
+        if (*separator == '\0') {
+            const size_t len_next = strlen(next);
+
+            if (len_next <= available_len) {
+                next += len_next;
+                curr = NULL; /* no need to split */
+            } else {
+                next += available_len;
+                curr = next; /* will split at this point */
+            }
+        } else {
+            while (*next != '\0' && (size_t)(next - txt) <= available_len) {
+                curr = next;
+                next = strstr(curr, separator);
+                if (next != NULL) {
+                    next += strlen(separator);
+                    trailing_separator = *next == '\0';
+                } else {
+                    next = curr + strlen(curr);
+                }
+            }
+            if ((size_t)(next - txt) <= available_len)
+                curr = NULL; /* the above loop implies *next == '\0' */
+        }
+        if (curr != NULL) {
+            /* split error msg at curr since error data would get too long */
+            if (curr != txt) {
+                tmp = OPENSSL_strndup(txt, curr - txt);
+                if (tmp == NULL)
+                    return;
+                ERR_add_error_data(2, separator, tmp);
+                OPENSSL_free(tmp);
+            }
+            put_error(ERR_LIB_CMP, func, err, file, line);
+            txt = curr;
+        } else {
+            if (trailing_separator) {
+                tmp = OPENSSL_strndup(txt, next - strlen(separator) - txt);
+                if (tmp == NULL)
+                    return;
+                /* output txt without the trailing separator */
+                ERR_add_error_data(2, leading_separator, tmp);
+                OPENSSL_free(tmp);
+            } else {
+                ERR_add_error_data(2, leading_separator, txt);
+            }
+            txt = next; /* finished */
+        }
+    } while (*txt != '\0');
+}
+
+void ERR_add_error_mem_bio(const char *separator, BIO *bio)
+{
+    if (bio != NULL) {
+        char *str;
+        long len = BIO_get_mem_data(bio, &str);
+
+        if (len > 0) {
+            if (str[len - 1] != '\0') {
+                if (BIO_write(bio, "", 1) <= 0)
+                    return;
+
+                len = BIO_get_mem_data(bio, &str);
+            }
+            if (len > 1)
+                ERR_add_error_txt(separator, str);
+        }
+    }
+}
+
 static int print_bio(const char *str, size_t len, void *bp)
 {
     return BIO_write((BIO *)bp, str, len);
index 8920a77..e6a45ac 100644 (file)
@@ -2067,6 +2067,7 @@ BN_R_PRIVATE_KEY_TOO_LARGE:117:private key too large
 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_REQUEST_ID:108:bad request id
 CMP_R_CERTID_NOT_FOUND:109:certid not found
 CMP_R_CERTIFICATE_NOT_FOUND:112:certificate not found
@@ -2087,24 +2088,41 @@ CMP_R_ERROR_CREATING_RR:126:error creating rr
 CMP_R_ERROR_PARSING_PKISTATUS:107:error parsing pkistatus
 CMP_R_ERROR_PROTECTING_MESSAGE:127:error protecting message
 CMP_R_ERROR_SETTING_CERTHASH:128:error setting certhash
+CMP_R_ERROR_VALIDATING_PROTECTION:140:error validating protection
+CMP_R_FAILED_EXTRACTING_PUBKEY:141:failed extracting pubkey
 CMP_R_FAILURE_OBTAINING_RANDOM:110:failure obtaining random
 CMP_R_FAIL_INFO_OUT_OF_RANGE:129:fail info out of range
 CMP_R_INVALID_ARGS:100:invalid args
 CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION:130:\
        missing key input for creating protection
+CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE:142:missing key usage digitalsignature
 CMP_R_MISSING_PRIVATE_KEY:131:missing private key
+CMP_R_MISSING_PROTECTION:143:missing protection
 CMP_R_MISSING_SENDER_IDENTIFICATION:111:missing sender identification
+CMP_R_MISSING_TRUST_STORE:144:missing trust store
 CMP_R_MULTIPLE_SAN_SOURCES:102:multiple san sources
 CMP_R_NO_STDIO:194:no stdio
+CMP_R_NO_SUITABLE_SENDER_CERT:145:no suitable sender cert
 CMP_R_NULL_ARGUMENT:103:null argument
+CMP_R_PKIBODY_ERROR:146:pkibody error
 CMP_R_PKISTATUSINFO_NOT_FOUND:132:pkistatusinfo not found
-CMP_R_POTENTIALLY_INVALID_CERTIFICATE:139:potentially invalid certificate
+CMP_R_POTENTIALLY_INVALID_CERTIFICATE:147:potentially invalid certificate
+CMP_R_RECIPNONCE_UNMATCHED:148:recipnonce unmatched
+CMP_R_REQUEST_NOT_ACCEPTED:149:request not accepted
+CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED:150:\
+       sender generalname type not supported
+CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG:151:srvcert does not validate msg
+CMP_R_TRANSACTIONID_UNMATCHED:152:transactionid unmatched
 CMP_R_UNEXPECTED_PKIBODY:133:unexpected pkibody
+CMP_R_UNEXPECTED_PVNO:153:unexpected pvno
 CMP_R_UNKNOWN_ALGORITHM_ID:134:unknown algorithm id
 CMP_R_UNKNOWN_CERT_TYPE:135:unknown cert type
 CMP_R_UNSUPPORTED_ALGORITHM:136:unsupported algorithm
 CMP_R_UNSUPPORTED_KEY_TYPE:137:unsupported key type
+CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC:154:\
+       unsupported protection alg dhbasedmac
 CMP_R_WRONG_ALGORITHM_OID:138:wrong algorithm oid
+CMP_R_WRONG_PBM_VALUE:155:wrong pbm value
 CMS_R_ADD_SIGNER_ERROR:99:add signer error
 CMS_R_ATTRIBUTE_ERROR:161:attribute error
 CMS_R_CERTIFICATE_ALREADY_PRESENT:175:certificate already present
@@ -3360,6 +3378,7 @@ X509_R_BAD_X509_FILETYPE:100:bad x509 filetype
 X509_R_BASE64_DECODE_ERROR:118:base64 decode error
 X509_R_CANT_CHECK_DH_KEY:114:cant check dh key
 X509_R_CERT_ALREADY_IN_HASH_TABLE:101:cert already in hash table
+X509_R_CERTIFICATE_VERIFICATION_FAILED:139:certificate verification failed
 X509_R_CRL_ALREADY_DELTA:127:crl already delta
 X509_R_CRL_VERIFY_FAILURE:131:crl verify failure
 X509_R_IDP_MISMATCH:128:idp mismatch
index 4969bb3..eac299c 100644 (file)
@@ -15,6 +15,7 @@
 #include <openssl/x509.h>
 #include <openssl/x509v3.h>
 #include "crypto/asn1.h"
+#include "crypto/x509.h"
 
 #ifndef OPENSSL_NO_STDIO
 int X509_print_fp(FILE *fp, X509 *x)
@@ -380,3 +381,107 @@ int X509_aux_print(BIO *out, X509 *x, int indent)
     }
     return 1;
 }
+
+/*
+ * Helper functions for improving certificate verification error diagnostics
+ */
+
+int x509_print_ex_brief(BIO *bio, X509 *cert, unsigned long neg_cflags)
+{
+    unsigned long flags = ASN1_STRFLGS_RFC2253 | ASN1_STRFLGS_ESC_QUOTE |
+        XN_FLAG_SEP_CPLUS_SPC | XN_FLAG_FN_SN;
+
+    if (cert == NULL)
+        return BIO_printf(bio, "    (no certificate)\n") > 0;
+    if (BIO_printf(bio, "    certificate\n") <= 0
+            || !X509_print_ex(bio, cert, flags, ~X509_FLAG_NO_SUBJECT))
+        return 0;
+    if (X509_check_issued((X509 *)cert, cert) == X509_V_OK) {
+        if (BIO_printf(bio, "        self-issued\n") <= 0)
+            return 0;
+    } else {
+        if (BIO_printf(bio, " ") <= 0
+            || !X509_print_ex(bio, cert, flags, ~X509_FLAG_NO_ISSUER))
+            return 0;
+    }
+    if (!X509_print_ex(bio, cert, flags,
+                       ~(X509_FLAG_NO_SERIAL | X509_FLAG_NO_VALIDITY)))
+        return 0;
+    if (X509_cmp_current_time(X509_get0_notBefore(cert)) > 0)
+        if (BIO_printf(bio, "        not yet valid\n") <= 0)
+            return 0;
+    if (X509_cmp_current_time(X509_get0_notAfter(cert)) < 0)
+        if (BIO_printf(bio, "        no more valid\n") <= 0)
+            return 0;
+    return X509_print_ex(bio, cert, flags, ~(neg_cflags));
+}
+
+static int print_certs(BIO *bio, const STACK_OF(X509) *certs)
+{
+    int i;
+
+    if (certs == NULL || sk_X509_num(certs) <= 0)
+        return BIO_printf(bio, "    (no certificates)\n") >= 0;
+
+    for (i = 0; i < sk_X509_num(certs); i++) {
+        X509 *cert = sk_X509_value(certs, i);
+        if (cert != NULL && !x509_print_ex_brief(bio, cert, 0))
+            return 0;
+    }
+    return 1;
+}
+
+static int print_store_certs(BIO *bio, X509_STORE *store)
+{
+    if (store != NULL) {
+        STACK_OF(X509) *certs = X509_STORE_get1_all_certs(store);
+        int ret = print_certs(bio, certs);
+
+        sk_X509_pop_free(certs, X509_free);
+        return ret;
+    } else {
+        return BIO_printf(bio, "    (no trusted store)\n") >= 0;
+    }
+}
+
+/* Extend the error queue with details on a failed cert verification */
+int X509_STORE_CTX_print_verify_cb(int ok, X509_STORE_CTX *ctx)
+{
+    if (ok == 0 && ctx != NULL) {
+        int cert_error = X509_STORE_CTX_get_error(ctx);
+        int depth = X509_STORE_CTX_get_error_depth(ctx);
+        X509 *cert = X509_STORE_CTX_get_current_cert(ctx);
+        BIO *bio = BIO_new(BIO_s_mem()); /* may be NULL */
+
+        BIO_printf(bio, "%s at depth=%d error=%d (%s)\n",
+                   X509_STORE_CTX_get0_parent_ctx(ctx) != NULL
+                   ? "CRL path validation" : "certificate verification",
+                   depth, cert_error,
+                   X509_verify_cert_error_string(cert_error));
+        BIO_printf(bio, "failure for:\n");
+        x509_print_ex_brief(bio, cert, X509_FLAG_NO_EXTENSIONS);
+        if (cert_error == X509_V_ERR_CERT_UNTRUSTED
+                || cert_error == X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT
+                || cert_error == X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN
+                || cert_error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT
+                || cert_error == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY
+                || cert_error == X509_V_ERR_UNABLE_TO_GET_CRL_ISSUER
+                || cert_error == X509_V_ERR_STORE_LOOKUP) {
+            BIO_printf(bio, "non-trusted certs:\n");
+            print_certs(bio, X509_STORE_CTX_get0_untrusted(ctx));
+            BIO_printf(bio, "certs in trust store:\n");
+            print_store_certs(bio, X509_STORE_CTX_get0_store(ctx));
+        }
+        CMPerr(0, X509_R_CERTIFICATE_VERIFICATION_FAILED);
+        ERR_add_error_mem_bio("\n", bio);
+        BIO_free(bio);
+    }
+
+    /*
+     * TODO we could check policies here too, e.g.:
+     * if (cert_error == X509_V_OK && ok == 2)
+     *     policies_print(NULL, ctx);
+     */
+
+    return ok;
+}
index 1b01fd0..59ffbee 100644 (file)
@@ -22,6 +22,8 @@ static const ERR_STRING_DATA X509_str_reasons[] = {
     {ERR_PACK(ERR_LIB_X509, 0, X509_R_CANT_CHECK_DH_KEY), "cant check dh key"},
     {ERR_PACK(ERR_LIB_X509, 0, X509_R_CERT_ALREADY_IN_HASH_TABLE),
     "cert already in hash table"},
+    {ERR_PACK(ERR_LIB_X509, 0, X509_R_CERTIFICATE_VERIFICATION_FAILED),
+    "certificate verification failed"},
     {ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_ALREADY_DELTA), "crl already delta"},
     {ERR_PACK(ERR_LIB_X509, 0, X509_R_CRL_VERIFY_FAILURE),
     "crl verify failure"},
index 016b4b3..9018d6e 100644 (file)
@@ -532,6 +532,41 @@ STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(X509_STORE *v)
     return v->objs;
 }
 
+STACK_OF(X509) *X509_STORE_get1_all_certs(X509_STORE *store)
+{
+    STACK_OF(X509) *sk;
+    STACK_OF(X509_OBJECT) *objs;
+    int i;
+
+    if (store == NULL) {
+        X509err(0, ERR_R_PASSED_NULL_PARAMETER);
+        return NULL;
+    }
+    if ((sk = sk_X509_new_null()) == NULL)
+        return NULL;
+    X509_STORE_lock(store);
+    objs = X509_STORE_get0_objects(store);
+    for (i = 0; i < sk_X509_OBJECT_num(objs); i++) {
+        X509 *cert = X509_OBJECT_get0_X509(sk_X509_OBJECT_value(objs, i));
+
+        if (cert != NULL) {
+            if (!X509_up_ref(cert))
+                goto err;
+            if (!sk_X509_push(sk, cert)) {
+                X509_free(cert);
+                goto err;
+            }
+        }
+    }
+    X509_STORE_unlock(store);
+    return sk;
+
+ err:
+    X509_STORE_unlock(store);
+    sk_X509_pop_free(sk, X509_free);
+    return NULL;
+}
+
 STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *ctx, X509_NAME *nm)
 {
     int i, idx, cnt;
index a45897a..47d4dd8 100644 (file)
@@ -14,7 +14,6 @@ ossl_cmp_log2,
 ossl_cmp_log3,
 ossl_cmp_log4,
 ossl_cmp_log_parse_metadata,
-ossl_cmp_add_error_txt,
 ossl_cmp_add_error_data,
 ossl_cmp_add_error_line
 - logging and error reporting support for CMP
@@ -40,7 +39,6 @@ ossl_cmp_add_error_line
                                          OSSL_CMP_severity *level, char **func,
                                          char **file, int *line);
 
- void ossl_cmp_add_error_txt(const char *separator, const char *txt);
  #define ossl_cmp_add_error_data(txt)
  #define ossl_cmp_add_error_line(txt)
 
@@ -72,17 +70,11 @@ the variable pointed to by I<file> with the filename string or NULL, and
 the variable pointed to by I<line> with the line number or -1.
 Any string returned via I<*func> and I<*file> must be freeed by the caller.
 
-ossl_cmp_add_error_txt() appends text to the extra data field of the last
-error message in the OpenSSL error queue, after adding the optional separator
-unless data has been empty so far. The text can be of arbitrary length,
-which is not possible when using L<ERR_add_error_data(3)> in conjunction with
-L<ERR_print_errors_cb(3)>.
-
 ossl_cmp_add_error_data() is a macro calling
-ossl_cmp_add_error_txt() with the separator being ":".
+L<ERR_add_error_txt(3)> with the separator being ":".
 
 ossl_cmp_add_error_line() is a macro calling
-ossl_cmp_add_error_txt() with the separator being "\n".
+L<ERR_add_error_txt(3)> with the separator being "\n".
 
 =head1 RETURN VALUES
 
@@ -90,13 +82,16 @@ ossl_cmp_log_parse_metadata() returns the pointer to the actual message text
 after the OSSL_CMP_LOG_PREFIX and level and ':' if found in the buffer,
 else the beginning of the buffer.
 
-ossl_cmp_add_error_txt()
-ossl_cmp_add_error_data(), and
+ossl_cmp_add_error_data() and
 ossl_cmp_add_error_line()
 do not return anything.
 
 All other functions return 1 on success, 0 on error.
 
+=head1 SEE ALSO
+
+L<ERR_add_error_txt(3)>
+
 =head1 HISTORY
 
 The OpenSSL CMP support was added in OpenSSL 3.0.
index e3c19bf..85538f7 100644 (file)
@@ -3,7 +3,8 @@
 =head1 NAME
 
 ERR_raise, ERR_raise_data,
-ERR_put_error, ERR_add_error_data, ERR_add_error_vdata
+ERR_put_error, ERR_add_error_data, ERR_add_error_vdata,
+ERR_add_error_txt, ERR_add_error_mem_bio
 - record an error
 
 =head1 SYNOPSIS
@@ -15,6 +16,8 @@ ERR_put_error, ERR_add_error_data, ERR_add_error_vdata
 
  void ERR_add_error_data(int num, ...);
  void ERR_add_error_vdata(int num, va_list arg);
+ void ERR_add_error_txt(const char *sep, const char *txt);
+ void ERR_add_error_mem_bio(const char *sep, BIO *bio);
 
 Deprecated since OpenSSL 3.0:
 
@@ -38,9 +41,23 @@ B<func> of library B<lib>, in line number B<line> of B<file>.
 This function is usually called by a macro.
 
 ERR_add_error_data() associates the concatenation of its B<num> string
-arguments with the error code added last.
+arguments as additional data with the error code added last.
 ERR_add_error_vdata() is similar except the argument is a B<va_list>.
 Multiple calls to these functions append to the current top of the error queue.
+The total length of the string data per error is limited to 4096 characters.
+
+ERR_add_error_txt() appends the given text string as additional data to the
+last error queue entry, after inserting the optional separator string if it is
+not NULL and the top error entry does not yet have additional data.
+In case the separator is at the end of the text it is not appended to the data.
+The B<sep> argument may be for instance "\n" to insert a line break when needed.
+If the associated data would become more than 4096 characters long
+(which is the limit given above)
+it is split over sufficiently many new copies of the last error queue entry.
+
+ERR_add_error_mem_bio() is the same as ERR_add_error_txt() except that
+the text string is taken from the given memory BIO.
+It appends '\0' to the BIO contents if not already NUL-terminated.
 
 L<ERR_load_strings(3)> can be used to register
 error strings so that the application can a generate human-readable
@@ -76,8 +93,10 @@ the ASN1err() macro.
 
 =head1 RETURN VALUES
 
-ERR_raise(), ERR_put_error(), ERR_add_error_data() and
-ERR_add_error_vdata() return no values.
+ERR_raise(), ERR_put_error(),
+ERR_add_error_data(), ERR_add_error_vdata()
+ERR_add_error_txt(), and ERR_add_error_mem_bio()
+return no values.
 
 =head1 NOTES
 
@@ -87,6 +106,10 @@ ERR_raise() and ERR_put_error() are implemented as macros.
 
 L<ERR_load_strings(3)>
 
+=head1 HISTORY
+
+B<ERR_add_error_txt> and B<ERR_add_error_mem_bio> were added in OpenSSL 3.0.
+
 =head1 COPYRIGHT
 
 Copyright 2000-2019 The OpenSSL Project Authors. All Rights Reserved.
diff --git a/doc/man3/OSSL_CMP_validate_msg.pod b/doc/man3/OSSL_CMP_validate_msg.pod
new file mode 100644 (file)
index 0000000..acb17fa
--- /dev/null
@@ -0,0 +1,86 @@
+=pod
+
+=head1 NAME
+
+OSSL_CMP_validate_msg,
+OSSL_CMP_validate_cert_path
+- functions for verifying CMP message protection
+
+=head1 SYNOPSIS
+
+ #include <openssl/cmp.h>
+ int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, OSSL_CMP_MSG *msg);
+ int OSSL_CMP_validate_cert_path(const OSSL_CMP_CTX *ctx,
+                                 X509_STORE *trusted_store, X509 *cert);
+
+=head1 DESCRIPTION
+
+This is the API for validating the protection of CMP messages,
+which includes validating CMP message sender certificates and their paths
+while optionally checking the revocation status of the certificates(s).
+
+OSSL_CMP_validate_msg() validates the protection of the given C<msg>
+using either password-based mac (PBM) or a signature algorithm.
+
+In case of signature algorithm, the certificate to use for the signature check
+is preferably the one provided by a call to L<OSSL_CMP_CTX_set1_srvCert(3)>.
+If no such sender cert has been pinned then candidate sender certificates are
+taken from the list of certificates received in the C<msg> extraCerts, then any
+certificates provided before via L<OSSL_CMP_CTX_set1_untrusted_certs(3)>, and
+then all trusted certificates provided via L<OSSL_CMP_CTX_set0_trustedStore(3)>,
+where a candidate is acceptable only if has not expired, its subject DN matches
+the C<msg> sender DN (as far as present), and its subject key identifier
+is present and matches the senderKID (as far as the latter present).
+Each acceptable cert is tried in the given order to see if the message
+signature check succeeds and the cert and its path can be verified
+using any trust store set via L<OSSL_CMP_CTX_set0_trustedStore(3)>.
+
+If the option OSSL_CMP_OPT_PERMIT_TA_IN_EXTRACERTS_FOR_IR was set by calling
+L<OSSL_CMP_CTX_set_option(3)>, for an Initialization Response (IP) message
+any self-issued certificate from the C<msg> extraCerts field may also be used
+as trust anchor for the path verification of an acceptable cert if it can be
+used also to validate the issued certificate returned in the IP message. This is
+according to TS 33.310 [Network Domain Security (NDS); Authentication Framework
+(AF)] document specified by the The 3rd Generation Partnership Project (3GPP).
+
+Any cert that has been found as described above is cached and tried first when
+validating the signatures of subsequent messages in the same transaction.
+
+After successful validation of PBM-based protection of a certificate response
+the certificates in the caPubs field (if any) are added to the trusted
+certificates provided via L<OSSL_CMP_CTX_set0_trustedStore(3)>, such that
+they are available for validating subsequent messages in the same context.
+Those could apply to any Polling Response (pollRep), error, or PKI Confirmation
+(PKIConf) messages following in the same or future transactions.
+
+OSSL_CMP_validate_cert_path() attempts to validate the given certificate and its
+path using the given store of trusted certs (possibly including CRLs and a cert
+verification callback) and non-trusted intermediate certs from the B<ctx>.
+
+=head1 NOTES
+
+CMP is defined in RFC 4210 (and CRMF in RFC 4211).
+
+=head1 RETURN VALUES
+
+OSSL_CMP_validate_msg() and OSSL_CMP_validate_cert_path()
+return 1 on success, 0 on error or validation failed.
+
+=head1 SEE ALSO
+
+L<OSSL_CMP_CTX_new(3)>, L<OSSL_CMP_exec_IR_ses(3)>
+
+=head1 HISTORY
+
+The OpenSSL CMP support was added in OpenSSL 3.0.
+
+=head1 COPYRIGHT
+
+Copyright 2007-2019 The OpenSSL Project Authors. All Rights Reserved.
+
+Licensed under the Apache License 2.0 (the "License").  You may not use
+this file except in compliance with the License.  You can obtain a copy
+in the file LICENSE in the source distribution or at
+L<https://www.openssl.org/source/license.html>.
+
+=cut
index 64ccefa..c53b14d 100644 (file)
@@ -14,14 +14,16 @@ X509_STORE_CTX_get_check_issued,
 X509_STORE_CTX_get_get_issuer,
 X509_STORE_CTX_get_verify_cb,
 X509_STORE_CTX_set_verify_cb,
-X509_STORE_CTX_verify_cb
-- get and set verification callback
+X509_STORE_CTX_verify_cb,
+X509_STORE_CTX_print_verify_cb
+- get and set X509_STORE_CTX components such as verification callback
 
 =head1 SYNOPSIS
 
  #include <openssl/x509_vfy.h>
 
  typedef int (*X509_STORE_CTX_verify_cb)(int, X509_STORE_CTX *);
+ int X509_STORE_CTX_print_verify_cb(int ok, X509_STORE_CTX *ctx);
 
  X509_STORE_CTX_verify_cb X509_STORE_CTX_get_verify_cb(X509_STORE_CTX *ctx);
 
@@ -63,6 +65,12 @@ structure and receive additional information about the error, for example
 by calling X509_STORE_CTX_get_current_cert(). Additional application data can
 be passed to the callback via the B<ex_data> mechanism.
 
+X509_STORE_CTX_print_verify_cb() is a verification callback function that,
+when a certificate verification has failed, adds an entry to the error queue
+with code B<X509_R_CERTIFICATE_VERIFICATION_FAILED> and with diagnostic details,
+including the most relevant fields of the target certificate that failed to
+verify and, if appropriate, of the available untrusted and trusted certificates.
+
 X509_STORE_CTX_get_verify_cb() returns the value of the current callback
 for the specific B<ctx>.
 
@@ -200,6 +208,8 @@ X509_STORE_CTX_get_cert_crl(), X509_STORE_CTX_get_check_policy(),
 X509_STORE_CTX_get_lookup_certs(), X509_STORE_CTX_get_lookup_crls()
 and X509_STORE_CTX_get_cleanup() functions were added in OpenSSL 1.1.0.
 
+X509_STORE_CTX_print_verify_cb() was added in OpenSSL 3.0.
+
 =head1 COPYRIGHT
 
 Copyright 2009-2016 The OpenSSL Project Authors. All Rights Reserved.
index 27fe786..6db760e 100644 (file)
@@ -3,7 +3,8 @@
 =head1 NAME
 
 X509_STORE_get0_param, X509_STORE_set1_param,
-X509_STORE_get0_objects - X509_STORE setter and getter functions
+X509_STORE_get0_objects, X509_STORE_get1_all_certs
+- X509_STORE setter and getter functions
 
 =head1 SYNOPSIS
 
@@ -12,6 +13,7 @@ X509_STORE_get0_objects - X509_STORE setter and getter functions
  X509_VERIFY_PARAM *X509_STORE_get0_param(X509_STORE *ctx);
  int X509_STORE_set1_param(X509_STORE *ctx, X509_VERIFY_PARAM *pm);
  STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(X509_STORE *ctx);
+ STACK_OF(X509) *X509_STORE_get1_all_certs(X509_STORE *st);
 
 =head1 DESCRIPTION
 
@@ -22,10 +24,12 @@ X509_STORE_get0_param() retrieves an internal pointer to the verification
 parameters for B<ctx>. The returned pointer must not be freed by the
 calling application
 
-X509_STORE_get0_objects() retrieve an internal pointer to the store's
+X509_STORE_get0_objects() retrieves an internal pointer to the store's
 X509 object cache. The cache contains B<X509> and B<X509_CRL> objects. The
 returned pointer must not be freed by the calling application.
 
+X509_STORE_get1_all_certs() returns a list of all certificates in the store.
+The caller is responsible for freeing the returned list.
 
 =head1 RETURN VALUES
 
@@ -36,6 +40,9 @@ X509_STORE_set1_param() returns 1 for success and 0 for failure.
 
 X509_STORE_get0_objects() returns a pointer to a stack of B<X509_OBJECT>.
 
+X509_STORE_get1_all_certs() returns a pointer to a stack of the retrieved
+certificates on success, else NULL.
+
 =head1 SEE ALSO
 
 L<X509_STORE_new(3)>
@@ -44,6 +51,7 @@ L<X509_STORE_new(3)>
 
 B<X509_STORE_get0_param> and B<X509_STORE_get0_objects> were added in
 OpenSSL 1.1.0.
+B<X509_STORE_get1_certs> was added in OpenSSL 3.0.
 
 =head1 COPYRIGHT
 
index 11a7769..602a72f 100644 (file)
@@ -288,5 +288,6 @@ struct x509_object_st {
 
 int a2i_ipadd(unsigned char *ipout, const char *ipasc);
 int x509_set1_time(ASN1_TIME **ptm, const ASN1_TIME *tm);
+int x509_print_ex_brief(BIO *bio, X509 *cert, unsigned long neg_cflags);
 
 void x509_init_sig_info(X509 *x);
index bc1ae35..43dcc69 100644 (file)
@@ -348,6 +348,11 @@ ASN1_OCTET_STRING *OSSL_CMP_HDR_get0_recipNonce(const OSSL_CMP_PKIHEADER *hdr);
 /* support application-level CMP debugging in cmp.c: */
 OSSL_CMP_PKIHEADER *OSSL_CMP_MSG_get0_header(const OSSL_CMP_MSG *msg);
 
+/* from cmp_vfy.c */
+int OSSL_CMP_validate_msg(OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg);
+int OSSL_CMP_validate_cert_path(OSSL_CMP_CTX *ctx,
+                                X509_STORE *trusted_store, X509 *cert);
+
 #  ifdef  __cplusplus
 }
 #  endif
index a44a1a9..51795a5 100644 (file)
@@ -33,6 +33,7 @@ int ERR_load_CMP_strings(void);
 /*
  * CMP reason codes.
  */
+#  define CMP_R_ALGORITHM_NOT_SUPPORTED                    139
 #  define CMP_R_BAD_REQUEST_ID                             108
 #  define CMP_R_CERTID_NOT_FOUND                           109
 #  define CMP_R_CERTIFICATE_NOT_FOUND                      112
@@ -53,23 +54,38 @@ int ERR_load_CMP_strings(void);
 #  define CMP_R_ERROR_PARSING_PKISTATUS                    107
 #  define CMP_R_ERROR_PROTECTING_MESSAGE                   127
 #  define CMP_R_ERROR_SETTING_CERTHASH                     128
+#  define CMP_R_ERROR_VALIDATING_PROTECTION                140
+#  define CMP_R_FAILED_EXTRACTING_PUBKEY                   141
 #  define CMP_R_FAILURE_OBTAINING_RANDOM                   110
 #  define CMP_R_FAIL_INFO_OUT_OF_RANGE                     129
 #  define CMP_R_INVALID_ARGS                               100
 #  define CMP_R_MISSING_KEY_INPUT_FOR_CREATING_PROTECTION  130
+#  define CMP_R_MISSING_KEY_USAGE_DIGITALSIGNATURE         142
 #  define CMP_R_MISSING_PRIVATE_KEY                        131
+#  define CMP_R_MISSING_PROTECTION                         143
 #  define CMP_R_MISSING_SENDER_IDENTIFICATION              111
+#  define CMP_R_MISSING_TRUST_STORE                        144
 #  define CMP_R_MULTIPLE_SAN_SOURCES                       102
 #  define CMP_R_NO_STDIO                                   194
+#  define CMP_R_NO_SUITABLE_SENDER_CERT                    145
 #  define CMP_R_NULL_ARGUMENT                              103
+#  define CMP_R_PKIBODY_ERROR                              146
 #  define CMP_R_PKISTATUSINFO_NOT_FOUND                    132
-#  define CMP_R_POTENTIALLY_INVALID_CERTIFICATE            139
+#  define CMP_R_POTENTIALLY_INVALID_CERTIFICATE            147
+#  define CMP_R_RECIPNONCE_UNMATCHED                       148
+#  define CMP_R_REQUEST_NOT_ACCEPTED                       149
+#  define CMP_R_SENDER_GENERALNAME_TYPE_NOT_SUPPORTED      150
+#  define CMP_R_SRVCERT_DOES_NOT_VALIDATE_MSG              151
+#  define CMP_R_TRANSACTIONID_UNMATCHED                    152
 #  define CMP_R_UNEXPECTED_PKIBODY                         133
+#  define CMP_R_UNEXPECTED_PVNO                            153
 #  define CMP_R_UNKNOWN_ALGORITHM_ID                       134
 #  define CMP_R_UNKNOWN_CERT_TYPE                          135
 #  define CMP_R_UNSUPPORTED_ALGORITHM                      136
 #  define CMP_R_UNSUPPORTED_KEY_TYPE                       137
+#  define CMP_R_UNSUPPORTED_PROTECTION_ALG_DHBASEDMAC      154
 #  define CMP_R_WRONG_ALGORITHM_OID                        138
+#  define CMP_R_WRONG_PBM_VALUE                            155
 
 # endif
 #endif
index 17a248c..ef8e895 100644 (file)
@@ -333,6 +333,8 @@ void ERR_print_errors(BIO *bp);
 
 void ERR_add_error_data(int num, ...);
 void ERR_add_error_vdata(int num, va_list args);
+void ERR_add_error_txt(const char *sepr, const char *txt);
+void ERR_add_error_mem_bio(const char *sep, BIO *bio);
 
 int ERR_load_strings(int lib, ERR_STRING_DATA *str);
 int ERR_load_strings_const(const ERR_STRING_DATA *str);
index affdc67..75529b2 100644 (file)
@@ -67,6 +67,7 @@ DEFINE_STACK_OF(X509_VERIFY_PARAM)
 int X509_STORE_set_depth(X509_STORE *store, int depth);
 
 typedef int (*X509_STORE_CTX_verify_cb)(int, X509_STORE_CTX *);
+int X509_STORE_CTX_print_verify_cb(int ok, X509_STORE_CTX *ctx);
 typedef int (*X509_STORE_CTX_verify_fn)(X509_STORE_CTX *);
 typedef int (*X509_STORE_CTX_get_issuer_fn)(X509 **issuer,
                                             X509_STORE_CTX *ctx, X509 *x);
@@ -287,8 +288,9 @@ void X509_STORE_free(X509_STORE *v);
 int X509_STORE_lock(X509_STORE *ctx);
 int X509_STORE_unlock(X509_STORE *ctx);
 int X509_STORE_up_ref(X509_STORE *v);
-STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(X509_STORE *v);
 
+STACK_OF(X509_OBJECT) *X509_STORE_get0_objects(X509_STORE *v);
+STACK_OF(X509) *X509_STORE_get1_all_certs(X509_STORE *st);
 STACK_OF(X509) *X509_STORE_CTX_get1_certs(X509_STORE_CTX *st, X509_NAME *nm);
 STACK_OF(X509_CRL) *X509_STORE_CTX_get1_crls(X509_STORE_CTX *st, X509_NAME *nm);
 int X509_STORE_set_flags(X509_STORE *ctx, unsigned long flags);
index 5b0a6b5..2653870 100644 (file)
@@ -107,6 +107,7 @@ int ERR_load_X509_strings(void);
 # define X509_R_BASE64_DECODE_ERROR                       118
 # define X509_R_CANT_CHECK_DH_KEY                         114
 # define X509_R_CERT_ALREADY_IN_HASH_TABLE                101
+# define X509_R_CERTIFICATE_VERIFICATION_FAILED           139
 # define X509_R_CRL_ALREADY_DELTA                         127
 # define X509_R_CRL_VERIFY_FAILURE                        131
 # define X509_R_IDP_MISMATCH                              128
index c35bed0..f964dec 100644 (file)
@@ -455,7 +455,7 @@ IF[{- !$disabled{tests} -}]
 
   IF[{- !$disabled{cmp} -}]
     PROGRAMS{noinst}=cmp_asn_test cmp_ctx_test cmp_status_test cmp_hdr_test \
-                     cmp_protect_test cmp_msg_test
+                     cmp_protect_test cmp_msg_test cmp_vfy_test
   ENDIF
 
   SOURCE[cmp_asn_test]=cmp_asn_test.c cmp_testlib.c
@@ -482,6 +482,10 @@ IF[{- !$disabled{tests} -}]
   INCLUDE[cmp_msg_test]=.. ../include ../apps/include
   DEPEND[cmp_msg_test]=../libcrypto.a libtestutil.a
 
+  SOURCE[cmp_vfy_test]=cmp_status_test.c cmp_testlib.c
+  INCLUDE[cmp_vfy_test]=.. ../include ../apps/include
+  DEPEND[cmp_vfy_test]=../libcrypto.a libtestutil.a
+
   # Internal test programs.  These are essentially a collection of internal
   # test routines.  Some of them need to reach internal symbols that aren't
   # available through the shared library (at least on Linux, Solaris, Windows
index 5c637b0..26c6577 100644 (file)
@@ -169,7 +169,7 @@ static int execute_CTX_print_errors_test(OSSL_CMP_CTX_TEST_FIXTURE *fixture)
         base_err_msg_size = strlen("INVALID_ARGS") + strlen(" : ");
         expected_size = base_err_msg_size;
         while (expected_size < 4096) { /* force split */
-            ossl_cmp_add_error_txt(STR_SEP, max_str_literal);
+            ERR_add_error_txt(STR_SEP, max_str_literal);
             expected_size += strlen(STR_SEP) + strlen(max_str_literal);
         }
         expected_size += base_err_msg_size - 2 * strlen(STR_SEP);
@@ -794,8 +794,7 @@ int setup_tests(void)
 #if !defined(OPENSSL_NO_ERR) && !defined(OPENSSL_NO_AUTOERRINIT)
     /*
      * also tests OSSL_CMP_CTX_set_log_cb(), OSSL_CMP_print_errors_cb(),
-     * ossl_cmp_add_error_txt(), and the macros
-     * ossl_cmp_add_error_data and ossl_cmp_add_error_line:
+     * and the macros ossl_cmp_add_error_data and ossl_cmp_add_error_line:
      */
     ADD_TEST(test_CTX_print_errors);
 #endif
index 022dea6..5d5df89 100644 (file)
@@ -387,7 +387,7 @@ static int execute_X509_STORE_test(CMP_PROTECT_TEST_FIXTURE *fixture)
                                                   fixture->certs,
                                                   fixture->callback_arg)))
         goto err;
-    sk = ossl_cmp_X509_STORE_get1_certs(store);
+    sk = X509_STORE_get1_all_certs(store);
     if (!TEST_int_eq(0, STACK_OF_X509_cmp(sk, fixture->chain)))
         goto err;
     res = 1;
diff --git a/test/cmp_vfy_test.c b/test/cmp_vfy_test.c
new file mode 100644 (file)
index 0000000..41ddad8
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ * 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_testlib.h"
+#include "../crypto/crmf/crmf_local.h" /* for manipulating POPO signature */
+
+static const char *server_f;
+static const char *client_f;
+static const char *endentity1_f;
+static const char *endentity2_f;
+static const char *root_f;
+static const char *intermediate_f;
+static const char *ir_protected_f;
+static const char *ir_unprotected_f;
+static const char *ir_rmprotection_f;
+static const char *ip_waiting_f;
+static const char *instacert_f;
+static const char *instaca_f;
+static const char *ir_protected_0_extracerts;
+static const char *ir_protected_2_extracerts;
+
+typedef struct test_fixture {
+    const char *test_case_name;
+    int expected;
+    OSSL_CMP_CTX *cmp_ctx;
+    OSSL_CMP_MSG *msg;
+    X509 *cert;
+    ossl_cmp_allow_unprotected_cb_t allow_unprotected_cb;
+    int additional_arg;
+} CMP_VFY_TEST_FIXTURE;
+
+static void tear_down(CMP_VFY_TEST_FIXTURE *fixture)
+{
+    OSSL_CMP_MSG_free(fixture->msg);
+    OSSL_CMP_CTX_free(fixture->cmp_ctx);
+    OPENSSL_free(fixture);
+}
+
+static int print_to_bio_out(const char *func, const char *file, int line,
+                            OSSL_CMP_severity level, const char *msg)
+{
+    return OSSL_CMP_print_to_bio(bio_out, func, file, line, level, msg);
+}
+
+static time_t test_time_valid = 0, test_time_after_expiration = 0;
+
+static CMP_VFY_TEST_FIXTURE *set_up(const char *const test_case_name)
+{
+    X509_STORE *ts = X509_STORE_new();
+    CMP_VFY_TEST_FIXTURE *fixture;
+
+    if (!TEST_ptr(fixture = OPENSSL_zalloc(sizeof(*fixture))))
+        return NULL;
+    fixture->test_case_name = test_case_name;
+    if (ts == NULL
+            || !TEST_ptr(fixture->cmp_ctx = OSSL_CMP_CTX_new())
+            || !OSSL_CMP_CTX_set0_trustedStore(fixture->cmp_ctx, ts)
+            || !OSSL_CMP_CTX_set_log_cb(fixture->cmp_ctx, print_to_bio_out)) {
+        tear_down(fixture);
+        X509_STORE_free(ts);
+        return NULL;
+    }
+    X509_VERIFY_PARAM_set_time(X509_STORE_get0_param(ts), test_time_valid);
+    X509_STORE_set_verify_cb(ts, OSSL_CMP_print_cert_verify_cb);
+    return fixture;
+}
+
+static X509 *srvcert = NULL;
+static X509 *clcert = NULL;
+/* chain */
+static X509 *endentity1 = NULL, *endentity2 = NULL,
+    *intermediate = NULL, *root = NULL;
+/* INSTA chain */
+static X509 *insta_cert = NULL, *instaca_cert = NULL;
+
+static unsigned char rand_data[OSSL_CMP_TRANSACTIONID_LENGTH];
+static OSSL_CMP_MSG *ir_unprotected, *ir_rmprotection;
+
+static int flip_bit(ASN1_BIT_STRING *bitstr)
+{
+    int bit_num = 7;
+    int bit = ASN1_BIT_STRING_get_bit(bitstr, bit_num);
+
+    return ASN1_BIT_STRING_set_bit(bitstr, bit_num, !bit);
+}
+
+static int execute_verify_popo_test(CMP_VFY_TEST_FIXTURE *fixture)
+{
+    if ((fixture->msg = load_pkimsg(ir_protected_f)) == NULL)
+        return 0;
+    if (fixture->expected == 0) {
+        const OSSL_CRMF_MSGS *reqs = fixture->msg->body->value.ir;
+        const OSSL_CRMF_MSG *req = sk_OSSL_CRMF_MSG_value(reqs, 0);
+        if (req == NULL || !flip_bit(req->popo->value.signature->signature))
+            return 0;
+    }
+    return TEST_int_eq(fixture->expected,
+                       ossl_cmp_verify_popo(fixture->msg,
+                                            fixture->additional_arg));
+}
+
+static int test_verify_popo(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    EXECUTE_TEST(execute_verify_popo_test, tear_down);
+    return result;
+}
+
+static int test_verify_popo_bad(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    fixture->expected = 0;
+    EXECUTE_TEST(execute_verify_popo_test, tear_down);
+    return result;
+}
+
+static int execute_validate_msg_test(CMP_VFY_TEST_FIXTURE *fixture)
+{
+    return TEST_int_eq(fixture->expected,
+                       OSSL_CMP_validate_msg(fixture->cmp_ctx, fixture->msg));
+}
+
+static int execute_validate_cert_path_test(CMP_VFY_TEST_FIXTURE *fixture)
+{
+    X509_STORE *ts = OSSL_CMP_CTX_get0_trustedStore(fixture->cmp_ctx);
+    int res = TEST_int_eq(fixture->expected,
+                          OSSL_CMP_validate_cert_path(fixture->cmp_ctx,
+                                                      ts, fixture->cert));
+
+    OSSL_CMP_CTX_print_errors(fixture->cmp_ctx);
+    return res;
+}
+
+static int test_validate_msg_mac_alg_protection(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    /* secret value belonging to cmp-test/CMP_IP_waitingStatus_PBM.der */
+    const unsigned char sec_1[] = {
+        '9', 'p', 'p', '8', '-', 'b', '3', '5', 'i', '-', 'X', 'd', '3',
+        'Q', '-', 'u', 'd', 'N', 'R'
+    };
+
+    fixture->expected = 1;
+    if (!TEST_true(OSSL_CMP_CTX_set1_secretValue(fixture->cmp_ctx, sec_1,
+                                                 sizeof(sec_1)))
+            || !TEST_ptr(fixture->msg = load_pkimsg(ip_waiting_f))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_validate_msg_test, tear_down);
+    return result;
+}
+
+static int test_validate_msg_mac_alg_protection_bad(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    const unsigned char sec_bad[] = {
+        '9', 'p', 'p', '8', '-', 'b', '3', '5', 'i', '-', 'X', 'd', '3',
+        'Q', '-', 'u', 'd', 'N', 'r'
+    };
+    fixture->expected = 0;
+
+    if (!TEST_true(OSSL_CMP_CTX_set1_secretValue(fixture->cmp_ctx, sec_bad,
+                                                 sizeof(sec_bad)))
+            || !TEST_ptr(fixture->msg = load_pkimsg(ip_waiting_f))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_validate_msg_test, tear_down);
+    return result;
+}
+
+static int add_trusted(OSSL_CMP_CTX *ctx, X509 *cert)
+{
+    return X509_STORE_add_cert(OSSL_CMP_CTX_get0_trustedStore(ctx), cert);
+}
+
+static int add_untrusted(OSSL_CMP_CTX *ctx, X509 *cert)
+{
+    return ossl_cmp_sk_X509_add1_cert(OSSL_CMP_CTX_get0_untrusted_certs(ctx),
+                                      cert, 0, 0);
+}
+
+static int test_validate_msg_signature_partial_chain(int expired)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    X509_STORE *ts = OSSL_CMP_CTX_get0_trustedStore(fixture->cmp_ctx);
+
+    fixture->expected = !expired;
+    if (ts == NULL
+            || !TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f))
+            || !add_trusted(fixture->cmp_ctx, srvcert)) {
+        tear_down(fixture);
+        fixture = NULL;
+    } else {
+        X509_VERIFY_PARAM *vpm = X509_STORE_get0_param(ts);
+        X509_VERIFY_PARAM_set_flags(vpm, X509_V_FLAG_PARTIAL_CHAIN);
+        if (expired)
+            X509_VERIFY_PARAM_set_time(vpm, test_time_after_expiration);
+    }
+    EXECUTE_TEST(execute_validate_msg_test, tear_down);
+    return result;
+}
+
+static int test_validate_msg_signature_trusted_ok(void)
+{
+    return test_validate_msg_signature_partial_chain(0);
+}
+
+static int test_validate_msg_signature_trusted_expired(void)
+{
+    return test_validate_msg_signature_partial_chain(1);
+}
+
+static int test_validate_msg_signature_srvcert_wrong(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    fixture->expected = 0;
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f))
+        || !TEST_true(OSSL_CMP_CTX_set1_srvCert(fixture->cmp_ctx, clcert))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_validate_msg_test, tear_down);
+    return result;
+}
+
+static int test_validate_msg_signature_srvcert(int bad_sig)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    fixture->expected = !bad_sig;
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f))
+        || !TEST_true(OSSL_CMP_CTX_set1_srvCert(fixture->cmp_ctx, srvcert))
+        || (bad_sig && !flip_bit(fixture->msg->protection))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_validate_msg_test, tear_down);
+    return result;
+}
+
+static int test_validate_msg_signature_bad(void)
+{
+    return test_validate_msg_signature_srvcert(1);
+}
+
+static int test_validate_msg_signature_sender_cert_srvcert(void)
+{
+    return test_validate_msg_signature_srvcert(0);
+}
+
+static int test_validate_msg_signature_sender_cert_untrusted(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_0_extracerts))
+            || !add_trusted(fixture->cmp_ctx, instaca_cert)
+            || !add_untrusted(fixture->cmp_ctx, insta_cert)) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_validate_msg_test, tear_down);
+    return result;
+}
+
+static int test_validate_msg_signature_sender_cert_trusted(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_0_extracerts))
+            || !add_trusted(fixture->cmp_ctx, instaca_cert)
+            || !add_trusted(fixture->cmp_ctx, insta_cert)) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_validate_msg_test, tear_down);
+    return result;
+}
+
+static int test_validate_msg_signature_sender_cert_extracert(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    fixture->expected = 1;
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_2_extracerts))
+            || !add_trusted(fixture->cmp_ctx, instaca_cert)) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_validate_msg_test, tear_down);
+    return result;
+}
+
+
+static int test_validate_msg_signature_sender_cert_absent(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    fixture->expected = 0;
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_0_extracerts))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_validate_msg_test, tear_down);
+    return result;
+}
+
+
+static int test_validate_with_sender(X509_NAME *name, int expected)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    fixture->expected = expected;
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_protected_f))
+        || !TEST_true(OSSL_CMP_CTX_set1_expected_sender(fixture->cmp_ctx, name))
+        || !TEST_true(OSSL_CMP_CTX_set1_srvCert(fixture->cmp_ctx, srvcert))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_validate_msg_test, tear_down);
+    return result;
+}
+
+static int test_validate_msg_signature_expected_sender(void)
+{
+    return test_validate_with_sender(X509_get_subject_name(srvcert), 1);
+}
+
+static int test_validate_msg_signature_unexpected_sender(void)
+{
+    return test_validate_with_sender(X509_get_subject_name(root), 0);
+}
+
+static int test_validate_msg_unprotected_request(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    fixture->expected = 0;
+    if (!TEST_ptr(fixture->msg = load_pkimsg(ir_unprotected_f))) {
+        tear_down(fixture);
+        fixture = NULL;
+    }
+    EXECUTE_TEST(execute_validate_msg_test, tear_down);
+    return result;
+}
+
+static void setup_path(CMP_VFY_TEST_FIXTURE **fixture, X509 *wrong, int expired)
+{
+    (*fixture)->cert = endentity2;
+    (*fixture)->expected = wrong == NULL && !expired;
+    if (expired) {
+        X509_STORE *ts = OSSL_CMP_CTX_get0_trustedStore((*fixture)->cmp_ctx);
+        X509_VERIFY_PARAM *vpm = X509_STORE_get0_param(ts);
+        X509_VERIFY_PARAM_set_time(vpm, test_time_after_expiration);
+    }
+    if (!add_trusted((*fixture)->cmp_ctx, wrong == NULL ? root : wrong)
+            || !add_untrusted((*fixture)->cmp_ctx, endentity1)
+            || !add_untrusted((*fixture)->cmp_ctx, intermediate)) {
+        tear_down((*fixture));
+        (*fixture) = NULL;
+    }
+}
+
+static int test_validate_cert_path_ok(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    setup_path(&fixture, NULL, 0);
+    EXECUTE_TEST(execute_validate_cert_path_test, tear_down);
+    return result;
+}
+
+static int test_validate_cert_path_wrong_anchor(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    setup_path(&fixture, srvcert /* wrong/non-root cert */, 0);
+    EXECUTE_TEST(execute_validate_cert_path_test, tear_down);
+    return result;
+}
+
+static int test_validate_cert_path_expired(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    setup_path(&fixture, NULL, 1);
+    EXECUTE_TEST(execute_validate_cert_path_test, tear_down);
+    return result;
+}
+
+static int execute_MSG_check_received_test(CMP_VFY_TEST_FIXTURE *fixture)
+{
+    const OSSL_CMP_PKIHEADER *hdr = OSSL_CMP_MSG_get0_header(fixture->msg);
+    const ASN1_OCTET_STRING *tid = OSSL_CMP_HDR_get0_transactionID(hdr);
+
+    if (!TEST_int_eq(fixture->expected,
+                     ossl_cmp_msg_check_received(fixture->cmp_ctx,
+                                                 fixture->msg,
+                                                 fixture->allow_unprotected_cb,
+                                                 fixture->additional_arg)))
+        return 0;
+
+    if (fixture->expected < 0) /* error expected aready during above check */
+        return 1;
+    return
+        TEST_int_eq(0,
+                    ASN1_OCTET_STRING_cmp(ossl_cmp_hdr_get0_senderNonce(hdr),
+                                          fixture->cmp_ctx->recipNonce))
+        && TEST_int_eq(0,
+                       ASN1_OCTET_STRING_cmp(tid,
+                                             fixture->cmp_ctx->transactionID));
+}
+
+static int allow_unprotected(const OSSL_CMP_CTX *ctx, const OSSL_CMP_MSG *msg,
+                             int invalid_protection, int allow)
+{
+    return allow;
+}
+
+static void setup_check_received(CMP_VFY_TEST_FIXTURE **fixture, int expected,
+                                 ossl_cmp_allow_unprotected_cb_t cb, int arg,
+                                 const unsigned char *trid_data,
+                                 const unsigned char *nonce_data)
+{
+    OSSL_CMP_CTX *ctx = (*fixture)->cmp_ctx;
+    int nonce_len = OSSL_CMP_SENDERNONCE_LENGTH;
+
+    (*fixture)->expected = expected;
+    (*fixture)->allow_unprotected_cb = cb;
+    (*fixture)->additional_arg = arg;
+    (*fixture)->msg = OSSL_CMP_MSG_dup(ir_rmprotection);
+    if ((*fixture)->msg == NULL
+        || (nonce_data != NULL
+            && !ossl_cmp_asn1_octet_string_set1_bytes(&ctx->senderNonce,
+                                                      nonce_data, nonce_len))) {
+        tear_down((*fixture));
+        (*fixture) = NULL;
+    }
+    else if (trid_data != NULL) {
+        ASN1_OCTET_STRING *trid = ASN1_OCTET_STRING_new();
+        if (trid == NULL
+            || !ASN1_OCTET_STRING_set(trid, trid_data,
+                                      OSSL_CMP_TRANSACTIONID_LENGTH)
+            || !OSSL_CMP_CTX_set1_transactionID(ctx, trid)) {
+            tear_down((*fixture));
+            (*fixture) = NULL;
+        }
+        ASN1_OCTET_STRING_free(trid);
+    }
+}
+
+static int test_MSG_check_received_no_protection_no_cb(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    setup_check_received(&fixture, -1, NULL, 0, NULL, NULL);
+    EXECUTE_TEST(execute_MSG_check_received_test, tear_down);
+    return result;
+}
+
+static int test_MSG_check_received_no_protection_restrictive_cb(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    setup_check_received(&fixture, -1, allow_unprotected, 0, NULL, NULL);
+    EXECUTE_TEST(execute_MSG_check_received_test, tear_down);
+    return result;
+}
+
+static int test_MSG_check_received_no_protection_permissive_cb(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    setup_check_received(&fixture, OSSL_CMP_PKIBODY_IP, allow_unprotected, 1,
+                         NULL, NULL);
+    EXECUTE_TEST(execute_MSG_check_received_test, tear_down);
+    return result;
+}
+
+static int test_MSG_check_received_check_transaction_id(void)
+{
+    /* Transaction id belonging to CMP_IR_rmprotection.der */
+    const unsigned char trans_id[OSSL_CMP_TRANSACTIONID_LENGTH] = {
+        0x39, 0xB6, 0x90, 0x28, 0xC4, 0xBC, 0x7A, 0xF6,
+        0xBE, 0xC6, 0x4A, 0x88, 0x97, 0xA6, 0x95, 0x0B
+    };
+
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    setup_check_received(&fixture, OSSL_CMP_PKIBODY_IP, allow_unprotected, 1,
+                         trans_id, NULL);
+    EXECUTE_TEST(execute_MSG_check_received_test, tear_down);
+    return result;
+}
+
+static int test_MSG_check_received_check_transaction_id_bad(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    setup_check_received(&fixture, -1, allow_unprotected, 1, rand_data, NULL);
+    EXECUTE_TEST(execute_MSG_check_received_test, tear_down);
+    return result;
+}
+
+static int test_MSG_check_received_check_recipient_nonce(void)
+{
+    /* Recipient nonce belonging to CMP_IP_ir_rmprotection.der */
+    const unsigned char rec_nonce[OSSL_CMP_SENDERNONCE_LENGTH] = {
+        0x48, 0xF1, 0x71, 0x1F, 0xE5, 0xAF, 0x1C, 0x8B,
+        0x21, 0x97, 0x5C, 0x84, 0x74, 0x49, 0xBA, 0x32
+    };
+
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    setup_check_received(&fixture, OSSL_CMP_PKIBODY_IP, allow_unprotected, 1,
+                         NULL, rec_nonce);
+    EXECUTE_TEST(execute_MSG_check_received_test, tear_down);
+    return result;
+}
+
+static int test_MSG_check_received_check_recipient_nonce_bad(void)
+{
+    SETUP_TEST_FIXTURE(CMP_VFY_TEST_FIXTURE, set_up);
+    setup_check_received(&fixture, -1, allow_unprotected, 1, NULL, rand_data);
+    EXECUTE_TEST(execute_MSG_check_received_test, tear_down);
+    return result;
+}
+
+void cleanup_tests(void)
+{
+    X509_free(srvcert);
+    X509_free(clcert);
+    X509_free(endentity1);
+    X509_free(endentity2);
+    X509_free(intermediate);
+    X509_free(root);
+    X509_free(insta_cert);
+    X509_free(instaca_cert);
+    OSSL_CMP_MSG_free(ir_unprotected);
+    OSSL_CMP_MSG_free(ir_rmprotection);
+    return;
+}
+
+int setup_tests(void)
+{
+    /* Set test time stamps */
+    struct tm ts = { 0 };
+
+    ts.tm_year = 2018 - 1900;      /* 2018 */
+    ts.tm_mon = 1;                 /* February */
+    ts.tm_mday = 18;               /* 18th */
+    test_time_valid = mktime(&ts); /* February 18th 2018 */
+    ts.tm_year += 10;              /* February 18th 2028 */
+    test_time_after_expiration = mktime(&ts);
+
+    RAND_bytes(rand_data, OSSL_CMP_TRANSACTIONID_LENGTH);
+    if (!TEST_ptr(server_f = test_get_argument(0))
+            || !TEST_ptr(client_f = test_get_argument(1))
+            || !TEST_ptr(endentity1_f = test_get_argument(2))
+            || !TEST_ptr(endentity2_f = test_get_argument(3))
+            || !TEST_ptr(root_f = test_get_argument(4))
+            || !TEST_ptr(intermediate_f = test_get_argument(5))
+            || !TEST_ptr(ir_protected_f = test_get_argument(6))
+            || !TEST_ptr(ir_unprotected_f = test_get_argument(7))
+            || !TEST_ptr(ip_waiting_f = test_get_argument(8))
+            || !TEST_ptr(ir_rmprotection_f = test_get_argument(9))
+            || !TEST_ptr(instacert_f = test_get_argument(10))
+            || !TEST_ptr(instaca_f = test_get_argument(11))
+            || !TEST_ptr(ir_protected_0_extracerts = test_get_argument(12))
+            || !TEST_ptr(ir_protected_2_extracerts = test_get_argument(13))) {
+        TEST_error("usage: cmp_vfy_test server.crt client.crt "
+                   "EndEntity1.crt EndEntity2.crt "
+                   "Root_CA.crt Intermediate_CA.crt "
+                   "CMP_IR_protected.der CMP_IR_unprotected.der "
+                   "IP_waitingStatus_PBM.der IR_rmprotection.der "
+                   "insta.cert.pem insta_ca.cert.pem "
+                   "IR_protected_0_extraCerts.der "
+                   "IR_protected_2_extraCerts.der\n");
+        return 0;
+    }
+
+    /* Load certificates for cert chain */
+    if (!TEST_ptr(endentity1 = load_pem_cert(endentity1_f))
+            || !TEST_ptr(endentity2 = load_pem_cert(endentity2_f))
+            || !TEST_ptr(root = load_pem_cert(root_f))
+            || !TEST_ptr(intermediate = load_pem_cert(intermediate_f)))
+        goto err;
+
+    if (!TEST_ptr(insta_cert = load_pem_cert(instacert_f))
+            || !TEST_ptr(instaca_cert = load_pem_cert(instaca_f)))
+        goto err;
+
+    /* Load certificates for message validation */
+    if (!TEST_ptr(srvcert = load_pem_cert(server_f))
+            || !TEST_ptr(clcert = load_pem_cert(client_f)))
+        goto err;
+    if (!TEST_int_eq(1, RAND_bytes(rand_data, OSSL_CMP_TRANSACTIONID_LENGTH)))
+        goto err;
+    if (!TEST_ptr(ir_unprotected = load_pkimsg(ir_unprotected_f))
+            || !TEST_ptr(ir_rmprotection = load_pkimsg(ir_rmprotection_f)))
+        goto err;
+
+    /* Message validation tests */
+    ADD_TEST(test_verify_popo);
+    ADD_TEST(test_verify_popo_bad);
+    ADD_TEST(test_validate_msg_signature_trusted_ok);
+    ADD_TEST(test_validate_msg_signature_trusted_expired);
+    ADD_TEST(test_validate_msg_signature_srvcert_wrong);
+    ADD_TEST(test_validate_msg_signature_bad);
+    ADD_TEST(test_validate_msg_signature_sender_cert_srvcert);
+    ADD_TEST(test_validate_msg_signature_sender_cert_untrusted);
+    ADD_TEST(test_validate_msg_signature_sender_cert_trusted);
+    ADD_TEST(test_validate_msg_signature_sender_cert_extracert);
+    ADD_TEST(test_validate_msg_signature_sender_cert_absent);
+    ADD_TEST(test_validate_msg_signature_expected_sender);
+    ADD_TEST(test_validate_msg_signature_unexpected_sender);
+    ADD_TEST(test_validate_msg_unprotected_request);
+    ADD_TEST(test_validate_msg_mac_alg_protection);
+    ADD_TEST(test_validate_msg_mac_alg_protection_bad);
+
+    /* Cert path validation tests */
+    ADD_TEST(test_validate_cert_path_ok);
+    ADD_TEST(test_validate_cert_path_expired);
+    ADD_TEST(test_validate_cert_path_wrong_anchor);
+
+    ADD_TEST(test_MSG_check_received_no_protection_no_cb);
+    ADD_TEST(test_MSG_check_received_no_protection_restrictive_cb);
+    ADD_TEST(test_MSG_check_received_no_protection_permissive_cb);
+    ADD_TEST(test_MSG_check_received_check_transaction_id);
+    ADD_TEST(test_MSG_check_received_check_transaction_id_bad);
+    ADD_TEST(test_MSG_check_received_check_recipient_nonce);
+    ADD_TEST(test_MSG_check_received_check_recipient_nonce_bad);
+
+    return 1;
+
+ err:
+    cleanup_tests();
+    return 0;
+
+}
diff --git a/test/recipes/65-test_cmp_vfy.t b/test/recipes/65-test_cmp_vfy.t
new file mode 100644 (file)
index 0000000..c07e693
--- /dev/null
@@ -0,0 +1,36 @@
+#! /usr/bin/env perl
+# 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
+
+use strict;
+use OpenSSL::Test qw/:DEFAULT data_file/;
+use OpenSSL::Test::Utils;
+
+setup("test_cmp_vfy");
+
+plan skip_all => "This test is not supported in a no-cmp build"
+    if disabled("cmp");
+
+plan skip_all => "This test is not supported in a no-ec build"
+    if disabled("ec");
+
+plan tests => 1;
+
+ok(run(test(["cmp_vfy_test",
+             data_file("server.crt"),     data_file("client.crt"),
+             data_file("EndEntity1.crt"), data_file("EndEntity2.crt"),
+             data_file("Root_CA.crt"),    data_file("Intermediate_CA.crt"),
+             data_file("IR_protected.der"),
+             data_file("IR_unprotected.der"),
+             data_file("IP_waitingStatus_PBM.der"),
+             data_file("IR_rmprotection.der"),
+             data_file("insta.cert.pem"),
+             data_file("insta_ca.cert.pem"),
+             data_file("IR_protected_0_extraCerts.der"),
+             data_file("IR_protected_2_extraCerts.der")])));
diff --git a/test/recipes/65-test_cmp_vfy_data/EndEntity1.crt b/test/recipes/65-test_cmp_vfy_data/EndEntity1.crt
new file mode 100644 (file)
index 0000000..4e05449
--- /dev/null
@@ -0,0 +1,16 @@
+-----BEGIN CERTIFICATE-----
+MIICnDCCAYSgAwIBAgIBAzANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdSb290
+IENBMB4XDTE3MTEwODE1NDgwMFoXDTE4MTEwODExMTkwMFowETEPMA0GA1UEAxMG
+Q2xpZW50MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtNiWJufEotHe
+p6E/4b0laX7K1NRamNoUokLIsq78RoBieBXaGxIdbT6zmhLnLmZdb0UN3v7FUP75
+rqPN2yyj3TbS4o5ilh5El8bDDAPhW5lthCddvH/uBziRAM5oIB4xxOumNbgHpLUT
+Clh49sdXd4ydYpCTWld5emRouBmMUeP/0EkyWMBIrHGSBxrqtFVRXhxvVHImQv6Z
+hIKql7dCVCZbhUtxw6sLxIGL4xlhKoM2o31k4I/9tjZrWSZZ7KAIOlOLrjxZc/bQ
+MwvxVUgS+C+iXzhCY8v+N/K37jwtAAk4C1aOGv/VygNcN0C/ynfKSzFmtnfei4+3
+6GC7HtFzewIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQB3GYpPSCCYsJM5owKcODr/
+I1aJ8jQ+u5jCKjvYLp6Cnbr4AbRXzvKuMyV6UfIAQbrGOxAClvX++5/ZQbhY+TxN
+iiUM3yr5yYCLqj4MeYHhJ3gOzcppAO9LQ9V7eA8C830giZMm3cpApFSLP8CpwNUD
+W/fgoQfaOae5IYPZdea88Gmt5RVNbtHgVqtm4ifTQo577kfxTeh20s+M6pgYW3/R
+vftXy2ITEtk/j3NcRvOyZ7Bu1mAg7wNeUjL+gDWAaxs16LsWsCsUGwfr/Z2Rq1CF
+zB0XwIyigkVLDLqDzUShcw0Eb/zYy2KXsxNWA2tb27mw+T+tmmOszpn7JjLrlVks
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_vfy_data/EndEntity2.crt b/test/recipes/65-test_cmp_vfy_data/EndEntity2.crt
new file mode 100644 (file)
index 0000000..ba06210
--- /dev/null
@@ -0,0 +1,13 @@
+-----BEGIN CERTIFICATE-----
+MIIB3zCCAZSgAwIBAgIBBjAKBggqhkjOPQQDAzAVMRMwEQYDVQQDEwpad2lzY2hl
+bkNBMB4XDTE3MTEwODE2MDUwMFoXDTE4MTEwODExMTkwMFowEjEQMA4GA1UEAxMH
+Q2xpZW50MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALTYlibnxKLR
+3qehP+G9JWl+ytTUWpjaFKJCyLKu/EaAYngV2hsSHW0+s5oS5y5mXW9FDd7+xVD+
++a6jzdsso9020uKOYpYeRJfGwwwD4VuZbYQnXbx/7gc4kQDOaCAeMcTrpjW4B6S1
+EwpYePbHV3eMnWKQk1pXeXpkaLgZjFHj/9BJMljASKxxkgca6rRVUV4cb1RyJkL+
+mYSCqpe3QlQmW4VLccOrC8SBi+MZYSqDNqN9ZOCP/bY2a1kmWeygCDpTi648WXP2
+0DML8VVIEvgvol84QmPL/jfyt+48LQAJOAtWjhr/1coDXDdAv8p3yksxZrZ33ouP
+t+hgux7Rc3sCAwEAAaMNMAswCQYDVR0TBAIwADAKBggqhkjOPQQDAwM5ADA2AhkA
+qASBLwTauET6FGp/EBe7b/99jTyGB861AhkA5ILGkLX4KmjRkTcNxJ3JKB1Sumya
+cbqF
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_vfy_data/IP_waitingStatus_PBM.der b/test/recipes/65-test_cmp_vfy_data/IP_waitingStatus_PBM.der
new file mode 100644 (file)
index 0000000..76888e8
Binary files /dev/null and b/test/recipes/65-test_cmp_vfy_data/IP_waitingStatus_PBM.der differ
diff --git a/test/recipes/65-test_cmp_vfy_data/IP_waitingStatus_PBM.txt b/test/recipes/65-test_cmp_vfy_data/IP_waitingStatus_PBM.txt
new file mode 100644 (file)
index 0000000..8983797
--- /dev/null
@@ -0,0 +1,2 @@
+Reference#:   4787
+Secret Value: 9pp8-b35i-Xd3Q-udNR
diff --git a/test/recipes/65-test_cmp_vfy_data/IR_protected.der b/test/recipes/65-test_cmp_vfy_data/IR_protected.der
new file mode 100644 (file)
index 0000000..ce0a7a4
Binary files /dev/null and b/test/recipes/65-test_cmp_vfy_data/IR_protected.der differ
diff --git a/test/recipes/65-test_cmp_vfy_data/IR_protected_0_extraCerts.der b/test/recipes/65-test_cmp_vfy_data/IR_protected_0_extraCerts.der
new file mode 100755 (executable)
index 0000000..1c26028
Binary files /dev/null and b/test/recipes/65-test_cmp_vfy_data/IR_protected_0_extraCerts.der differ
diff --git a/test/recipes/65-test_cmp_vfy_data/IR_protected_2_extraCerts.der b/test/recipes/65-test_cmp_vfy_data/IR_protected_2_extraCerts.der
new file mode 100755 (executable)
index 0000000..56faad4
Binary files /dev/null and b/test/recipes/65-test_cmp_vfy_data/IR_protected_2_extraCerts.der differ
diff --git a/test/recipes/65-test_cmp_vfy_data/IR_rmprotection.der b/test/recipes/65-test_cmp_vfy_data/IR_rmprotection.der
new file mode 100644 (file)
index 0000000..e84c64d
Binary files /dev/null and b/test/recipes/65-test_cmp_vfy_data/IR_rmprotection.der differ
diff --git a/test/recipes/65-test_cmp_vfy_data/IR_unprotected.der b/test/recipes/65-test_cmp_vfy_data/IR_unprotected.der
new file mode 100644 (file)
index 0000000..41a6496
Binary files /dev/null and b/test/recipes/65-test_cmp_vfy_data/IR_unprotected.der differ
diff --git a/test/recipes/65-test_cmp_vfy_data/Intermediate_CA.crt b/test/recipes/65-test_cmp_vfy_data/Intermediate_CA.crt
new file mode 100644 (file)
index 0000000..3416cdb
--- /dev/null
@@ -0,0 +1,12 @@
+-----BEGIN CERTIFICATE-----
+MIIB1jCBv6ADAgECAgEFMA0GCSqGSIb3DQEBDQUAMBIxEDAOBgNVBAMTB1Jvb3Qg
+Q0EwHhcNMTcxMTA4MTYwNDAwWhcNMTgxMTA4MTExOTAwWjAVMRMwEQYDVQQDEwpa
+d2lzY2hlbkNBMEkwEwYHKoZIzj0CAQYIKoZIzj0DAQEDMgAE9bJcmZWj2CmO6aW8
+9Qylkj1WgPREf9/s4Z1VYqFODeJnebPXFBLVH/aoGxnds9E9oxAwDjAMBgNVHRME
+BTADAQH/MA0GCSqGSIb3DQEBDQUAA4IBAQBwQD4NTIWMMevEsSrBpKjjQEWc81Ct
+eXoyAXr/d8wgVyuIZe9C7ekxPQCwowcmONUyeYQv9N2eYpdhkAQuk6DS4+aDR4s7
+I6rg5R5CUGGla5NUxM0BKIS3ZIezvEGlP1NFN+HBgJI7ZIIYQ3zDr0EYgo4J7Xvm
+5p58pcCZSsbVyKwKs6T+rTzOVVmJ2L1bWzywZEDmzxMkPmA6fP9XtB4Kx/b4oviw
+TEQl3Jf9EkBvBkKX2rRJs7aMJo4MwOnE4HHOV5GAQqhGrXltsuXmVfIQPtRN4xlK
+oNf/FukI1NcBh4A/iY4PmbyxHYmKy6qjFjng2u2VFtH15HDT4XlLP5gq
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_vfy_data/Root_CA.crt b/test/recipes/65-test_cmp_vfy_data/Root_CA.crt
new file mode 100644 (file)
index 0000000..6ccf362
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICrzCCAZegAwIBAgIBATANBgkqhkiG9w0BAQUFADASMRAwDgYDVQQDEwdSb290
+IENBMB4XDTE3MTEwODE1NDUwMFoXDTE4MTEwODExMTkwMFowEjEQMA4GA1UEAxMH
+Um9vdCBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALiHdLAD2Wu+
+C5UDMK6WCL53Wz0CeU61RRRlGEVSqHrQOWnffgVutgftzsddxxgJJyGsqKo1B+nQ
+vapyJyugYJWYNQLN5+iffe4y1UBPnHMQFHiZ4cNR6PB0eHja2wpcN3QmJzOcpRYE
+xf+QQwJNFqhRi0cZGfd/JfFi/ybJalqClbnYMPcJo7g6S7M3lWbOnEOUWnbM2EBp
+h849mC+kd80vXcRcb7U/3MJKK3Ee72TDye5/kWFf9zcxj2ac0oCiS66JKYobiVJr
+NmbGM0I9U6T6ejXVUu2J3pGUFlcf3RCUYf1aWhkmzEzbm/FGMRJ7vVyCXm/OWIh9
+bqtwH5YfljsCAwEAAaMQMA4wDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOC
+AQEAF7tSa9oVan7kPR5/TXB330Ca1xQt5C38afaJbacR9mM8ZkL0HceQTuJGrnAR
+4kK7CaB5iraU6Lxyql7drq8aixz/7TXna6c172J6HxDeFhQMeSt1LAh7XN5Ir6Y6
+iO7XD5I5lw3Xv6qvhoD0ktkNk/WtF7aBw2ZAi+RcDMgWzWjoS4WqMbvWEHw10j9b
+s8R0YG4yi6wb89UNIMfQtC2XviHKcRS9MzIJQHw73r2EY2t6o9TO+5ukHYDB6/Zo
+/CLXu21MzsFvhupHgX6zdptU324tq2za1+4LvmOHSW+D36jEPT22SndXmHo5VmAn
+6bQ52MhBI0rrWwju9aBpVzsUUg==
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_vfy_data/chain.txt b/test/recipes/65-test_cmp_vfy_data/chain.txt
new file mode 100644 (file)
index 0000000..1b55c25
--- /dev/null
@@ -0,0 +1,4 @@
+1 - Root_CA (self-signed)
+1.1 - EndEntity1
+1.2 Intermediate_CA
+1.2.1 EndEntity2
diff --git a/test/recipes/65-test_cmp_vfy_data/client.crt b/test/recipes/65-test_cmp_vfy_data/client.crt
new file mode 100644 (file)
index 0000000..fa6cdec
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICtTCCAZ2gAwIBAgIBATANBgkqhkiG9w0BAQUFADAeMRwwGgYDVQQKExNjbGll
+bnQgb3JnYW5pemF0aW9uMB4XDTE4MDIwNjEyNDYwMFoXDTE5MDIwNjEyNDYwMFow
+HjEcMBoGA1UEChMTY2xpZW50IG9yZ2FuaXphdGlvbjCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBALf0KDl07RlJlQVQcibB+JiUyXthFz4nzIkFVNISORCG
+JpTUMLLWxhF7Sc1li7gzvMAvx77SUThaNEOd0d2MJBbOXmZ9MtAOy8yHzRejBpw1
+mn9e0FKCI8rz3ttivspsGUIsRDhvMxuOol3lQ93QjfI593D7BOfBGdhsivD8m6+P
+EzF400iOSsbo3VPlArA+xTHiCyJ+E9p3yFGvzQrmK/MjM3lW3l3tARJmbXINIOio
+PnVmh4nsc9awqDGQdQTup/EjuY15AR4Vck7Zf9e+6U9t7Ow7aaZ5gX07FNnnqlVs
+48Lj/5a2Qgh482SQNvvRWAkPwTQNZ40ThKvOR/sB3iUCAwEAATANBgkqhkiG9w0B
+AQUFAAOCAQEAUSZBAR22ICoO7oPKMpfxwIHDAODv6jEHx2fSTpwxqodVqwF8ghAS
+PvJwQ4+7+yny4ieX9iVicRdXXT8kEOQL5/3/Q+cBj/BzYE0VGxo4YloHQwWNdSg0
+B1oQ/4dAnDntGnXHDJMSZCGq/jj4/56XSrPymzR2jgOQNqnEkMM9/SpW7MirixJA
+ZBR5Oc97vKaAH89ucsTu0neVMTXgywdBiy1W8bo4XxquK6VDRHlLj4gMLBpaG0mW
+r5ST1gs8j63nK/eZ7AuTV/tvI25reXT+2wOKAgPEcd02Fh61TO4IPD4GDidEHvAw
+6m66U9eFVezkxDvjE0X5voFnsBl4qTSZ/A==
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_vfy_data/insta.cert.pem b/test/recipes/65-test_cmp_vfy_data/insta.cert.pem
new file mode 100755 (executable)
index 0000000..4a25699
--- /dev/null
@@ -0,0 +1,25 @@
+-----BEGIN CERTIFICATE-----
+MIIEHTCCAwWgAwIBAgIEBtqJKDANBgkqhkiG9w0BAQsFADA6MQswCQYDVQQGEwJG
+STETMBEGA1UECgwKSW5zdGEgRGVtbzEWMBQGA1UEAwwNSW5zdGEgRGVtbyBDQTAe
+Fw0xODAxMzAxMDE0MjNaFw0xODA0MzAyMzU5NTlaMBAxDjAMBgNVBAMMBXRlc3Qx
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAoiNNxo5pwk1lD1em3mad
+bpKz86GSYyGlQtd0ZhIX1tOUFo9lFex7n5Osv0A99pKb+7EKqB9Ghg6mJ29kIUUm
+LACnfZJ/q+U6s9T4zFrYyXweUNJvQgbA2ojDPyVoRp2T1ekahPh4DpxPWNKfYECD
+RbrxkHMM3WiIqYFLU8hYvEMGSWRHHbnS/vG7MTaVDkR8d0zixTOp0fST5c1UUTqp
+pYlThac/BG1kk3hyjIjz5o7lspfX3s/eAYgT9GhYHL6Uy4o4OqCleR39aVc0dMrr
+jb7hsmX6ecNwqJOE5AHHOG4Ti6CbweSOcdH5PRFzdpao5rlTErsFHlUSTca4mfVe
+WwIDAQABo4IBUzCCAU8wHwYDVR0jBBgwFoAUPHjduMGNV/UFKl5t4FhySvpEJWEw
+HQYDVR0OBBYEFD0oLwov3vSGa1f9bIKGzWoPP0A1MCcGA1UdEQQgMB6CBGFiLmOC
+BGRlLmaCBHRlc3SHBAECA/+HBAQFBgcweAYDVR0fBHEwbzBtoGugaYZnbGRhcDov
+L3BraS5jZXJ0aWZpY2F0ZS5maTozODkvQ049SW5zdGElMjBEZW1vJTIwQ0EsTz1J
+bnN0YSUyMERlbW8sQz1GST9jZXJ0aWZpY2F0ZVJldm9jYXRpb25MaXN0O2JpbmFy
+eTBqBggrBgEFBQcBAQReMFwwWgYIKwYBBQUHMAKGTmxkYXA6Ly93d3cuY2VydGlm
+aWNhdGUuZmk6Mzg5L0NOPUluc3RhIERlbW8gQ0EsTz1JbnN0YSBEZW1vLEM9Rkk/
+Y2FDZXJ0aWZpY2F0ZTANBgkqhkiG9w0BAQsFAAOCAQEAbIRfAbU0v2RWZg6lkjZg
+58fi4lT7Xk64sK4G/QLZ8TR/jg5UR0J5IvYt52YBjs/tjwJokkaW7+DyhVKkPrGs
+oexpdLRSnXBv33+Yj+MZbSfrIX1Ox7up+ovs8le4viSlUqIDWBuuUBfZ16BFMmnB
+UwDar8p/ci9ReKJH+FmvxlHbTHdMznZooSxTZm96HTutuiULL/SzZ2FpUsd7G5EE
+mRA6uRVV1tuysD15H+9paqVwd0RaKee8Z63cDi3NXOxUcCnpINHrjVsdcW47/73V
+IgfU4t39BKNiQNL0ADYpCyrpntTpsyZWrNmYzXMgLYEXxi4s6obusY0I3Qg+U31o
+Uw==
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_vfy_data/insta.priv.pem b/test/recipes/65-test_cmp_vfy_data/insta.priv.pem
new file mode 100755 (executable)
index 0000000..8612994
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEpQIBAAKCAQEAoiNNxo5pwk1lD1em3madbpKz86GSYyGlQtd0ZhIX1tOUFo9l
+Fex7n5Osv0A99pKb+7EKqB9Ghg6mJ29kIUUmLACnfZJ/q+U6s9T4zFrYyXweUNJv
+QgbA2ojDPyVoRp2T1ekahPh4DpxPWNKfYECDRbrxkHMM3WiIqYFLU8hYvEMGSWRH
+HbnS/vG7MTaVDkR8d0zixTOp0fST5c1UUTqppYlThac/BG1kk3hyjIjz5o7lspfX
+3s/eAYgT9GhYHL6Uy4o4OqCleR39aVc0dMrrjb7hsmX6ecNwqJOE5AHHOG4Ti6Cb
+weSOcdH5PRFzdpao5rlTErsFHlUSTca4mfVeWwIDAQABAoIBAQCUYAZevBjgbP8c
+qTPVtsY/WBVB0Qwrl7CqmIy2k7wpJfoRIyx4ga8n+3ZMlredm9EO5ZdA/04EhAdd
+czyIjcU+42JjMduQLPgpda4xJLnauLDteYXDQHbgBePXN55TcQTG7skMAm2rwTOD
+r0uWQ7Nd7pP9gqu1OmJF7EJI68D4llCU1FrOrliwSDzHWP3p4QmCW3M9PQJ68xw1
+gE7X1QflROGivcFoRgcgeoJDzpxveGvPbEn6Q+05/FMRVxjqWhpxdZ9/SL7iRz1e
+45T+P9a8OLgTyErT3Lp/f/vuHA1tlbAYumhSnxXsb+nHi80aDcImOrNQHAp076Ik
+bkZ1NpOxAoGBAM3Ulgi2hUPdoAMFtHZF8eBHRzn+4uTfY2s33wObiUJQ8VbGDeJY
+ifCfOwLThiAXAqktrs7ItwWDYmzd5xPYGQeWoKcBEoZ+dvaaOe8H7TCMnjB3R3i1
+ACSDHo/3c+NfFOnPJtXL85jeAqGYH50uOtYmYaBVe6xASTBgNvP7snYHAoGBAMmo
+ZBQqgIhoqMRapGh6n4OpzH0Nt9ruOTJoteAfbLdAu7X+wAaMuxEaAmZQRDYj0lzX
+Ty8DlKSy7vfvXtghxMBEv4+dsYpagXcUOeEZSPfu1c3e253dAov6C0MdREKWBT7P
++NwPBowPy0CP/yBeHaw7d/P7/SYIoPXLGraGl6ANAoGBAMmmce7LUjgw0mjjl+8f
+i14cts08x3FO4YnTTOut34VW43oNwuBzuYBBn4CfVpHtuS+hj9cKkTQXib/6jj7E
+wZDLo0y6Ijodf9MNOaDSdS/RM9Frqlu5iBA9XR3SYnjpWAXQas2eaGLlblJ+RMqq
+1f2j0JVR6j3RJWL9gBj8B9TVAoGBALYZrs4bF1iXEhfGNoL2gIdX1QX0VluIFfR0
+ZBDQr87H0Ppm4qbHfMHTt+kGgKJXNMaL08CDvj4AKxWPfhk0XUS2kDmzUDi8w/5x
+MFcaCy+A6Gdw4OcsRfl7QaJIknSCnpf7HCI0G1hthsB1iBCFjMwUI50ap54p2pg6
+4ZOD9PYdAoGAERi5Hlq7+rJeDi3VunKHySqV9mvbOPNclEUmAdKi1yuu3INF1Zgv
+Lf432ZI/Ufk2g888ed5ZGE1IMULc2tgSIAMzdX4ZYI4uGFLkHWzSOM6a7NCeZuVt
+W+NgUYa2qsqFEd9kqaoDbNry+nPvLM7fWXvBoE4oNkeJhHjOIabBPvw=
+-----END RSA PRIVATE KEY-----
diff --git a/test/recipes/65-test_cmp_vfy_data/insta_ca.cert.pem b/test/recipes/65-test_cmp_vfy_data/insta_ca.cert.pem
new file mode 100755 (executable)
index 0000000..4b7e31b
--- /dev/null
@@ -0,0 +1,22 @@
+-----BEGIN CERTIFICATE-----
+MIIDkDCCAnigAwIBAgIDCZU1MA0GCSqGSIb3DQEBBQUAMDoxCzAJBgNVBAYTAkZJ
+MRMwEQYDVQQKEwpJbnN0YSBEZW1vMRYwFAYDVQQDEw1JbnN0YSBEZW1vIENBMB4X
+DTA2MDEwMjA4NDgzOFoXDTI1MTIzMTA4NDgzOFowOjELMAkGA1UEBhMCRkkxEzAR
+BgNVBAoTCkluc3RhIERlbW8xFjAUBgNVBAMTDUluc3RhIERlbW8gQ0EwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDF57bSwj+hZnkgLyLtFsoNIN19qBv9
+GIoqFaCiPvw6VQgMXR15t+Z5sdYHdydGp875yJD4wDq2K7cjMoCXALxLeyp6dCY6
+WPC6Hk3QvZtMRuDAz8+0Nb5qaC4+O+7c7j1h/Gs8Jpj+TUuSkmtlCVIGPSWkWaQl
+FhLWeUnKRW8bj1CJQguV7igF19kGQKUZ/VZj+n5xIXKHc8njC1ZrS/s0IBFViQkZ
+63nTdNPLHQ4Xu8uKrbJbYEK1S4KVNH3L9yA4ut+brqX8n6OulTsKntvMdwNWZdor
+KoM15D3lmM7QUGDflJdSQ/qvBVTda+ccrT21sp4hdwwiU01vxQguT26JAgMBAAGj
+gZ4wgZswHwYDVR0jBBgwFoAUPHjduMGNV/UFKl5t4FhySvpEJWEwHQYDVR0OBBYE
+FDx43bjBjVf1BSpebeBYckr6RCVhMA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8E
+CDAGAQH/AgEAMDUGCWCGSAGG+EIBDQQoFiZJbnN0YSBEZW1vIENBIC0gb25seSBm
+b3IgZGVtbyBwdXJwb3NlczANBgkqhkiG9w0BAQUFAAOCAQEAuVRmRimTxVTZMNXi
+3u4bRCq7GxJ4Lonx3mocxYiwBjCYwqn5dPAd4AHrA1HWYCEvIPo52FibpUNNljqH
+v7CSoEBg2f4If6cFtwudobqNvf8Z50CAnxlwpPy4k+EbXlh49/uZBtu8+Lc2Ss7L
+QaNHHiOeHxYeGX7pTcr6fnXQWAbbn4SLyqniW7ZTqjNJvC79Ym7KowMYzCbmozzv
+3xqElA+g/MLFfxn52c/vl/obOVk5eBf3f7V68qKL2IDEip3fyZyoelhfTypq944m
+sSJFQjoVzgd7ykgouEwOceOT8YMWWigNsWl/hsVJ03Ri7TxRX4+v8dMEbat+SsTL
+AqTTgQ==
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_vfy_data/server.crt b/test/recipes/65-test_cmp_vfy_data/server.crt
new file mode 100644 (file)
index 0000000..ed1d433
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICpTCCAY2gAwIBAgIBATANBgkqhkiG9w0BAQUFADAWMRQwEgYDVQQKDAtvcGVu
+c3NsX2NtcDAeFw0xNzEyMjAxMzA0MDBaFw0xODEyMjAxMzA0MDBaMBYxFDASBgNV
+BAoMC29wZW5zc2xfY21wMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA
+4ckRrH0UWmIJFj99kBqvCipGjJRAaPkdvWjdDQLglTpI3eZAJHnq0ypW/PZccrWj
+o7mxuvAStEYWF+5Jx6ZFmAsC1K0NNebSAZQoLWYZqiOzkfVVpLicMnItNFElfCoh
+BzPCYmF5UlC5yp9PSUEfNwPJqDIRMtw+IlVUV3AJw9TJ3uuWq/vWW9r96/gBKKdd
+mj/q2gGT8RC6LxEaolTbhfPbHaA1DFpv1WQFb3oAV3Wq14SOZf9bH1olBVsmBMsU
+shFEw5MXVrNCv2moM4HtITMyjvZe7eIwHzSzf6dvQjERG6GvZ/i5KOhaqgJCnRKd
+HHzijz9cLec5p9NSOuC1OwIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQDGUXpFCBkV
+WgPrBfZyBwt6VCjWB/e67q4IdcKMfDa4hwSquah1AyXHI0PlC/qitnoSx2+7f7pY
+TEOay/3eEPUl1J5tdPF2Vg56Dw8jdhSkMwO7bXKDEE3R6o6jaa4ECgxwQtdGHmNU
+A41PgKX76yEXku803ptO39/UR7i7Ye3MbyAmWE+PvixJYUbxd3fqz5fsaJqTCzAy
+AT9hrr4uu8J7m3LYaYXo4LVL4jw5UsP5bIYtpmmEBfy9GhpUqH5/LzBNij7y3ziE
+T59wHkzawAQDHsBPuCe07DFtlzqWWvaih0TQAw9MZ2tbyK9jt7P80Rqt9CwpM/i9
+jQYqSl/ix5hn
+-----END CERTIFICATE-----
diff --git a/test/recipes/65-test_cmp_vfy_data/server.key b/test/recipes/65-test_cmp_vfy_data/server.key
new file mode 100644 (file)
index 0000000..2324266
--- /dev/null
@@ -0,0 +1,27 @@
+-----BEGIN RSA PRIVATE KEY-----
+MIIEowIBAAKCAQEA4ckRrH0UWmIJFj99kBqvCipGjJRAaPkdvWjdDQLglTpI3eZA
+JHnq0ypW/PZccrWjo7mxuvAStEYWF+5Jx6ZFmAsC1K0NNebSAZQoLWYZqiOzkfVV
+pLicMnItNFElfCohBzPCYmF5UlC5yp9PSUEfNwPJqDIRMtw+IlVUV3AJw9TJ3uuW
+q/vWW9r96/gBKKddmj/q2gGT8RC6LxEaolTbhfPbHaA1DFpv1WQFb3oAV3Wq14SO
+Zf9bH1olBVsmBMsUshFEw5MXVrNCv2moM4HtITMyjvZe7eIwHzSzf6dvQjERG6Gv
+Z/i5KOhaqgJCnRKdHHzijz9cLec5p9NSOuC1OwIDAQABAoIBAGiYVO+rIfqc38jG
+sMxJED2NSBFnvE7k2LoeEgktBA0daxQgziYXtIkOXC3jkwAw1RXLuGH5RTDuJt3/
+LX6nsCW3NCCB6lTGERNaJyKg4dLHpzA+juY3/2P/MKHD1bGncpV7jNk2fpV7gBY1
+pu0wld1Oi+S3DPCaxs3w6Zl39Y4Z7oSNf6DRO5lGN3Asc8TSVjIOWpAl8LIg+P2B
+ZvFeHRANVXaV9YmF2uEi7iMgH4vGrK2svsmM9VThVO4ArGcTRTvGYn7aw3/H4Pt+
+lYuhERdpkKBT0tCgIpO5IJXMl4/5RSDTtcBwiJcReN5IHUAItBIPSHcMflNSKG/I
+aQf4u0ECgYEA8+PAyzn096Y2UrKzE75yuadCveLjsUWx2NN5ZMohQru99F4k7Pab
+/Te4qOe5zlxHAPK3LRwvbwUWo5mLfs45wFrSgZoRlYcCuL+JaX0y2oXMMF9E+UkY
+tljMt/HpLo1SfSjN2Sae4LVhC7rWJ43LtyRepptzBPGqd26eLPGAMr8CgYEA7P8u
+RGkMOrMzEKAb0A9smrzq2xW88T1VejqEt6R8mUcNt8PFHMgjuzVU4zDysrlb7G/0
+VSkQWnJxBh1yNGc1Av7YgwicIgApr4ty0hZhLcnKX2VrNw+L/sSe/cnwVAc6RtPK
+RR6xQubuLlrCGcbYXmyn5Jv+nlY0S3uCyDFHqIUCgYAwtpLxhJf7RwWeqva9wNJl
+ZpUcHE9iPwtwxXx/tyfBjoI4Zv11HyS1BQYrJm2kXCYKeHBB4FlREXEeKDMGluZO
+F1XocP+GIDtY71jg6xLXNtY76yt5pzH6ae4p53WtyKhrO1UyRFaDh3bkwuK3b8j6
+wZbuLCpjGGn2BPAvBeWXPQKBgEewKN6op/pZmmi9Bay5/bAQ1TnQKYcPdnuyl9K0
+/ruespeTsFw0bhqC11qhw8gsKZIri0z3TusNEwM2hQU08uQlEnkQcaoXQoTHOcQy
+4NJo575Tf0r4ePBnqXA7VWcViJtEFTszPYtvLzz2VyBU9b4aP+73AN4EVW0/vx+v
+SG3BAoGBAMzESFA2TXwUFmozK5zowIszc995Xqpi7mXKk77WESOpoS1dQ1wF1dSg
+XOwxzFoYovLxcc1K9lqOrod8BV+qGuEfc/PIJ2aiXjvEDeZYX2eWaANNmj4OSLoJ
+MNYj9tZxbq56slD7snf7AgUBnwKz0Pj6H6UsbE3gdJqZWCDyw/bB
+-----END RSA PRIVATE KEY-----
index 380a2d2..9029688 100644 (file)
@@ -4928,3 +4928,10 @@ OSSL_HTTP_get_asn1                      ?        3_0_0   EXIST::FUNCTION:SOCK
 OSSL_HTTP_post_asn1                     ?      3_0_0   EXIST::FUNCTION:SOCK
 OSSL_HTTP_transfer                      ?      3_0_0   EXIST::FUNCTION:SOCK
 OSSL_HTTP_proxy_connect                 ?      3_0_0   EXIST::FUNCTION:SOCK
+ERR_add_error_txt                       ?      3_0_0   EXIST::FUNCTION:
+ERR_add_error_mem_bio                   ?      3_0_0   EXIST::FUNCTION:
+X509_STORE_CTX_print_verify_cb          ?      3_0_0   EXIST::FUNCTION:
+X509_STORE_get1_all_certs               ?      3_0_0   EXIST::FUNCTION:
+OSSL_CMP_validate_msg                   ?      3_0_0   EXIST::FUNCTION:CMP
+OSSL_CMP_validate_cert_path             ?      3_0_0   EXIST::FUNCTION:CMP
+OSSL_CMP_print_to_bio                   ?      3_0_0   EXIST::FUNCTION:CMP