mirror of
https://github.com/openssl/openssl.git
synced 2025-01-18 13:44:20 +08:00
c5dc9ab965
The ASN1_STRING_get0_data(3) manual explitely cautions the reader that the data is not necessarily NUL-terminated, and the function X509_alias_set1(3) does not sanitize the data passed into it in any way either, so we must assume the return value from X509_alias_get0(3) is merely a byte array and not necessarily a string in the sense of the C language. I found this bug while writing manual pages for X509_print_ex(3) and related functions. Theo Buehler <tb@openbsd.org> checked my patch to fix the same bug in LibreSSL, see http://cvsweb.openbsd.org/src/lib/libcrypto/asn1/t_x509a.c#rev1.9 As an aside, note that the function still produces incomplete and misleading results when the data contains a NUL byte in the middle and that error handling is consistently absent throughout, even though the function provides an "int" return value obviously intended to be 1 for success and 0 for failure, and even though this function is called by another function that also wants to return 1 for success and 0 for failure and even does so in many of its code paths, though not in others. But let's stay focussed. Many things would be nice to have in the wide wild world, but a buffer overflow must not be allowed to remain in our backyard. CLA: trivial Reviewed-by: Tim Hudson <tjh@openssl.org> Reviewed-by: Paul Dale <pauli@openssl.org> Reviewed-by: Tomas Mraz <tomas@openssl.org> (Merged from https://github.com/openssl/openssl/pull/16108)
530 lines
16 KiB
C
530 lines
16 KiB
C
/*
|
|
* Copyright 1995-2021 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
|
|
* https://www.openssl.org/source/license.html
|
|
*/
|
|
|
|
#include <stdio.h>
|
|
#include "internal/cryptlib.h"
|
|
#include <openssl/buffer.h>
|
|
#include <openssl/bn.h>
|
|
#include <openssl/objects.h>
|
|
#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)
|
|
{
|
|
return X509_print_ex_fp(fp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
|
|
}
|
|
|
|
int X509_print_ex_fp(FILE *fp, X509 *x, unsigned long nmflag,
|
|
unsigned long cflag)
|
|
{
|
|
BIO *b;
|
|
int ret;
|
|
|
|
if ((b = BIO_new(BIO_s_file())) == NULL) {
|
|
ERR_raise(ERR_LIB_X509, ERR_R_BUF_LIB);
|
|
return 0;
|
|
}
|
|
BIO_set_fp(b, fp, BIO_NOCLOSE);
|
|
ret = X509_print_ex(b, x, nmflag, cflag);
|
|
BIO_free(b);
|
|
return ret;
|
|
}
|
|
#endif
|
|
|
|
int X509_print(BIO *bp, X509 *x)
|
|
{
|
|
return X509_print_ex(bp, x, XN_FLAG_COMPAT, X509_FLAG_COMPAT);
|
|
}
|
|
|
|
int X509_print_ex(BIO *bp, X509 *x, unsigned long nmflags,
|
|
unsigned long cflag)
|
|
{
|
|
long l;
|
|
int ret = 0, i;
|
|
char *m = NULL, mlch = ' ';
|
|
int nmindent = 0, printok = 0;
|
|
EVP_PKEY *pkey = NULL;
|
|
const char *neg;
|
|
|
|
if ((nmflags & XN_FLAG_SEP_MASK) == XN_FLAG_SEP_MULTILINE) {
|
|
mlch = '\n';
|
|
nmindent = 12;
|
|
}
|
|
|
|
if (nmflags == X509_FLAG_COMPAT) {
|
|
nmindent = 16;
|
|
printok = 1;
|
|
}
|
|
|
|
if (!(cflag & X509_FLAG_NO_HEADER)) {
|
|
if (BIO_write(bp, "Certificate:\n", 13) <= 0)
|
|
goto err;
|
|
if (BIO_write(bp, " Data:\n", 10) <= 0)
|
|
goto err;
|
|
}
|
|
if (!(cflag & X509_FLAG_NO_VERSION)) {
|
|
l = X509_get_version(x);
|
|
if (l >= X509_VERSION_1 && l <= X509_VERSION_3) {
|
|
if (BIO_printf(bp, "%8sVersion: %ld (0x%lx)\n", "", l + 1, (unsigned long)l) <= 0)
|
|
goto err;
|
|
} else {
|
|
if (BIO_printf(bp, "%8sVersion: Unknown (%ld)\n", "", l) <= 0)
|
|
goto err;
|
|
}
|
|
}
|
|
if (!(cflag & X509_FLAG_NO_SERIAL)) {
|
|
const ASN1_INTEGER *bs = X509_get0_serialNumber(x);
|
|
|
|
if (BIO_write(bp, " Serial Number:", 22) <= 0)
|
|
goto err;
|
|
|
|
if (bs->length <= (int)sizeof(long)) {
|
|
ERR_set_mark();
|
|
l = ASN1_INTEGER_get(bs);
|
|
ERR_pop_to_mark();
|
|
} else {
|
|
l = -1;
|
|
}
|
|
if (l != -1) {
|
|
unsigned long ul;
|
|
if (bs->type == V_ASN1_NEG_INTEGER) {
|
|
ul = 0 - (unsigned long)l;
|
|
neg = "-";
|
|
} else {
|
|
ul = l;
|
|
neg = "";
|
|
}
|
|
if (BIO_printf(bp, " %s%lu (%s0x%lx)\n", neg, ul, neg, ul) <= 0)
|
|
goto err;
|
|
} else {
|
|
neg = (bs->type == V_ASN1_NEG_INTEGER) ? " (Negative)" : "";
|
|
if (BIO_printf(bp, "\n%12s%s", "", neg) <= 0)
|
|
goto err;
|
|
|
|
for (i = 0; i < bs->length; i++) {
|
|
if (BIO_printf(bp, "%02x%c", bs->data[i],
|
|
((i + 1 == bs->length) ? '\n' : ':')) <= 0)
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if (!(cflag & X509_FLAG_NO_SIGNAME)) {
|
|
const X509_ALGOR *tsig_alg = X509_get0_tbs_sigalg(x);
|
|
|
|
if (BIO_puts(bp, " ") <= 0)
|
|
goto err;
|
|
if (X509_signature_print(bp, tsig_alg, NULL) <= 0)
|
|
goto err;
|
|
}
|
|
|
|
if (!(cflag & X509_FLAG_NO_ISSUER)) {
|
|
if (BIO_printf(bp, " Issuer:%c", mlch) <= 0)
|
|
goto err;
|
|
if (X509_NAME_print_ex(bp, X509_get_issuer_name(x), nmindent, nmflags)
|
|
< printok)
|
|
goto err;
|
|
if (BIO_write(bp, "\n", 1) <= 0)
|
|
goto err;
|
|
}
|
|
if (!(cflag & X509_FLAG_NO_VALIDITY)) {
|
|
if (BIO_write(bp, " Validity\n", 17) <= 0)
|
|
goto err;
|
|
if (BIO_write(bp, " Not Before: ", 24) <= 0)
|
|
goto err;
|
|
if (ossl_asn1_time_print_ex(bp, X509_get0_notBefore(x), ASN1_DTFLGS_RFC822) == 0)
|
|
goto err;
|
|
if (BIO_write(bp, "\n Not After : ", 25) <= 0)
|
|
goto err;
|
|
if (ossl_asn1_time_print_ex(bp, X509_get0_notAfter(x), ASN1_DTFLGS_RFC822) == 0)
|
|
goto err;
|
|
if (BIO_write(bp, "\n", 1) <= 0)
|
|
goto err;
|
|
}
|
|
if (!(cflag & X509_FLAG_NO_SUBJECT)) {
|
|
if (BIO_printf(bp, " Subject:%c", mlch) <= 0)
|
|
goto err;
|
|
if (X509_NAME_print_ex
|
|
(bp, X509_get_subject_name(x), nmindent, nmflags) < printok)
|
|
goto err;
|
|
if (BIO_write(bp, "\n", 1) <= 0)
|
|
goto err;
|
|
}
|
|
if (!(cflag & X509_FLAG_NO_PUBKEY)) {
|
|
X509_PUBKEY *xpkey = X509_get_X509_PUBKEY(x);
|
|
ASN1_OBJECT *xpoid;
|
|
X509_PUBKEY_get0_param(&xpoid, NULL, NULL, NULL, xpkey);
|
|
if (BIO_write(bp, " Subject Public Key Info:\n", 33) <= 0)
|
|
goto err;
|
|
if (BIO_printf(bp, "%12sPublic Key Algorithm: ", "") <= 0)
|
|
goto err;
|
|
if (i2a_ASN1_OBJECT(bp, xpoid) <= 0)
|
|
goto err;
|
|
if (BIO_puts(bp, "\n") <= 0)
|
|
goto err;
|
|
|
|
pkey = X509_get0_pubkey(x);
|
|
if (pkey == NULL) {
|
|
BIO_printf(bp, "%12sUnable to load Public Key\n", "");
|
|
ERR_print_errors(bp);
|
|
} else {
|
|
EVP_PKEY_print_public(bp, pkey, 16, NULL);
|
|
}
|
|
}
|
|
|
|
if (!(cflag & X509_FLAG_NO_IDS)) {
|
|
const ASN1_BIT_STRING *iuid, *suid;
|
|
X509_get0_uids(x, &iuid, &suid);
|
|
if (iuid != NULL) {
|
|
if (BIO_printf(bp, "%8sIssuer Unique ID: ", "") <= 0)
|
|
goto err;
|
|
if (!X509_signature_dump(bp, iuid, 12))
|
|
goto err;
|
|
}
|
|
if (suid != NULL) {
|
|
if (BIO_printf(bp, "%8sSubject Unique ID: ", "") <= 0)
|
|
goto err;
|
|
if (!X509_signature_dump(bp, suid, 12))
|
|
goto err;
|
|
}
|
|
}
|
|
|
|
if (!(cflag & X509_FLAG_NO_EXTENSIONS)
|
|
&& !X509V3_extensions_print(bp, "X509v3 extensions",
|
|
X509_get0_extensions(x), cflag, 8))
|
|
goto err;
|
|
|
|
if (!(cflag & X509_FLAG_NO_SIGDUMP)) {
|
|
const X509_ALGOR *sig_alg;
|
|
const ASN1_BIT_STRING *sig;
|
|
X509_get0_signature(&sig, &sig_alg, x);
|
|
if (X509_signature_print(bp, sig_alg, sig) <= 0)
|
|
goto err;
|
|
}
|
|
if (!(cflag & X509_FLAG_NO_AUX)) {
|
|
if (!X509_aux_print(bp, x, 0))
|
|
goto err;
|
|
}
|
|
ret = 1;
|
|
err:
|
|
OPENSSL_free(m);
|
|
return ret;
|
|
}
|
|
|
|
int X509_ocspid_print(BIO *bp, X509 *x)
|
|
{
|
|
unsigned char *der = NULL;
|
|
unsigned char *dertmp;
|
|
int derlen;
|
|
int i;
|
|
unsigned char SHA1md[SHA_DIGEST_LENGTH];
|
|
ASN1_BIT_STRING *keybstr;
|
|
const X509_NAME *subj;
|
|
EVP_MD *md = NULL;
|
|
|
|
if (x == NULL || bp == NULL)
|
|
return 0;
|
|
/*
|
|
* display the hash of the subject as it would appear in OCSP requests
|
|
*/
|
|
if (BIO_printf(bp, " Subject OCSP hash: ") <= 0)
|
|
goto err;
|
|
subj = X509_get_subject_name(x);
|
|
derlen = i2d_X509_NAME(subj, NULL);
|
|
if (derlen <= 0)
|
|
goto err;
|
|
if ((der = dertmp = OPENSSL_malloc(derlen)) == NULL)
|
|
goto err;
|
|
i2d_X509_NAME(subj, &dertmp);
|
|
|
|
md = EVP_MD_fetch(x->libctx, SN_sha1, x->propq);
|
|
if (md == NULL)
|
|
goto err;
|
|
if (!EVP_Digest(der, derlen, SHA1md, NULL, md, NULL))
|
|
goto err;
|
|
for (i = 0; i < SHA_DIGEST_LENGTH; i++) {
|
|
if (BIO_printf(bp, "%02X", SHA1md[i]) <= 0)
|
|
goto err;
|
|
}
|
|
OPENSSL_free(der);
|
|
der = NULL;
|
|
|
|
/*
|
|
* display the hash of the public key as it would appear in OCSP requests
|
|
*/
|
|
if (BIO_printf(bp, "\n Public key OCSP hash: ") <= 0)
|
|
goto err;
|
|
|
|
keybstr = X509_get0_pubkey_bitstr(x);
|
|
|
|
if (keybstr == NULL)
|
|
goto err;
|
|
|
|
if (!EVP_Digest(ASN1_STRING_get0_data(keybstr),
|
|
ASN1_STRING_length(keybstr), SHA1md, NULL, md, NULL))
|
|
goto err;
|
|
for (i = 0; i < SHA_DIGEST_LENGTH; i++) {
|
|
if (BIO_printf(bp, "%02X", SHA1md[i]) <= 0)
|
|
goto err;
|
|
}
|
|
BIO_printf(bp, "\n");
|
|
EVP_MD_free(md);
|
|
|
|
return 1;
|
|
err:
|
|
OPENSSL_free(der);
|
|
EVP_MD_free(md);
|
|
return 0;
|
|
}
|
|
|
|
int X509_signature_dump(BIO *bp, const ASN1_STRING *sig, int indent)
|
|
{
|
|
const unsigned char *s;
|
|
int i, n;
|
|
|
|
n = sig->length;
|
|
s = sig->data;
|
|
for (i = 0; i < n; i++) {
|
|
if ((i % 18) == 0) {
|
|
if (i > 0 && BIO_write(bp, "\n", 1) <= 0)
|
|
return 0;
|
|
if (BIO_indent(bp, indent, indent) <= 0)
|
|
return 0;
|
|
}
|
|
if (BIO_printf(bp, "%02x%s", s[i], ((i + 1) == n) ? "" : ":") <= 0)
|
|
return 0;
|
|
}
|
|
if (BIO_write(bp, "\n", 1) != 1)
|
|
return 0;
|
|
|
|
return 1;
|
|
}
|
|
|
|
int X509_signature_print(BIO *bp, const X509_ALGOR *sigalg,
|
|
const ASN1_STRING *sig)
|
|
{
|
|
int sig_nid;
|
|
int indent = 4;
|
|
if (BIO_printf(bp, "%*sSignature Algorithm: ", indent, "") <= 0)
|
|
return 0;
|
|
if (i2a_ASN1_OBJECT(bp, sigalg->algorithm) <= 0)
|
|
return 0;
|
|
|
|
if (sig && BIO_printf(bp, "\n%*sSignature Value:", indent, "") <= 0)
|
|
return 0;
|
|
sig_nid = OBJ_obj2nid(sigalg->algorithm);
|
|
if (sig_nid != NID_undef) {
|
|
int pkey_nid, dig_nid;
|
|
const EVP_PKEY_ASN1_METHOD *ameth;
|
|
if (OBJ_find_sigid_algs(sig_nid, &dig_nid, &pkey_nid)) {
|
|
ameth = EVP_PKEY_asn1_find(NULL, pkey_nid);
|
|
if (ameth && ameth->sig_print)
|
|
return ameth->sig_print(bp, sigalg, sig, indent + 4, 0);
|
|
}
|
|
}
|
|
if (BIO_write(bp, "\n", 1) != 1)
|
|
return 0;
|
|
if (sig)
|
|
return X509_signature_dump(bp, sig, indent + 4);
|
|
return 1;
|
|
}
|
|
|
|
int X509_aux_print(BIO *out, X509 *x, int indent)
|
|
{
|
|
char oidstr[80], first;
|
|
STACK_OF(ASN1_OBJECT) *trust, *reject;
|
|
const unsigned char *alias, *keyid;
|
|
int keyidlen;
|
|
int i;
|
|
if (X509_trusted(x) == 0)
|
|
return 1;
|
|
trust = X509_get0_trust_objects(x);
|
|
reject = X509_get0_reject_objects(x);
|
|
if (trust) {
|
|
first = 1;
|
|
BIO_printf(out, "%*sTrusted Uses:\n%*s", indent, "", indent + 2, "");
|
|
for (i = 0; i < sk_ASN1_OBJECT_num(trust); i++) {
|
|
if (!first)
|
|
BIO_puts(out, ", ");
|
|
else
|
|
first = 0;
|
|
OBJ_obj2txt(oidstr, sizeof(oidstr),
|
|
sk_ASN1_OBJECT_value(trust, i), 0);
|
|
BIO_puts(out, oidstr);
|
|
}
|
|
BIO_puts(out, "\n");
|
|
} else
|
|
BIO_printf(out, "%*sNo Trusted Uses.\n", indent, "");
|
|
if (reject) {
|
|
first = 1;
|
|
BIO_printf(out, "%*sRejected Uses:\n%*s", indent, "", indent + 2, "");
|
|
for (i = 0; i < sk_ASN1_OBJECT_num(reject); i++) {
|
|
if (!first)
|
|
BIO_puts(out, ", ");
|
|
else
|
|
first = 0;
|
|
OBJ_obj2txt(oidstr, sizeof(oidstr),
|
|
sk_ASN1_OBJECT_value(reject, i), 0);
|
|
BIO_puts(out, oidstr);
|
|
}
|
|
BIO_puts(out, "\n");
|
|
} else
|
|
BIO_printf(out, "%*sNo Rejected Uses.\n", indent, "");
|
|
alias = X509_alias_get0(x, &i);
|
|
if (alias)
|
|
BIO_printf(out, "%*sAlias: %.*s\n", indent, "", i, alias);
|
|
keyid = X509_keyid_get0(x, &keyidlen);
|
|
if (keyid) {
|
|
BIO_printf(out, "%*sKey Id: ", indent, "");
|
|
for (i = 0; i < keyidlen; i++)
|
|
BIO_printf(out, "%s%02X", i ? ":" : "", keyid[i]);
|
|
BIO_write(out, "\n", 1);
|
|
}
|
|
return 1;
|
|
}
|
|
|
|
/*
|
|
* Helper functions for improving certificate verification error diagnostics
|
|
*/
|
|
|
|
int ossl_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 & ~X509_FLAG_EXTENSIONS_ONLY_KID);
|
|
}
|
|
|
|
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) {
|
|
if (!ossl_x509_print_ex_brief(bio, cert, 0))
|
|
return 0;
|
|
if (!X509V3_extensions_print(bio, NULL,
|
|
X509_get0_extensions(cert),
|
|
X509_FLAG_EXTENSIONS_ONLY_KID, 8))
|
|
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);
|
|
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",
|
|
X509_STORE_CTX_get_error_depth(ctx),
|
|
cert_error, X509_verify_cert_error_string(cert_error));
|
|
{
|
|
X509_STORE *ts = X509_STORE_CTX_get0_store(ctx);
|
|
X509_VERIFY_PARAM *vpm = X509_STORE_get0_param(ts);
|
|
char *str;
|
|
int idx = 0;
|
|
|
|
switch (cert_error) {
|
|
case X509_V_ERR_HOSTNAME_MISMATCH:
|
|
BIO_printf(bio, "Expected hostname(s) = ");
|
|
while ((str = X509_VERIFY_PARAM_get0_host(vpm, idx++)) != NULL)
|
|
BIO_printf(bio, "%s%s", idx == 1 ? "" : ", ", str);
|
|
BIO_printf(bio, "\n");
|
|
break;
|
|
case X509_V_ERR_EMAIL_MISMATCH:
|
|
str = X509_VERIFY_PARAM_get0_email(vpm);
|
|
if (str != NULL)
|
|
BIO_printf(bio, "Expected email address = %s\n", str);
|
|
break;
|
|
case X509_V_ERR_IP_ADDRESS_MISMATCH:
|
|
str = X509_VERIFY_PARAM_get1_ip_asc(vpm);
|
|
if (str != NULL)
|
|
BIO_printf(bio, "Expected IP address = %s\n", str);
|
|
OPENSSL_free(str);
|
|
break;
|
|
default:
|
|
break;
|
|
}
|
|
}
|
|
|
|
BIO_printf(bio, "Failure for:\n");
|
|
ossl_x509_print_ex_brief(bio, X509_STORE_CTX_get_current_cert(ctx),
|
|
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));
|
|
}
|
|
ERR_raise(ERR_LIB_X509, X509_R_CERTIFICATE_VERIFICATION_FAILED);
|
|
ERR_add_error_mem_bio("\n", bio);
|
|
BIO_free(bio);
|
|
}
|
|
|
|
return ok;
|
|
}
|