{
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",
+ 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);
+ ? "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");
+ 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_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");
+ BIO_printf(bio, "Non-trusted certs:\n");
print_certs(bio, X509_STORE_CTX_get0_untrusted(ctx));
- BIO_printf(bio, "certs in trust store:\n");
+ BIO_printf(bio, "Certs in trust store:\n");
print_store_certs(bio, X509_STORE_CTX_get0_store(ctx));
}
X509err(0, X509_R_CERTIFICATE_VERIFICATION_FAILED);
return 0;
BIO_printf(out, "%d.%d.%d.%d", addr[0], addr[1], addr[2], addr[3]);
break;
+ /* TODO possibly combine with ipaddr_to_asc() */
case IANA_AFI_IPV6:
if (!addr_expand(addr, bs, 16, fill))
return 0;
GENERAL_NAME *gen,
STACK_OF(CONF_VALUE) *ret)
{
- unsigned char *p;
char othername[300];
- char oline[256], htmp[5];
- int i;
+ char oline[256], *tmp;
switch (gen->type) {
case GEN_OTHERNAME:
break;
case GEN_IPADD:
- p = gen->d.ip->data;
- if (gen->d.ip->length == 4)
- BIO_snprintf(oline, sizeof(oline), "%d.%d.%d.%d",
- p[0], p[1], p[2], p[3]);
- else if (gen->d.ip->length == 16) {
- oline[0] = 0;
- for (i = 0; i < 8; i++) {
- BIO_snprintf(htmp, sizeof(htmp), "%X", p[0] << 8 | p[1]);
- p += 2;
- strcat(oline, htmp);
- if (i != 7)
- strcat(oline, ":");
- }
- } else {
- if (!X509V3_add_value("IP Address", "<invalid>", &ret))
- return NULL;
- break;
- }
- if (!X509V3_add_value("IP Address", oline, &ret))
- return NULL;
+ tmp = ipaddr_to_asc(gen->d.ip->data, gen->d.ip->length);
+ if (tmp == NULL || !X509V3_add_value("IP Address", tmp, &ret))
+ ret = NULL;
+ OPENSSL_free(tmp);
break;
case GEN_RID:
int GENERAL_NAME_print(BIO *out, GENERAL_NAME *gen)
{
- unsigned char *p;
- int i, nid;
+ char *tmp;
+ int nid;
switch (gen->type) {
case GEN_OTHERNAME:
break;
case GEN_IPADD:
- p = gen->d.ip->data;
- if (gen->d.ip->length == 4)
- BIO_printf(out, "IP Address:%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
- else if (gen->d.ip->length == 16) {
- BIO_printf(out, "IP Address");
- for (i = 0; i < 8; i++) {
- BIO_printf(out, ":%X", p[0] << 8 | p[1]);
- p += 2;
- }
- } else {
- BIO_printf(out, "IP Address:<invalid>");
- break;
- }
+ tmp = ipaddr_to_asc(gen->d.ip->data, gen->d.ip->length);
+ if (tmp == NULL)
+ return 0;
+ BIO_printf(out, "IP Address:%s", tmp);
+ OPENSSL_free(tmp);
break;
case GEN_RID:
static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip)
{
- int i, len;
- unsigned char *p;
- p = ip->data;
- len = ip->length;
- BIO_puts(bp, "IP:");
- if (len == 8) {
- BIO_printf(bp, "%d.%d.%d.%d/%d.%d.%d.%d",
- p[0], p[1], p[2], p[3], p[4], p[5], p[6], p[7]);
- } else if (len == 32) {
- for (i = 0; i < 16; i++) {
- BIO_printf(bp, "%X", p[0] << 8 | p[1]);
- p += 2;
- if (i == 7)
- BIO_puts(bp, "/");
- else if (i != 15)
- BIO_puts(bp, ":");
- }
- } else
- BIO_printf(bp, "IP Address:<invalid>");
- return 1;
+ /* ip->length should be 8 or 32 and len1 == len2 == 4 or len1 == len2 == 16 */
+ int len1 = ip->length >= 16 ? 16 : ip->length >= 4 ? 4 : ip->length;
+ int len2 = ip->length - len1;
+ char *ip1 = ipaddr_to_asc(ip->data, len1);
+ char *ip2 = ipaddr_to_asc(ip->data + len1, len2);
+ int ret = ret = ip1 != NULL && ip2 != NULL
+ && BIO_printf(bp, "IP:%s/%s", ip1, ip2) > 0;
+
+ OPENSSL_free(ip1);
+ OPENSSL_free(ip2);
+ return ret;
}
#define NAME_CHECK_MAX (1 << 20)
static STACK_OF(OPENSSL_STRING) *get_email(const X509_NAME *name,
GENERAL_NAMES *gens);
static void str_free(OPENSSL_STRING str);
-static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, const ASN1_IA5STRING *email);
+static int append_ia5(STACK_OF(OPENSSL_STRING) **sk,
+ const ASN1_IA5STRING *email);
static int ipv4_from_asc(unsigned char *v4, const char *in);
static int ipv6_from_asc(unsigned char *v6, const char *in);
ASN1_INTEGER *aint;
int isneg, ishex;
int ret;
+
if (value == NULL) {
X509V3err(X509V3_F_S2I_ASN1_INTEGER, X509V3_R_INVALID_NULL_VALUE);
return NULL;
if (value[0] == '-') {
value++;
isneg = 1;
- } else
+ } else {
isneg = 0;
+ }
if (value[0] == '0' && ((value[1] == 'x') || (value[1] == 'X'))) {
value += 2;
ishex = 1;
- } else
+ } else {
ishex = 0;
+ }
if (ishex)
ret = BN_hex2bn(&bn, value);
STACK_OF(CONF_VALUE) *values = NULL;
char *linebuf;
int state;
+
/* We are going to modify the line so copy it first */
linebuf = OPENSSL_strdup(line);
if (linebuf == NULL) {
static char *strip_spaces(char *name)
{
char *p, *q;
+
/* Skip over leading spaces */
p = name;
while (*p && ossl_isspace(*p))
{
int len, ret;
char c;
+
len = strlen(cmp);
if ((ret = strncmp(name, cmp, len)))
return ret;
OPENSSL_free(str);
}
-static int append_ia5(STACK_OF(OPENSSL_STRING) **sk, const ASN1_IA5STRING *email)
+static int append_ia5(STACK_OF(OPENSSL_STRING) **sk,
+ const ASN1_IA5STRING *email)
{
char *emtmp;
+
/* First some sanity checks */
if (email->type != V_ASN1_IA5STRING)
return 1;
return 1;
emtmp = OPENSSL_strdup((char *)email->data);
if (emtmp == NULL || !sk_OPENSSL_STRING_push(*sk, emtmp)) {
- OPENSSL_free(emtmp); /* free on push failure */
+ OPENSSL_free(emtmp); /* free on push failure */
X509_email_free(*sk);
*sk = NULL;
return 0;
skip_prefix(&pattern, &pattern_len, subject_len, flags);
if (pattern_len != subject_len)
return 0;
- while (pattern_len) {
+ while (pattern_len != 0) {
unsigned char l = *pattern;
unsigned char r = *subject;
+
/* The pattern must not contain NUL characters. */
if (l == 0)
return 0;
unsigned int unused_flags)
{
size_t i = a_len;
+
if (a_len != b_len)
return 0;
/*
size_t i;
int state = LABEL_START;
int dots = 0;
+
for (i = 0; i < len; ++i) {
/*
* Locate first and only legal wildcard, either at the start
if ((state & LABEL_START) != 0)
return NULL;
state |= LABEL_HYPHEN;
- } else
+ } else {
return NULL;
+ }
}
/*
for (i = 0; i < sk_GENERAL_NAME_num(gens); i++) {
GENERAL_NAME *gen;
ASN1_STRING *cstr;
+
gen = sk_GENERAL_NAME_value(gens, i);
if (gen->type != check_type)
continue;
return do_x509_check(x, (char *)ipout, iplen, flags, GEN_IPADD, NULL);
}
+char *ipaddr_to_asc(unsigned char *p, int len)
+{
+ char buf[40], *out;
+
+ switch (len) {
+ case 4: /* IPv4 */
+ BIO_snprintf(buf, sizeof(buf), "%d.%d.%d.%d", p[0], p[1], p[2], p[3]);
+ break;
+ /* TODO possibly combine with static i2r_address() in v3_addr.c */
+ case 16: /* IPv6 */
+ for (out = buf; out < buf + 8 * 3; out += 3) {
+ BIO_snprintf(out, 3 + 1, "%X:", p[0] << 8 | p[1]);
+ p += 2;
+ }
+ out[-1] = '\0';
+ break;
+ default:
+ BIO_snprintf(buf, sizeof(buf), "<invalid length=%d>", len);
+ break;
+ }
+ return OPENSSL_strdup(buf);
+}
+
/*
* Convert IP addresses both IPv4 and IPv6 into an OCTET STRING compatible
* with RFC3280.
static int ipv4_from_asc(unsigned char *v4, const char *in)
{
int a0, a1, a2, a3;
+
if (sscanf(in, "%d.%d.%d.%d", &a0, &a1, &a2, &a3) != 4)
return 0;
if ((a0 < 0) || (a0 > 255) || (a1 < 0) || (a1 > 255)
static int ipv6_from_asc(unsigned char *v6, const char *in)
{
IPV6_STAT v6stat;
+
v6stat.total = 0;
v6stat.zero_pos = -1;
v6stat.zero_cnt = 0;
if (v6stat.total == 16)
return 0;
/* More than three zeroes is an error */
- if (v6stat.zero_cnt > 3)
+ if (v6stat.zero_cnt > 3) {
return 0;
/* Can only have three zeroes if nothing else present */
- else if (v6stat.zero_cnt == 3) {
+ } else if (v6stat.zero_cnt == 3) {
if (v6stat.total > 0)
return 0;
- }
- /* Can only have two zeroes if at start or end */
- else if (v6stat.zero_cnt == 2) {
+ } else if (v6stat.zero_cnt == 2) {
+ /* Can only have two zeroes if at start or end */
if ((v6stat.zero_pos != 0)
&& (v6stat.zero_pos != v6stat.total))
return 0;
- } else
+ } else {
/* Can only have one zero if *not* start or end */
- {
if ((v6stat.zero_pos == 0)
|| (v6stat.zero_pos == v6stat.total))
return 0;
memcpy(v6 + v6stat.zero_pos + 16 - v6stat.total,
v6stat.tmp + v6stat.zero_pos,
v6stat.total - v6stat.zero_pos);
- } else
+ } else {
memcpy(v6, v6stat.tmp, 16);
+ }
return 1;
}
static int ipv6_cb(const char *elem, int len, void *usr)
{
IPV6_STAT *s = usr;
+
/* Error if 16 bytes written */
if (s->total == 16)
return 0;
CONF_VALUE *v;
int i, mval, spec_char, plus_char;
char *p, *type;
+
if (!nm)
return 0;
spec_char = ((*p == ':') || (*p == ',') || (*p == '.'));
#else
spec_char = ((*p == os_toascii[':']) || (*p == os_toascii[','])
- || (*p == os_toascii['.']));
+ || (*p == os_toascii['.']));
#endif
if (spec_char) {
p++;
if (plus_char) {
mval = -1;
type++;
- } else
+ } else {
mval = 0;
+ }
if (!X509_NAME_add_entry_by_txt(nm, type, chtype,
(unsigned char *)v->value, -1, -1,
mval))
/* Macro to test if a field should be copied from src to dest */
#define test_x509_verify_param_copy(field, def) \
- (to_overwrite || \
- ((src->field != def) && (to_default || (dest->field == def))))
+ (to_overwrite \
+ || ((src->field != def) && (to_default || (dest->field == def))))
/* Macro to test and copy a field if necessary */
#define x509_verify_param_copy(field, def) \
- if (test_x509_verify_param_copy(field, def)) \
- dest->field = src->field
+ if (test_x509_verify_param_copy(field, def)) \
+ dest->field = src->field;
int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
const X509_VERIFY_PARAM *src)
static int int_x509_param_set1(char **pdest, size_t *pdestlen,
const char *src, size_t srclen)
{
- void *tmp;
+ char *tmp;
if (src) {
if (srclen == 0)
srclen = strlen(src);
- tmp = OPENSSL_memdup(src, srclen);
+ tmp = OPENSSL_malloc(srclen + 1);
if (tmp == NULL)
return 0;
+ memcpy(tmp, src, srclen);
+ tmp[srclen] = '\0'; /* enforce NUL termination */
} else {
tmp = NULL;
srclen = 0;
return 1;
}
+char *X509_VERIFY_PARAM_get0_host(X509_VERIFY_PARAM *param, int idx)
+{
+ return sk_OPENSSL_STRING_value(param->hosts, idx);
+}
+
int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
const char *name, size_t namelen)
{
from->peername = NULL;
}
+char *X509_VERIFY_PARAM_get0_email(X509_VERIFY_PARAM *param)
+{
+ return param->email;
+}
+
int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
const char *email, size_t emaillen)
{
email, emaillen);
}
+static unsigned char
+*int_X509_VERIFY_PARAM_get0_ip(X509_VERIFY_PARAM *param, size_t *plen)
+{
+ if (param == NULL || param->ip == NULL)
+ return NULL;
+ if (plen != NULL)
+ *plen = param->iplen;
+ return param->ip;
+}
+
+char *X509_VERIFY_PARAM_get1_ip_asc(X509_VERIFY_PARAM *param)
+{
+ size_t iplen;
+ unsigned char *ip = int_X509_VERIFY_PARAM_get0_ip(param, &iplen);
+
+ return ip == NULL ? NULL : ipaddr_to_asc(ip, iplen);
+}
+
int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
const unsigned char *ip, size_t iplen)
{
X509_VERIFY_PARAM_get_auth_level, X509_VERIFY_PARAM_set_time,
X509_VERIFY_PARAM_get_time,
X509_VERIFY_PARAM_add0_policy, X509_VERIFY_PARAM_set1_policies,
+X509_VERIFY_PARAM_get0_host,
X509_VERIFY_PARAM_set1_host, X509_VERIFY_PARAM_add1_host,
X509_VERIFY_PARAM_set_hostflags,
X509_VERIFY_PARAM_get_hostflags,
X509_VERIFY_PARAM_get0_peername,
-X509_VERIFY_PARAM_set1_email, X509_VERIFY_PARAM_set1_ip,
+X509_VERIFY_PARAM_get0_email, X509_VERIFY_PARAM_set1_email,
+X509_VERIFY_PARAM_set1_ip, X509_VERIFY_PARAM_get1_ip_asc,
X509_VERIFY_PARAM_set1_ip_asc
- X509 verification parameters
int auth_level);
int X509_VERIFY_PARAM_get_auth_level(const X509_VERIFY_PARAM *param);
+ char *X509_VERIFY_PARAM_get0_host(X509_VERIFY_PARAM *param, int n);
int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
const char *name, size_t namelen);
int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param,
unsigned int flags);
unsigned int X509_VERIFY_PARAM_get_hostflags(const X509_VERIFY_PARAM *param);
char *X509_VERIFY_PARAM_get0_peername(const X509_VERIFY_PARAM *param);
+ char *X509_VERIFY_PARAM_get0_email(X509_VERIFY_PARAM *param);
int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
const char *email, size_t emaillen);
+ char *X509_VERIFY_PARAM_get1_ip_asc(X509_VERIFY_PARAM *param);
int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
const unsigned char *ip, size_t iplen);
int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc);
interoperable, though it will, for example, reject MD5 signatures or RSA keys
shorter than 1024 bits.
+X509_VERIFY_PARAM_get0_host() returns the B<n>th expected DNS hostname that has
+been set using X509_VERIFY_PARAM_set1_host() or X509_VERIFY_PARAM_add1_host().
+To obtain all names start with B<n> = 0 and increment B<n> as long as no NULL
+pointer is returned.
+
X509_VERIFY_PARAM_set1_host() sets the expected DNS hostname to
B<name> clearing any previously specified hostname. If
B<name> is NULL, or empty the list of hostnames is cleared, and
associated B<param> argument is freed. Applications must not free
the return value.
+X509_VERIFY_PARAM_get0_email() returns the expected RFC822 email address.
+
X509_VERIFY_PARAM_set1_email() sets the expected RFC822 email address to
B<email>. If B<email> is NUL-terminated, B<emaillen> may be zero, otherwise
B<emaillen> must be set to the length of B<email>. When an email address
is specified, certificate verification automatically invokes
L<X509_check_email(3)>.
+X509_VERIFY_PARAM_get1_ip_asc() returns the expected IP address as a string.
+The caller is responsible for freeing it.
+
X509_VERIFY_PARAM_set1_ip() sets the expected IP address to B<ip>.
The B<ip> argument is in binary format, in network byte-order and
B<iplen> must be set to 4 for IPv4 and 16 for IPv6. When an IP
X509_VERIFY_PARAM_set1_ip_asc() return 1 for success and 0 for
failure.
+X509_VERIFY_PARAM_get0_host(), X509_VERIFY_PARAM_get0_email(), and
+X509_VERIFY_PARAM_get1_ip_asc(), return the string pointers pecified above
+or NULL if the respective value has not been set or on error.
+
X509_VERIFY_PARAM_get_flags() returns the current verification flags.
X509_VERIFY_PARAM_get_hostflags() returns any current host flags.
The X509_VERIFY_PARAM_get_hostflags() function was added in OpenSSL 1.1.0i.
+The X509_VERIFY_PARAM_get0_host(), X509_VERIFY_PARAM_get0_email(),
+and X509_VERIFY_PARAM_get1_ip_asc() functions were added in OpenSSL 3.0.
+
=head1 COPYRIGHT
Copyright 2009-2020 The OpenSSL Project Authors. All Rights Reserved.
char *sk_ASN1_UTF8STRING2text(STACK_OF(ASN1_UTF8STRING) *text, const char *sep,
size_t max_len);
+char *ipaddr_to_asc(unsigned char *p, int len);
#endif
uint32_t flags);
uint32_t X509_VERIFY_PARAM_get_inh_flags(const X509_VERIFY_PARAM *param);
+char *X509_VERIFY_PARAM_get0_host(X509_VERIFY_PARAM *param, int idx);
int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
const char *name, size_t namelen);
int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param,
unsigned int X509_VERIFY_PARAM_get_hostflags(const X509_VERIFY_PARAM *param);
char *X509_VERIFY_PARAM_get0_peername(const X509_VERIFY_PARAM *param);
void X509_VERIFY_PARAM_move_peername(X509_VERIFY_PARAM *, X509_VERIFY_PARAM *);
+char *X509_VERIFY_PARAM_get0_email(X509_VERIFY_PARAM *param);
int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
const char *email, size_t emaillen);
+char *X509_VERIFY_PARAM_get1_ip_asc(X509_VERIFY_PARAM *param);
int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
const unsigned char *ip, size_t iplen);
int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param,
EVP_PKEY_CTX_set_dh_nid ? 3_0_0 EXIST::FUNCTION:DH
EVP_PKEY_CTX_set_dh_rfc5114 ? 3_0_0 EXIST::FUNCTION:DH
EVP_PKEY_CTX_set_dhx_rfc5114 ? 3_0_0 EXIST::FUNCTION:DH
+X509_VERIFY_PARAM_get0_host ? 3_0_0 EXIST::FUNCTION:
+X509_VERIFY_PARAM_get0_email ? 3_0_0 EXIST::FUNCTION:
+X509_VERIFY_PARAM_get1_ip_asc ? 3_0_0 EXIST::FUNCTION:
X509_verify_ex ? 3_0_0 EXIST::FUNCTION:
X509_REQ_verify_ex ? 3_0_0 EXIST::FUNCTION:
X509_ALGOR_copy ? 3_0_0 EXIST::FUNCTION: