Let's support multiple names for certificate verification

This adds the functionality to VERIFY_PARAM to separately add multiple
ip's and email addresses for verification purposes.

We then mark the unfortunate SSL_add1_host API which unfortunately
aquired a confusing "maybe add an IP address" behaviour as deprecated.

We replace this with SSL_set1_<dnsname, email, ip, ip_asc> and
SSL_add1_<dnsname, email, ip, ip_asc> to set the things in the SSL
corresponding to the VERIFY_PARAM funcitons.

Fixes: https://github.com/openssl/openssl/issues/28418

Reviewed-by: Neil Horman <nhorman@openssl.org>
Reviewed-by: Viktor Dukhovni <viktor@openssl.org>
MergeDate: Tue Feb 24 14:03:42 2026
(Merged from https://github.com/openssl/openssl/pull/29612)
This commit is contained in:
Bob Beck
2025-12-20 12:21:40 -07:00
committed by Neil Horman
parent dbc2e10272
commit f584ae959c
22 changed files with 1370 additions and 246 deletions
+29 -6
View File
@@ -867,7 +867,7 @@ static int do_check_string(const ASN1_STRING *a, int cmp_type, equal_fn equal,
}
static int do_x509_check(X509 *x, const char *chk, size_t chklen,
unsigned int flags, int check_type, char **peername)
unsigned int flags, int check_type, int check_nid, char **peername)
{
GENERAL_NAMES *gens = NULL;
const X509_NAME *name = NULL;
@@ -913,6 +913,8 @@ static int do_x509_check(X509 *x, const char *chk, size_t chklen,
default:
continue;
case GEN_OTHERNAME:
if (check_type != GEN_OTHERNAME)
continue;
switch (OBJ_obj2nid(gen->d.otherName->type_id)) {
default:
continue;
@@ -942,7 +944,7 @@ static int do_x509_check(X509 *x, const char *chk, size_t chklen,
* choose to turn it off, doing so is at this time a best
* practice.
*/
if (check_type != GEN_EMAIL
if (check_nid != NID_id_on_SmtpUTF8Mailbox
|| gen->d.otherName->value->type != V_ASN1_UTF8STRING)
continue;
alt_type = 0;
@@ -1015,7 +1017,21 @@ int X509_check_host(X509 *x, const char *chk, size_t chklen,
return -2;
if (chklen > 1 && chk[chklen - 1] == '\0')
--chklen;
return do_x509_check(x, chk, chklen, flags, GEN_DNS, peername);
return do_x509_check(x, chk, chklen, flags, GEN_DNS, 0, peername);
}
int ossl_x509_check_rfc822(X509 *x, const char *chk, size_t chklen,
unsigned int flags)
{
return do_x509_check(x, chk, chklen, flags, GEN_EMAIL, 0, NULL) == 1;
}
int ossl_x509_check_smtputf8(X509 *x, const char *chk, size_t chklen,
unsigned int flags)
{
return do_x509_check(x, chk, chklen, flags, GEN_OTHERNAME,
NID_id_on_SmtpUTF8Mailbox, NULL)
== 1;
}
int X509_check_email(X509 *x, const char *chk, size_t chklen,
@@ -1034,7 +1050,14 @@ int X509_check_email(X509 *x, const char *chk, size_t chklen,
return -2;
if (chklen > 1 && chk[chklen - 1] == '\0')
--chklen;
return do_x509_check(x, chk, chklen, flags, GEN_EMAIL, NULL);
/*
* As this is public API, historically it has supported checking
* whatever is supplied against both RFC822 and SMTPUTF8.
*/
if (do_x509_check(x, chk, chklen, flags, GEN_EMAIL, 0, NULL) == 1)
return 1;
return do_x509_check(x, chk, chklen, flags, GEN_OTHERNAME,
NID_id_on_SmtpUTF8Mailbox, NULL);
}
int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen,
@@ -1042,7 +1065,7 @@ int X509_check_ip(X509 *x, const unsigned char *chk, size_t chklen,
{
if (chk == NULL)
return -2;
return do_x509_check(x, (char *)chk, chklen, flags, GEN_IPADD, NULL);
return do_x509_check(x, (char *)chk, chklen, flags, GEN_IPADD, 0, NULL);
}
int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags)
@@ -1055,7 +1078,7 @@ int X509_check_ip_asc(X509 *x, const char *ipasc, unsigned int flags)
iplen = (size_t)ossl_a2i_ipadd(ipout, ipasc);
if (iplen == 0)
return -2;
return do_x509_check(x, (char *)ipout, iplen, flags, GEN_IPADD, NULL);
return do_x509_check(x, (char *)ipout, iplen, flags, GEN_IPADD, 0, NULL);
}
char *ossl_ipaddr_to_asc(unsigned char *p, int len)
+24 -6
View File
@@ -6,6 +6,7 @@
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
*/
#include <openssl/safestack.h>
#include "internal/refcount.h"
#include "internal/hashtable.h"
@@ -13,12 +14,22 @@
#define X509V3_conf_add_error_name_value(val) \
ERR_add_error_data(4, "name=", (val)->name, ", value=", (val)->value)
/*
* Really all I want is CRYPTO_BUFFER from BoringSSL, but let's just do this
* for now.
*/
typedef struct ossl_x509_buffer_st {
const uint8_t *data;
size_t len;
} X509_BUFFER;
DEFINE_STACK_OF(X509_BUFFER)
/*
* This structure holds all parameters associated with a verify operation by
* including an X509_VERIFY_PARAM structure in related structures the
* parameters used can be customized
*/
struct X509_VERIFY_PARAM_st {
char *name;
int64_t check_time; /* Time to use */
@@ -30,13 +41,16 @@ struct X509_VERIFY_PARAM_st {
int auth_level; /* Security level for chain verification */
STACK_OF(ASN1_OBJECT) *policies; /* Permissible policies */
/* Peer identity details */
STACK_OF(OPENSSL_STRING) *hosts; /* Set of acceptable names */
STACK_OF(X509_BUFFER) *hosts; /* Set of acceptable names */
int (*validate_host)(const char *name, size_t len);
STACK_OF(X509_BUFFER) *ips; /* Set of acceptable ip addresses */
int (*validate_ip)(const uint8_t *name, size_t len);
STACK_OF(X509_BUFFER) *rfc822s; /* Set of acceptable RFC 822 names */
int (*validate_rfc822)(const char *name, size_t len);
STACK_OF(X509_BUFFER) *smtputf8s; /* Set of acceptable SMTP Utf8 names */
int (*validate_smtputf8)(const char *name, size_t len);
unsigned int hostflags; /* Flags to control matching features */
char *peername; /* Matching hostname in peer certificate */
char *email; /* If not NULL email address to match */
size_t emaillen;
unsigned char *ip; /* If not NULL IP address to match */
size_t iplen; /* Length of IP address */
};
/* No error callback if depth < 0 */
@@ -173,3 +187,7 @@ int ossl_x509_store_ctx_get_by_subject(const X509_STORE_CTX *ctx, X509_LOOKUP_TY
__owur int ossl_x509_store_read_lock(X509_STORE *xs);
STACK_OF(X509_OBJECT) *ossl_x509_store_ht_get_by_name(const X509_STORE *store,
const X509_NAME *xn);
int ossl_x509_check_rfc822(X509 *x, const char *chk, size_t chklen,
unsigned int flags);
int ossl_x509_check_smtputf8(X509 *x, const char *chk, size_t chklen,
unsigned int flags);
+52 -7
View File
@@ -940,16 +940,60 @@ static int check_id_error(X509_STORE_CTX *ctx, int errcode)
static int check_hosts(X509 *x, X509_VERIFY_PARAM *vpm)
{
int i;
int n = sk_OPENSSL_STRING_num(vpm->hosts);
char *name;
int n = sk_X509_BUFFER_num(vpm->hosts);
const uint8_t *name;
if (vpm->peername != NULL) {
OPENSSL_free(vpm->peername);
vpm->peername = NULL;
}
for (i = 0; i < n; ++i) {
name = sk_OPENSSL_STRING_value(vpm->hosts, i);
if (X509_check_host(x, name, 0, vpm->hostflags, &vpm->peername) > 0)
size_t len = sk_X509_BUFFER_value(vpm->hosts, i)->len;
name = sk_X509_BUFFER_value(vpm->hosts, i)->data;
if (X509_check_host(x, (const char *)name, len, vpm->hostflags, &vpm->peername) > 0)
return 1;
}
return n == 0;
}
static int check_email(X509 *x, X509_VERIFY_PARAM *vpm)
{
int i, n, j;
const uint8_t *name;
if (vpm->rfc822s == NULL)
return 1;
n = sk_X509_BUFFER_num(vpm->rfc822s);
for (i = 0; i < n; ++i) {
size_t len = sk_X509_BUFFER_value(vpm->rfc822s, i)->len;
name = sk_X509_BUFFER_value(vpm->rfc822s, i)->data;
if (ossl_x509_check_rfc822(x, (const char *)name, len, vpm->hostflags))
return 1;
}
j = sk_X509_BUFFER_num(vpm->smtputf8s);
for (i = 0; i < j; ++i) {
size_t len = sk_X509_BUFFER_value(vpm->smtputf8s, i)->len;
name = sk_X509_BUFFER_value(vpm->smtputf8s, i)->data;
if (ossl_x509_check_smtputf8(x, (const char *)name, len, vpm->hostflags))
return 1;
}
return n == 0 && i == 0;
}
static int check_ips(X509 *x, X509_VERIFY_PARAM *vpm)
{
int i;
int n = sk_X509_BUFFER_num(vpm->ips);
const uint8_t *name;
for (i = 0; i < n; ++i) {
size_t len = sk_X509_BUFFER_value(vpm->ips, i)->len;
name = sk_X509_BUFFER_value(vpm->ips, i)->data;
if (X509_check_ip(x, name, len, vpm->hostflags) > 0)
return 1;
}
return n == 0;
@@ -964,12 +1008,13 @@ static int check_id(X509_STORE_CTX *ctx)
if (!check_id_error(ctx, X509_V_ERR_HOSTNAME_MISMATCH))
return 0;
}
if (vpm->email != NULL
&& X509_check_email(x, vpm->email, vpm->emaillen, 0) <= 0) {
if (!check_email(x, vpm)) {
if (!check_id_error(ctx, X509_V_ERR_EMAIL_MISMATCH))
return 0;
}
if (vpm->ip != NULL && X509_check_ip(x, vpm->ip, vpm->iplen, 0) <= 0) {
if (vpm->ips != NULL && check_ips(x, vpm) <= 0) {
if (!check_id_error(ctx, X509_V_ERR_IP_ADDRESS_MISMATCH))
return 0;
}
+562 -174
View File
@@ -14,70 +14,348 @@
#include <openssl/buffer.h>
#include <openssl/x509.h>
#include <openssl/x509v3.h>
#include "crypto/ctype.h"
#include "crypto/x509.h"
#include "x509_local.h"
typedef enum {
OSSL_CHARSET_NONASCII,
OSSL_CHARSET_ASCII,
OSSL_CHARSET_ASCII_ALNUM,
} ossl_charset_t;
/* X509_VERIFY_PARAM functions */
#define SET_HOST 0
#define ADD_HOST 1
static char *str_copy(const char *s)
static X509_BUFFER *buffer_from_bytes(const uint8_t *bytes, size_t length)
{
return OPENSSL_strdup(s);
X509_BUFFER *buf;
if ((buf = OPENSSL_zalloc(sizeof *buf)) != NULL
&& (buf->data = OPENSSL_memdup(bytes, length)) != NULL)
buf->len = length;
else
OPENSSL_free(buf);
return buf;
}
static void str_free(char *s)
/*
* Copies |length| bytes from |bytes| to a new buffer, making the data
* A C string. It is an error for the |bytes| to contain any \0 values
* within |length|. |bytes| need not itself be \0 terminated, the data
* in the buffer will be on success.
*/
static X509_BUFFER *buffer_from_string(const uint8_t *bytes, size_t length)
{
OPENSSL_free(s);
X509_BUFFER *buf, *ret = NULL;
uint8_t *data = NULL;
if ((buf = OPENSSL_zalloc(sizeof *buf)) == NULL)
goto err;
if ((data = (uint8_t *)OPENSSL_strndup((char *)bytes, length)) == NULL)
goto err;
if (strlen((char *)data) != length)
goto err;
ret = buf;
buf = NULL;
ret->data = data;
ret->len = length;
data = NULL;
err:
OPENSSL_free(buf);
OPENSSL_free(data);
return ret;
}
static int int_x509_param_set_hosts(X509_VERIFY_PARAM *vpm, int mode,
const char *name, size_t namelen)
static X509_BUFFER *buffer_copy(const X509_BUFFER *b)
{
char *copy;
return buffer_from_bytes(b->data, b->len);
}
static void buffer_free(X509_BUFFER *b)
{
if (b == NULL)
return;
OPENSSL_free((void *)b->data);
OPENSSL_free(b);
}
static int replace_buffer_stack(STACK_OF(X509_BUFFER) **dest,
STACK_OF(X509_BUFFER) *const *src)
{
sk_X509_BUFFER_pop_free(*dest, buffer_free);
*dest = NULL;
if (*src != NULL) {
*dest = sk_X509_BUFFER_deep_copy(*src, buffer_copy, buffer_free);
if (*dest == NULL)
return 0;
}
return 1;
}
static int buffer_cmp(const X509_BUFFER *const *a, const X509_BUFFER *const *b)
{
if ((*a)->len < (*b)->len)
return -1;
if ((*a)->len > (*b)->len)
return 1;
return memcmp((*a)->data, (*b)->data, (*b)->len);
}
static void clear_buffer_stack(STACK_OF(X509_BUFFER) **buffer_stack)
{
sk_X509_BUFFER_pop_free(*buffer_stack, buffer_free);
*buffer_stack = NULL;
}
static int add_bytes_to_buffer_stack(STACK_OF(X509_BUFFER) **buffer_stack,
const uint8_t *name, size_t name_len)
{
STACK_OF(X509_BUFFER) *tmp_stack = NULL;
X509_BUFFER *copy = NULL;
int ret = 0;
if ((copy = buffer_from_bytes(name, name_len)) == NULL)
goto err;
tmp_stack = *buffer_stack;
if (tmp_stack == NULL && (tmp_stack = sk_X509_BUFFER_new(buffer_cmp)) == NULL)
goto err;
if (!sk_X509_BUFFER_push(tmp_stack, copy))
goto err;
ret = 1;
copy = NULL;
*buffer_stack = tmp_stack;
tmp_stack = NULL;
err:
sk_X509_BUFFER_pop_free(tmp_stack, buffer_free);
buffer_free(copy);
return ret;
}
static int add_string_to_buffer_stack(STACK_OF(X509_BUFFER) **buffer_stack,
const uint8_t *name, size_t name_len)
{
STACK_OF(X509_BUFFER) *tmp_stack = NULL;
X509_BUFFER *copy = NULL;
int ret = 0;
if ((copy = buffer_from_string(name, name_len)) == NULL)
goto err;
tmp_stack = *buffer_stack;
if (tmp_stack == NULL && (tmp_stack = sk_X509_BUFFER_new(buffer_cmp)) == NULL)
goto err;
if (!sk_X509_BUFFER_push(tmp_stack, copy))
goto err;
ret = 1;
copy = NULL;
*buffer_stack = tmp_stack;
tmp_stack = NULL;
err:
sk_X509_BUFFER_pop_free(tmp_stack, buffer_free);
buffer_free(copy);
return ret;
}
static int validate_string_name(const char *name, size_t *name_len)
{
size_t len = *name_len;
if (name == NULL || len == 0)
return 0;
/*
* Refuse names with embedded NUL bytes, except perhaps as final byte.
* XXX: Do we need to push an error onto the error stack?
* Accept the trailing \0 byte if this is a C string. This is to
* preserver behaviour that is traditional for the
* set1_[host|email] functions.
*/
if (namelen == 0 || name == NULL)
namelen = name ? strlen(name) : 0;
else if (name != NULL
&& memchr(name, '\0', namelen > 1 ? namelen - 1 : namelen) != NULL)
return 0;
if (namelen > 0 && name[namelen - 1] == '\0')
--namelen;
if (name[len - 1] == '\0')
len--;
if (mode == SET_HOST) {
sk_OPENSSL_STRING_pop_free(vpm->hosts, str_free);
vpm->hosts = NULL;
}
if (name == NULL || namelen == 0)
return 1;
copy = OPENSSL_strndup(name, namelen);
if (copy == NULL)
/* Refuse the empty string */
if (len == 0)
return 0;
if (vpm->hosts == NULL && (vpm->hosts = sk_OPENSSL_STRING_new_null()) == NULL) {
OPENSSL_free(copy);
/* Refuse values with embedded \0 bytes other than at the end */
if (memchr(name, '\0', len) != NULL)
return 0;
}
if (!sk_OPENSSL_STRING_push(vpm->hosts, copy)) {
OPENSSL_free(copy);
if (sk_OPENSSL_STRING_num(vpm->hosts) == 0) {
sk_OPENSSL_STRING_free(vpm->hosts);
vpm->hosts = NULL;
}
return 0;
}
return 1;
}
/*
* Default input validation for verification parameter names. As these
* could potentially come from untrusted input, doing basic input
* validation makes sense, and ensures that subsequent parsing or
* comparisons do not need to handle extreme out of range input.
*/
/* Default ip name input validation */
static int validate_ip_name(const uint8_t *name, size_t len)
{
if (name != NULL && (len == 4 || len == 16))
return 1;
return 0;
}
static ossl_charset_t ossl_name_charset(int c, ossl_charset_t charset)
{
if (ossl_isalnum(c))
return 1;
if (ossl_isascii(c))
return charset == OSSL_CHARSET_ASCII
|| charset == OSSL_CHARSET_NONASCII;
return charset == OSSL_CHARSET_NONASCII;
}
/*
* Check for allowed characters in a dns name label.
* |charset| controls the strictness of the checking.
*
* if |charset|is OSSL_CHARSET_NONASCII, anything is allowed
* except the forbidden characters of '.' and '-'. This
* will make minimally valid structure be checked but nothing
* else.
*
* if |charset| is OSSL_CHARSET_ASCII all ascii characters
* are allowed except the forbidden characters of '.' and '-'.
*
* if |charset| is OSSL_CHARSET_ASCII_ALNUM all alphanumeric
* characters plus the character '_' are allowed except the forbidden
* characters of '.' and '-'.
*/
static int is_label_ok(int c, ossl_charset_t charset)
{
if (!ossl_name_charset(c, charset) && c != '_')
return 0;
else
return c != '.' && c != '-';
}
/* Default host name input validation */
static int validate_hostname_part(const char *name, size_t len,
ossl_charset_t charset)
{
size_t i, part_len;
char c, prev;
if (len < 2 || len > 256)
return 0;
part_len = 0;
prev = '\0';
for (i = 0; i < len; i++) {
c = name[i];
if (c == '.') {
/* Can not start a label with a . */
if (part_len == 0)
return 0;
/* Can not end a label with a - */
if (prev == '-')
return 0;
part_len = 0;
} else {
if (!is_label_ok(c, charset) && c != '-')
return 0;
if (c == '-') {
/* Can not start a label with a - */
if (part_len == 0)
return 0;
}
}
part_len++;
if (part_len > 63)
return 0;
prev = c;
}
/* Can not end with a . or a _ */
if (prev == '.' || prev == '-')
return 0;
return 1;
}
static int validate_local_part(const char *name, size_t len,
ossl_charset_t *out_charset)
{
ossl_charset_t charset = OSSL_CHARSET_ASCII;
size_t i;
for (i = 0; i < len; i++) {
if (name[i] == '\0')
return 0;
if (!ossl_isascii(name[i]))
charset = OSSL_CHARSET_NONASCII;
}
*out_charset = charset;
return 1;
}
/* Default email name input validation */
static int validate_email_name(const char *name, size_t len, int rfc822)
{
size_t dns_len, local_len;
char *at, *dnsname;
ossl_charset_t local_charset;
/*
* 64 for local part, 1 for @, 255 for domain name
*/
if (len > 320)
return 0;
/* Reject it if there is no @ */
if ((at = memchr(name, '@', len)) == NULL)
return 0;
/* Ensure the local part is not oversize */
local_len = len - (at - name);
if (local_len > 64)
return 0;
if (!validate_local_part(name, len, &local_charset))
return 0;
if (rfc822 && local_charset == OSSL_CHARSET_NONASCII)
return 0;
if (!rfc822 && local_charset == OSSL_CHARSET_ASCII)
return 0;
/* What is after the @ must be valid as a dns name */
dnsname = at + 1;
dns_len = len - local_len - 1;
/* It may not have another @ */
if ((at = memchr(dnsname, '@', dns_len)) != NULL)
return 0;
if (rfc822)
return validate_hostname_part(dnsname, dns_len, OSSL_CHARSET_ASCII_ALNUM);
return validate_hostname_part(dnsname, dns_len, OSSL_CHARSET_NONASCII);
}
X509_VERIFY_PARAM *X509_VERIFY_PARAM_new(void)
{
X509_VERIFY_PARAM *param;
@@ -97,10 +375,11 @@ void X509_VERIFY_PARAM_free(X509_VERIFY_PARAM *param)
if (param == NULL)
return;
sk_ASN1_OBJECT_pop_free(param->policies, ASN1_OBJECT_free);
sk_OPENSSL_STRING_pop_free(param->hosts, str_free);
clear_buffer_stack(&param->hosts);
clear_buffer_stack(&param->ips);
clear_buffer_stack(&param->rfc822s);
clear_buffer_stack(&param->smtputf8s);
OPENSSL_free(param->peername);
OPENSSL_free(param->email);
OPENSSL_free(param->ip);
OPENSSL_free(param);
}
@@ -192,24 +471,28 @@ int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest,
x509_verify_param_copy(hostflags, 0);
if (test_x509_verify_param_copy(hosts, NULL)) {
sk_OPENSSL_STRING_pop_free(dest->hosts, str_free);
dest->hosts = NULL;
if (src->hosts != NULL) {
dest->hosts = sk_OPENSSL_STRING_deep_copy(src->hosts, str_copy, str_free);
if (dest->hosts == NULL)
return 0;
}
}
if (test_x509_verify_param_copy(email, NULL)) {
if (!X509_VERIFY_PARAM_set1_email(dest, src->email, src->emaillen))
if (!replace_buffer_stack(&dest->hosts, &src->hosts))
return 0;
}
x509_verify_param_copy(validate_host, NULL);
if (test_x509_verify_param_copy(ip, NULL)) {
if (!X509_VERIFY_PARAM_set1_ip(dest, src->ip, src->iplen))
if (test_x509_verify_param_copy(ips, NULL)) {
if (!replace_buffer_stack(&dest->ips, &src->ips))
return 0;
}
x509_verify_param_copy(validate_ip, NULL);
if (test_x509_verify_param_copy(rfc822s, NULL)) {
if (!replace_buffer_stack(&dest->rfc822s, &src->rfc822s))
return 0;
}
x509_verify_param_copy(validate_rfc822, NULL);
if (test_x509_verify_param_copy(smtputf8s, NULL)) {
if (!replace_buffer_stack(&dest->smtputf8s, &src->smtputf8s))
return 0;
}
x509_verify_param_copy(validate_smtputf8, NULL);
return 1;
}
@@ -231,31 +514,6 @@ int X509_VERIFY_PARAM_set1(X509_VERIFY_PARAM *to,
return ret;
}
static int int_x509_param_set1(char **pdest, size_t *pdestlen,
const char *src, size_t srclen)
{
char *tmp;
if (src != NULL) {
if (srclen == 0)
srclen = strlen(src);
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;
}
OPENSSL_free(*pdest);
*pdest = tmp;
if (pdestlen != NULL)
*pdestlen = srclen;
return 1;
}
int X509_VERIFY_PARAM_set1_name(X509_VERIFY_PARAM *param, const char *name)
{
OPENSSL_free(param->name);
@@ -389,19 +647,169 @@ int X509_VERIFY_PARAM_set1_policies(X509_VERIFY_PARAM *param,
char *X509_VERIFY_PARAM_get0_host(X509_VERIFY_PARAM *param, int idx)
{
return sk_OPENSSL_STRING_value(param->hosts, idx);
X509_BUFFER *buf = sk_X509_BUFFER_value(param->hosts, idx);
return (buf != NULL) ? (char *)buf->data : NULL;
}
int X509_VERIFY_PARAM_set1_host(X509_VERIFY_PARAM *param,
const char *name, size_t namelen)
const char *dnsname, size_t len)
{
return int_x509_param_set_hosts(param, SET_HOST, name, namelen);
clear_buffer_stack(&param->hosts);
if (dnsname == NULL)
return 1;
if (len == 0)
len = strlen(dnsname);
if (len == 0)
return 1;
return X509_VERIFY_PARAM_add1_host(param, dnsname, len);
}
int X509_VERIFY_PARAM_add1_host(X509_VERIFY_PARAM *param,
const char *name, size_t namelen)
const char *dnsname, size_t len)
{
return int_x509_param_set_hosts(param, ADD_HOST, name, namelen);
if (dnsname == NULL)
return 1;
if (len == 0)
len = strlen(dnsname);
if (len == 0)
return 1;
if (!validate_string_name(dnsname, &len))
return 0;
if (param->validate_host != NULL) {
if (!param->validate_host(dnsname, len))
return 0;
} else {
if (!validate_hostname_part(dnsname, len, OSSL_CHARSET_ASCII_ALNUM))
return 0;
}
return add_string_to_buffer_stack(&param->hosts, (const uint8_t *)dnsname, len);
}
void X509_VERIFY_PARAM_set1_host_input_validation(X509_VERIFY_PARAM *param,
int (*validate_host)(const char *name, size_t len))
{
param->validate_host = validate_host;
}
int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
const uint8_t *ip, size_t len)
{
clear_buffer_stack(&param->ips);
if (ip == NULL)
return 1;
return X509_VERIFY_PARAM_add1_ip(param, ip, len);
}
int X509_VERIFY_PARAM_add1_ip(X509_VERIFY_PARAM *param,
const uint8_t *ip, size_t len)
{
if (param->validate_ip != NULL) {
if (!param->validate_ip(ip, len))
return 0;
} else {
if (!validate_ip_name(ip, len))
return 0;
}
return add_bytes_to_buffer_stack(&param->ips, ip, len);
}
void X509_VERIFY_PARAM_set1_ip_input_validation(X509_VERIFY_PARAM *param,
int (*validate_ip)(const uint8_t *name, size_t len))
{
param->validate_ip = validate_ip;
}
char *X509_VERIFY_PARAM_get0_email(X509_VERIFY_PARAM *param)
{
X509_BUFFER *buf = sk_X509_BUFFER_value(param->rfc822s, 0);
if ((buf = sk_X509_BUFFER_value(param->rfc822s, 0)) != NULL
|| (buf = sk_X509_BUFFER_value(param->smtputf8s, 0)) != NULL)
return (char *)buf->data;
return NULL;
}
int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
const char *email, size_t len)
{
int ret = 0;
if (X509_VERIFY_PARAM_set1_smtputf8(param, email, len))
ret = 1;
if (X509_VERIFY_PARAM_set1_rfc822(param, email, len))
ret = 1;
return ret;
}
int X509_VERIFY_PARAM_set1_smtputf8(X509_VERIFY_PARAM *param,
const char *email, size_t len)
{
clear_buffer_stack(&param->smtputf8s);
if (email == NULL)
return 1;
return X509_VERIFY_PARAM_add1_smtputf8(param, email, len);
}
int X509_VERIFY_PARAM_add1_smtputf8(X509_VERIFY_PARAM *param,
const char *email, size_t len)
{
if (len == 0)
len = strlen(email);
if (!validate_string_name(email, &len))
return 0;
if (param->validate_smtputf8 != NULL) {
if (!param->validate_smtputf8(email, len))
return 0;
} else {
if (!validate_email_name(email, len, /*rfc822 =*/0))
return 0;
}
return add_string_to_buffer_stack(&param->smtputf8s,
(const uint8_t *)email, len);
}
void X509_VERIFY_PARAM_set1_smtputf8_input_validation(X509_VERIFY_PARAM *param,
int (*validate_smtputf8)(const char *name, size_t len))
{
param->validate_smtputf8 = validate_smtputf8;
}
int X509_VERIFY_PARAM_set1_rfc822(X509_VERIFY_PARAM *param,
const char *email, size_t len)
{
clear_buffer_stack(&param->rfc822s);
if (email == NULL)
return 1;
return X509_VERIFY_PARAM_add1_rfc822(param, email, len);
}
int X509_VERIFY_PARAM_add1_rfc822(X509_VERIFY_PARAM *param,
const char *email, size_t len)
{
if (len == 0)
len = strlen(email);
if (!validate_string_name(email, &len))
return 0;
if (param->validate_rfc822 != NULL) {
if (!param->validate_rfc822(email, len))
return 0;
} else {
if (!validate_email_name(email, len, /*rfc822 =*/1))
return 0;
}
return add_string_to_buffer_stack(&param->rfc822s,
(const uint8_t *)email, len);
}
void X509_VERIFY_PARAM_set1_rfc822_input_validation(X509_VERIFY_PARAM *param,
int (*validate_rfc822)(const char *name, size_t len))
{
param->validate_rfc822 = validate_rfc822;
}
void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param,
@@ -438,58 +846,59 @@ void X509_VERIFY_PARAM_move_peername(X509_VERIFY_PARAM *to,
from->peername = NULL;
}
char *X509_VERIFY_PARAM_get0_email(X509_VERIFY_PARAM *param)
static const unsigned char *int_X509_VERIFY_PARAM_get0_ip(X509_VERIFY_PARAM *param, size_t *plen, size_t idx)
{
return param->email;
}
X509_BUFFER *buf;
int X509_VERIFY_PARAM_set1_email(X509_VERIFY_PARAM *param,
const char *email, size_t emaillen)
{
return int_x509_param_set1(&param->email, &param->emaillen,
email, emaillen);
}
if (idx > INT_MAX)
return NULL;
static unsigned char *int_X509_VERIFY_PARAM_get0_ip(X509_VERIFY_PARAM *param, size_t *plen)
{
if (param == NULL || param->ip == NULL) {
buf = sk_X509_BUFFER_value(param->ips, (int)idx);
if (param == NULL || param->ips == NULL) {
ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER);
return NULL;
}
if (plen != NULL)
*plen = param->iplen;
return param->ip;
if (buf != NULL) {
if (plen != NULL)
*plen = buf->len;
return (unsigned char *)buf->data;
}
return NULL;
}
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);
/* XXX casts away const */
unsigned char *ip = (unsigned char *)int_X509_VERIFY_PARAM_get0_ip(param, &iplen, 0);
return ip == NULL ? NULL : ossl_ipaddr_to_asc(ip, (int)iplen);
}
int X509_VERIFY_PARAM_set1_ip(X509_VERIFY_PARAM *param,
const unsigned char *ip, size_t iplen)
{
if (iplen != 0 && iplen != 4 && iplen != 16) {
ERR_raise(ERR_LIB_X509, ERR_R_PASSED_INVALID_ARGUMENT);
return 0;
}
return int_x509_param_set1((char **)&param->ip, &param->iplen,
(char *)ip, iplen);
}
int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc)
{
unsigned char ipout[16];
size_t iplen = (size_t)ossl_a2i_ipadd(ipout, ipasc);
size_t iplen;
if (iplen == 0)
if (ipasc == NULL)
return X509_VERIFY_PARAM_set1_ip(param, NULL, 0);
if ((iplen = (size_t)ossl_a2i_ipadd(ipout, ipasc)) == 0)
return 0;
return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen);
}
int X509_VERIFY_PARAM_add1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc)
{
unsigned char ipout[16];
size_t iplen;
if ((iplen = (size_t)ossl_a2i_ipadd(ipout, ipasc)) == 0)
return 0;
return X509_VERIFY_PARAM_add1_ip(param, ipout, iplen);
}
int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param)
{
return param->depth;
@@ -505,8 +914,6 @@ const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param)
return param->name;
}
#define vpm_empty_id NULL, 0U, NULL, NULL, 0, NULL, 0
/*
* Default verify parameters: these are used for various applications and can
* be overridden by the user specified table. NB: the 'name' field *must* be
@@ -514,66 +921,47 @@ const char *X509_VERIFY_PARAM_get0_name(const X509_VERIFY_PARAM *param)
*/
static const X509_VERIFY_PARAM default_table[] = {
{ "code_sign", /* Code sign parameters */
0, /* check time to use */
0, /* inheritance flags */
0, /* flags */
X509_PURPOSE_CODE_SIGN, /* purpose */
X509_TRUST_OBJECT_SIGN, /* trust */
-1, /* depth */
-1, /* auth_level */
NULL, /* policies */
vpm_empty_id },
{ "default", /* X509 default parameters */
0, /* check time to use */
0, /* inheritance flags */
X509_V_FLAG_TRUSTED_FIRST, /* flags */
0, /* purpose */
0, /* trust */
100, /* depth */
-1, /* auth_level */
NULL, /* policies */
vpm_empty_id },
{ "pkcs7", /* S/MIME sign parameters */
0, /* check time to use */
0, /* inheritance flags */
0, /* flags */
X509_PURPOSE_SMIME_SIGN, /* purpose */
X509_TRUST_EMAIL, /* trust */
-1, /* depth */
-1, /* auth_level */
NULL, /* policies */
vpm_empty_id },
{ "smime_sign", /* S/MIME sign parameters */
0, /* check time to use */
0, /* inheritance flags */
0, /* flags */
X509_PURPOSE_SMIME_SIGN, /* purpose */
X509_TRUST_EMAIL, /* trust */
-1, /* depth */
-1, /* auth_level */
NULL, /* policies */
vpm_empty_id },
{ "ssl_client", /* SSL/TLS client parameters */
0, /* check time to use */
0, /* inheritance flags */
0, /* flags */
X509_PURPOSE_SSL_CLIENT, /* purpose */
X509_TRUST_SSL_CLIENT, /* trust */
-1, /* depth */
-1, /* auth_level */
NULL, /* policies */
vpm_empty_id },
{ "ssl_server", /* SSL/TLS server parameters */
0, /* check time to use */
0, /* inheritance flags */
0, /* flags */
X509_PURPOSE_SSL_SERVER, /* purpose */
X509_TRUST_SSL_SERVER, /* trust */
-1, /* depth */
-1, /* auth_level */
NULL, /* policies */
vpm_empty_id }
{
.name = "code_sign", /* Code sign parameters */
.purpose = X509_PURPOSE_CODE_SIGN,
.trust = X509_TRUST_OBJECT_SIGN,
.depth = -1,
.auth_level = -1,
},
{
.name = "default", /* X509 default parameters */
.flags = X509_V_FLAG_TRUSTED_FIRST,
.depth = 100,
.auth_level = -1,
},
{
.name = "pkcs7", /* S/MIME sign parameters */
.purpose = X509_PURPOSE_SMIME_SIGN,
.trust = X509_TRUST_EMAIL,
.depth = -1,
.auth_level = -1,
},
{
.name = "smime_sign", /* S/MIME sign parameters */
.purpose = X509_PURPOSE_SMIME_SIGN,
.trust = X509_TRUST_EMAIL,
.depth = -1,
.auth_level = -1,
},
{
.name = "ssl_client", /* SSL/TLS client parameters */
.purpose = X509_PURPOSE_SSL_CLIENT,
.trust = X509_TRUST_SSL_CLIENT,
.depth = -1,
.auth_level = -1,
},
{
.name = "ssl_server", /* SSL/TLS server parameters */
.purpose = X509_PURPOSE_SSL_SERVER,
.trust = X509_TRUST_SSL_SERVER,
.depth = -1,
.auth_level = -1,
}
};
static STACK_OF(X509_VERIFY_PARAM) *param_table = NULL;
+1 -1
View File
@@ -81,7 +81,7 @@ int main(int argc, char *argv[])
/* The BIO has parsed the host:port and even IPv6 literals in [] */
hostname = BIO_get_conn_hostname(out);
if (!hostname || SSL_set1_host(ssl, hostname) <= 0) {
if (!hostname || SSL_set1_dnsname(ssl, hostname) <= 0) {
BIO_free(ssl_bio);
goto err;
}
+1 -1
View File
@@ -204,7 +204,7 @@ int main(int argc, char *argv[])
* Virtually all clients should do this unless you really know what you
* are doing.
*/
if (!SSL_set1_host(ssl, hostname)) {
if (!SSL_set1_dnsname(ssl, hostname)) {
printf("Failed to set the certificate verification hostname");
goto end;
}
+1 -1
View File
@@ -313,7 +313,7 @@ int main(int argc, char *argv[])
* Virtually all clients should do this unless you really know what you
* are doing.
*/
if (!SSL_set1_host(ssl, hostname)) {
if (!SSL_set1_dnsname(ssl, hostname)) {
printf("Failed to set the certificate verification hostname");
goto end;
}
+1 -1
View File
@@ -231,7 +231,7 @@ int main(int argc, char *argv[])
* Virtually all clients should do this unless you really know what you
* are doing.
*/
if (!SSL_set1_host(ssl, hostname)) {
if (!SSL_set1_dnsname(ssl, hostname)) {
printf("Failed to set the certificate verification hostname");
goto end;
}
+1 -1
View File
@@ -194,7 +194,7 @@ int main(int argc, char *argv[])
* Virtually all clients should do this unless you really know what you
* are doing.
*/
if (!SSL_set1_host(ssl, hostname)) {
if (!SSL_set1_dnsname(ssl, hostname)) {
printf("Failed to set the certificate verification hostname");
goto end;
}
+1 -1
View File
@@ -273,7 +273,7 @@ int main(int argc, char *argv[])
* Virtually all clients should do this unless you really know what you
* are doing.
*/
if (!SSL_set1_host(ssl, hostname)) {
if (!SSL_set1_dnsname(ssl, hostname)) {
printf("Failed to set the certificate verification hostname");
goto end;
}
+1 -1
View File
@@ -416,7 +416,7 @@ OSSL_DEMO_H3_CONN *OSSL_DEMO_H3_CONN_new_for_addr(SSL_CTX *ctx, const BIO_ADDRIN
qconn_bio = NULL;
/* Set the hostname we will validate the X.509 certificate against. */
if (SSL_set1_host(qconn, bare_hostname) <= 0)
if (SSL_set1_dnsname(qconn, bare_hostname) <= 0)
goto err;
/* Configure SNI */
+1 -1
View File
@@ -309,7 +309,7 @@ int main(int argc, char **argv)
/* Set hostname for SNI */
SSL_set_tlsext_host_name(ssl, rem_server_ip);
/* Configure server hostname check */
if (!SSL_set1_host(ssl, rem_server_ip)) {
if (!SSL_set1_dnsname(ssl, rem_server_ip)) {
ERR_print_errors_fp(stderr);
goto exit;
}
+3 -3
View File
@@ -66,7 +66,7 @@ L<SSL_connect(3)> if (and only if) you want to enable DANE for that connection.
The B<basedomain> argument specifies the RFC7671 TLSA base domain,
which will be the primary peer reference identifier for certificate
name checks.
Additional server names can be specified via L<SSL_add1_host(3)>.
Additional server names can be specified via L<SSL_add1_dnsname(3)>.
The B<basedomain> is used as the default SNI hint if none has yet been
specified via L<SSL_set_tlsext_host_name(3)>.
@@ -216,7 +216,7 @@ the lifetime of the SSL connection.
*/
SSL_dane_set_flags(ssl, DANE_FLAG_NO_DANE_EE_NAMECHECKS);
if (!SSL_add1_host(ssl, nexthop_domain))
if (!SSL_add1_dnsname(ssl, nexthop_domain))
/* error */
SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
@@ -353,7 +353,7 @@ L<SSL_set_verify(3)> with B<mode> equal to B<SSL_VERIFY_NONE>.
L<ssl(7)>,
L<SSL_new(3)>,
L<SSL_add1_host(3)>,
L<SSL_add1_dnsname(3)>,
L<SSL_set_hostflags(3)>,
L<SSL_set_tlsext_host_name(3)>,
L<SSL_set_verify(3)>,
+79 -28
View File
@@ -2,7 +2,10 @@
=head1 NAME
SSL_set1_host, SSL_add1_host, SSL_set_hostflags, SSL_get0_peername -
SSL_set1_dnsname, SSL_add1_dnsname,
SSL_set1_ipaddr, SSL_add1_ipaddr,
SSL_set1_host, SSL_add1_host,
SSL_set_hostflags, SSL_get0_peername -
SSL server verification parameters
=head1 SYNOPSIS
@@ -11,39 +14,58 @@ SSL server verification parameters
int SSL_set1_host(SSL *s, const char *host);
int SSL_add1_host(SSL *s, const char *host);
int SSL_set1_dnsname(SSL *s, const char *dnsname);
int SSL_add1_dnsname(SSL *s, const char *dnsname);
int SSL_set1_ipaddr(SSL *s, const uint8_t *ip, size_t len);
int SSL_add1_ipaddr(SSL *s, const uint8_t *ip size_t len);
void SSL_set_hostflags(SSL *s, unsigned int flags);
const char *SSL_get0_peername(SSL *s);
int SSL_set1_host(SSL *s, const char *host);
int SSL_add1_host(SSL *s, const char *host);
=head1 DESCRIPTION
These functions configure server hostname checks in the SSL client.
These functions maintain lists of expected matches for peer
certificate subject alternate name (SAN) values is peer certificates
presented in an SSL connection. A peer certificate will be considered
a match for validation purposes if all of the following is true:
SSL_set1_host() sets in the verification parameters of I<s>
the expected DNS hostname or IP address to I<host>,
clearing any previously specified IP address and hostnames.
If I<host> is NULL or the empty string, IP address
and hostname checks are not performed on the peer certificate.
When a nonempty I<host> is specified, certificate verification automatically
checks the peer hostname via L<X509_check_host(3)> with I<flags> as specified
via SSL_set_hostflags(). Clients that enable DANE TLSA authentication
via L<SSL_dane_enable(3)> should leave it to that function to set
the primary reference identifier of the peer, and should not call
SSL_set1_host().
* Any name in the dnsname list, if not empty, matches any SAN dnsname
in the certificate. If verification flags allow it, these will also
attempt to match against the CN in the subject.
SSL_add1_host() adds I<host> as an additional reference identifier
that can match the peer's certificate. Any previous hostnames
set via SSL_set1_host() or SSL_add1_host() are retained.
Adding an IP address is allowed only if no IP address has been set before.
No change is made if I<host> is NULL or empty.
When an IP address and/or multiple hostnames are configured,
the peer is considered verified when any of these matches.
This function is required for DANE TLSA in the presence of service name indirection
via CNAME, MX or SRV records as specified in RFCs 7671, 7672, and 7673.
* Any address in the IP address list, if not empty, matches any IP
address SAN in the certificate.
TLS clients are recommended to use SSL_set1_host() or SSL_add1_host()
for server hostname or IP address validation,
as well as L<SSL_set_tlsext_host_name(3)> for Server Name Indication (SNI),
which may be crucial also for correct routing of the connection request.
The set1 family of functions clears the list, and sets the first value
to a the provided parameter if the provided parameter is not NULL.
The add1 family of functions adds a single entry to the list.
SSL_set1_dnsname() clears the list of dnsnames to match certificate
SAN dnsnames.
If I<dnsname> is not NULL, it will be checked for
validity and added to the list of DNS name reference identifiers as its first entry.
SSL_set1_ipaddr() clears the list of addresses to match certificate IP address SANs.
If <ip_asc> is not NULL, it is parsed as an
IPv4 or IPv6 address and added to the list as its first entry.
SSL_add1_dnsname() adds I<dnsname> to the list of DNS name reference
identifiers, if it has the correct structure for a DNS name. This
function is required for DANE TLSA in the presence of service name
indirection via CNAME, MX or SRV records as specified in RFCs 7671,
7672, and 7673.
SSL_add1_ipaddr() adds I<ip> to the list of IP addresses, if it parses as an IP address.
It is recommended that TLS clients use SSL_set1_dnsname() to configure server
hostname validation and L<SSL_set_tlsext_host_name(3)> to configure
Server Name Indication (SNI), which may be crucial also for correct
server certificate selection and/or routing of the connection request.
SSL_set1_ip(), or SSL_set1_ip_asc()
should be used for server IP address validation,
SSL_set_hostflags() sets the I<flags> that will be passed to
L<X509_check_host(3)> when name checks are applicable, by default
@@ -68,8 +90,35 @@ of scope with the RFC 7671 DANE-EE(3) certificate usage, and the
internal check will be suppressed as appropriate when DANE is
enabled.
==head1 DEPRECATED FUNCTIONS
SSL_set1_host and SSL_add1_host are deprecated as of OpenSSL 4.0.0.
SSL_add1_dnsame and SSL_add1_ip should be used instead.
SSL_set1_host() sets in the verification parameters of I<s>
the expected DNS hostname or IP address to I<host>,
clearing any previously specified IP address and hostnames.
If I<host> is NULL or the empty string, IP address
and hostname checks are not performed on the peer certificate.
When a nonempty I<host> is specified, certificate verification automatically
checks the peer hostname via L<X509_check_host(3)> with I<flags> as specified
via SSL_set_hostflags(). Clients that enable DANE TLSA authentication
via L<SSL_dane_enable(3)> should leave it to that function to set
the primary reference identifier of the peer, and should not call
SSL_set1_host().
SSL_add1_host() adds I<host> as an additional reference identifier
that can match the peer's certificate. Any previous hostnames set via
SSL_set1_host() or SSL_add1_host() are retained. Adding an IP address
is allowed only if no IP address has been set before. No change is
made if I<host> is NULL or empty. The peer is considered verified
when any of the added hostnames, if present, match, and the provided
IP address, if present, matches.
=head1 RETURN VALUES
SSL_set1_dnsname, SSL_set1_ip, SSL_set1_ip_asc,
SSL_add1_dnsname, SSL_add1_ip, SSL_add1_ip_asc,
SSL_set1_host() and SSL_add1_host() return 1 for success and 0 for
failure.
@@ -91,9 +140,9 @@ and must be copied by the application if it is to be retained beyond
the lifetime of the SSL connection.
SSL_set_hostflags(ssl, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
if (!SSL_set1_host(ssl, "smtp.example.com"))
if (!SSL_set1_dnsname(ssl, "smtp.example.com"))
/* error */
if (!SSL_add1_host(ssl, "example.com"))
if (!SSL_add1_dnsname(ssl, "example.com"))
/* error */
/* XXX: Perform SSL_connect() handshake and handle errors here */
@@ -115,6 +164,8 @@ L<SSL_get_verify_result(3)>, L<SSL_dane_enable(3)>
These functions were added in OpenSSL 1.1.0.
SSL_set1_host and SSL_add1_host were deprecated in OpenSSL 4.0.0
=head1 COPYRIGHT
Copyright 2016-2025 The OpenSSL Project Authors. All Rights Reserved.
+98 -8
View File
@@ -16,9 +16,17 @@ 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_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_VERIFY_PARAM_get0_email,
X509_VERIFY_PARAM_set1_email,
X509_VERIFY_PARAM_set1_rfc822, X509_VERIFY_PARAM_add1_rfc822,
X509_VERIFY_PARAM_set1_smtputf8, X509_VERIFY_PARAM_add1_smtputf8,
X509_VERIFY_PARAM_set1_ip, X509_VERIFY_PARAM_add1_ip,
X509_VERIFY_PARAM_set1_ip_asc, X509_VERIFY_PARAM_add1_ip_asc,
X509_VERIFY_PARAM_get1_ip_asc,
X509_VERIFY_PARAM_set1_host_input_validation,
X509_VERIFY_PARAM_set1_rfc822_input_validation,
X509_VERIFY_PARAM_set1_smtputf8_input_validation,
X509_VERIFY_PARAM_set1_ip_input_validation
- X509 verification parameters
=head1 SYNOPSIS
@@ -66,10 +74,29 @@ X509_VERIFY_PARAM_set1_ip_asc
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);
int X509_VERIFY_PARAM_set1_rfc822(X509_VERIFY_PARAM *param,
const char *email, size_t emaillen);
int X509_VERIFY_PARAM_add1_rfc822(X509_VERIFY_PARAM *param,
const char *email, size_t emaillen);
int X509_VERIFY_PARAM_set1_smtputf8(X509_VERIFY_PARAM *param,
const char *email, size_t emaillen);
int X509_VERIFY_PARAM_add1_smtputf8(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_add1_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);
int X509_VERIFY_PARAM_add1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc);
void X509_VERIFY_PARAM_set1_ip_input_validation(X509_VERIFY_PARAM *param,
int (*validate_ip)(const uint8_t *name, size_t len));
void X509_VERIFY_PARAM_set1_host_input_validation(X509_VERIFY_PARAM *param,
int (*validate_host)(const char *name, size_t len));
void X509_VERIFY_PARAM_set1_rfc822_input_validation(X509_VERIFY_PARAM *param,
int (*validate_rfc822)(const char *name, size_t len));
void X509_VERIFY_PARAM_set1_smtputf8_input_validation(X509_VERIFY_PARAM *param,
int (*validate_smtputf8)(const char *name, size_t len));
=head1 DESCRIPTION
@@ -195,14 +222,45 @@ 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
X509_VERIFY_PARAM_set1_rfc822() clears all expected RFC822 email
addresses, and sets the expected RFC822 email address to I<email>. If
I<email> is NULL no expected address is set. Otherwise, if
I<emaillen> is zero, I<email> must be NUL-terminated; if I<emaillen>
is nonzero, I<emaillen> must be set to the length of I<email>. When
any email address is specified, certificate verification automatically
invokes L<X509_check_email(3)>.
X509_VERIFY_PARAM_add1_rfc822() adds I<email> as an additional
reference identifier that can match RFC822 email addresses in the
peer's certificate. Any previous names set via
X509_VERIFY_PARAM_set1_rfc822(), X509_VERIFY_PARAM_add1_rfc822(), or
X509_VERIFY_PARAM_set1_email() are
retained on success, no change is made on failure. It is a failure if
email is NULL or the empty string.The peer is considered verified
when any one of the specified RFC822 or SMTPUTF8 names matches a corresponding email
address SAN in the certificate.
X509_VERIFY_PARAM_set1_smtputf8() sets the expected SMTPUTF8 email address to
I<email>.
If I<email> is NULL, email checking is disabled. Otherwise,
If I<email> is NULL, SMTPUTF8 email checking is disabled. Otherwise,
if I<emaillen> is zero, I<email> must be NUL-terminated; if I<emaillen> is nonzero,
I<emaillen> must be set to the length of I<email>. When an email address
I<emaillen> must be set to the length of I<email>. When any email address
is specified, certificate verification automatically invokes
L<X509_check_email(3)>.
X509_VERIFY_PARAM_add1_smtputf8() adds I<email> as an additional
reference identifier that can match SMTPUTF8 email addresses in the
peer's certificate. Any previous names set via
X509_VERIFY_PARAM_set1_smtputf8(), X509_VERIFY_PARAM_add1_smtputf8(), or
X509_VERIFY_PARAM_set1_email() are
retained on success, no change is made on failure. It is a failure if
email is NULL or the empty string. The peer is considered verified
when any one of the specified RFC822 or SMTPUTF8 names matches a corresponding email
address SAN in the certificate.
X509_VERIFY_PARAM_set1_email() calls X509_VERIFY_PARAM_set_rfc822(), and
X509_VERIFY_PARAM_set_smtputf8() and succeeds if any call succeeds.
X509_VERIFY_PARAM_get1_ip_asc() returns the expected IP address as a string.
The caller is responsible for freeing it.
@@ -213,11 +271,41 @@ I<iplen> must be set to 4 for IPv4 and 16 for IPv6. When an IP
address is specified, certificate verification automatically invokes
L<X509_check_ip(3)>.
X509_VERIFY_PARAM_add1_ip() adds I<ip> as an additional reference
identifier that can match the peer's certificate on success. Any
previous names set via X509_VERIFY_PARAM_set1_ip(),
X509_VERIFY_PARAM_add1_ip(), X509_VERIFY_PARAM_set1_ip_asc(), or
X509_VERIFY_PARAM_add1_ip_asc() are retained. No change is made on
failure. It is a failure if <ip> is NULL or the empty string. When
multiple names are configured, the peer is considered verified when
any name matches.
X509_VERIFY_PARAM_set1_ip_asc() sets the expected IP address to
I<ipasc>. The I<ipasc> argument must be a NUL-terminated ASCII string:
dotted decimal quad for IPv4 and colon-separated hexadecimal for
IPv6. The condensed "::" notation is supported for IPv6 addresses.
X509_VERIFY_PARAM_add1_ip_asc() adds I<ip_asc> as an additional
reference identifier that can match the peer's certificate on success.
The I<ipasc> argument must be a NUL-terminated ASCII string: dotted
decimal quad for IPv4 and colon-separated hexadecimal for IPv6. The
condensed "::" notation is supported for IPv6 addresses. Any previous
names set via X509_VERIFY_PARAM_set1_ip(),
X509_VERIFY_PARAM_add1_ip(), X509_VERIFY_PARAM_set1_ip_asc(), or
X509_VERIFY_PARAM_add1_ip_asc() are retained. No change is made on
failure. It is a failure if I<ip_asc> is NULL or the empty string.
When multiple names are configured, the peer is considered verified
when any one of the specified addresses matches a corresponding IP address SAN in the certificate.
X509_VERIFY_PARAM_set1_host_input_validation(),
X509_VERIFY_PARAM_set1_rfc822_input_validation(),
X509_VERIFY_PARAM_set1_smtputf8_input_validation(), and
X509_VERIFY_PARAM_set1_ip_input_validation() set a verification
function to validate the input on setting the corresponding validation
parameter expected values. These functions bypass OpenSSL's input validation
to these commands. if the provided function succeeds, the corresponding
input will be accepted and attempted to be used when verifying certificates.
=head1 RETURN VALUES
X509_VERIFY_PARAM_set_flags(), X509_VERIFY_PARAM_clear_flags(),
@@ -225,8 +313,10 @@ X509_VERIFY_PARAM_set_inh_flags(),
X509_VERIFY_PARAM_set_purpose(), X509_VERIFY_PARAM_set_trust(),
X509_VERIFY_PARAM_add0_policy() X509_VERIFY_PARAM_set1_policies(),
X509_VERIFY_PARAM_set1_host(), X509_VERIFY_PARAM_add1_host(),
X509_VERIFY_PARAM_set1_email(), X509_VERIFY_PARAM_set1_ip() and
X509_VERIFY_PARAM_set1_ip_asc() return 1 for success and 0 for
X509_VERIFY_PARAM_set1_email(),
X509_VERIFY_PARAM_set1_ip(), X509_VERIFY_PARAM_add1_ip(),
X509_VERIFY_PARAM_set1_ip_asc(),
X509_VERIFY_PARAM_add1_ip_asc() return 1 for success and 0 for
failure.
X509_VERIFY_PARAM_get0_host(), X509_VERIFY_PARAM_get0_email(), and
+8 -2
View File
@@ -1872,8 +1872,14 @@ __owur int SSL_set_purpose(SSL *ssl, int purpose);
__owur int SSL_CTX_set_trust(SSL_CTX *ctx, int trust);
__owur int SSL_set_trust(SSL *ssl, int trust);
__owur int SSL_set1_host(SSL *s, const char *host);
__owur int SSL_add1_host(SSL *s, const char *host);
#ifndef OPENSSL_NO_DEPRECATED_4_0
OSSL_DEPRECATEDIN_4_0 __owur int SSL_set1_host(SSL *s, const char *host);
OSSL_DEPRECATEDIN_4_0 __owur int SSL_add1_host(SSL *s, const char *host);
#endif /* OPENSSL_NO_DEPRECATED_4_0 */
__owur int SSL_set1_dnsname(SSL *s, const char *dnsname);
__owur int SSL_add1_dnsname(SSL *s, const char *dnsname);
__owur int SSL_set1_ipaddr(SSL *s, const char *ipaddr);
__owur int SSL_add1_ipaddr(SSL *s, const char *ipaddr);
__owur const char *SSL_get0_peername(SSL *s);
void SSL_set_hostflags(SSL *s, unsigned int flags);
+21 -1
View File
@@ -762,6 +762,8 @@ 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,
const char *name, size_t namelen);
void X509_VERIFY_PARAM_set1_host_input_validation(X509_VERIFY_PARAM *param,
int (*validate_host)(const char *name, size_t len));
void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param,
unsigned int flags);
unsigned int X509_VERIFY_PARAM_get_hostflags(const X509_VERIFY_PARAM *param);
@@ -770,11 +772,29 @@ 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);
int X509_VERIFY_PARAM_set1_rfc822(X509_VERIFY_PARAM *param,
const char *email, size_t emaillen);
int X509_VERIFY_PARAM_add1_rfc822(X509_VERIFY_PARAM *param,
const char *email, size_t len);
void X509_VERIFY_PARAM_set1_rfc822_input_validation(X509_VERIFY_PARAM *param,
int (*validate_rfc822)(const char *name, size_t len));
int X509_VERIFY_PARAM_set1_smtputf8(X509_VERIFY_PARAM *param,
const char *email, size_t emaillen);
int X509_VERIFY_PARAM_add1_smtputf8(X509_VERIFY_PARAM *param,
const char *email, size_t len);
void X509_VERIFY_PARAM_set1_smtputf8_input_validation(X509_VERIFY_PARAM *param,
int (*validate_smtputf8)(const char *name, size_t len));
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);
const uint8_t *ip, size_t iplen);
void X509_VERIFY_PARAM_set1_ip_input_validation(X509_VERIFY_PARAM *param,
int (*validate_ip)(const uint8_t *name, size_t len));
int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param,
const char *ipasc);
int X509_VERIFY_PARAM_add1_ip(X509_VERIFY_PARAM *param,
const uint8_t *ip, size_t len);
int X509_VERIFY_PARAM_add1_ip_asc(X509_VERIFY_PARAM *param,
const char *ipasc);
int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param);
int X509_VERIFY_PARAM_get_auth_level(const X509_VERIFY_PARAM *param);
+42
View File
@@ -1140,6 +1140,47 @@ int SSL_set_trust(SSL *s, int trust)
return X509_VERIFY_PARAM_set_trust(sc->param, trust);
}
int SSL_set1_dnsname(SSL *s, const char *host)
{
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
if (sc == NULL)
return 0;
return X509_VERIFY_PARAM_set1_host(sc->param, host, 0);
}
int SSL_add1_dnsname(SSL *s, const char *host)
{
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
if (sc == NULL)
return 0;
return X509_VERIFY_PARAM_add1_host(sc->param, host, strlen(host));
}
int SSL_set1_ipaddr(SSL *s, const char *ipaddr)
{
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
if (sc == NULL)
return 0;
return X509_VERIFY_PARAM_set1_ip_asc(sc->param, ipaddr);
}
int SSL_add1_ipaddr(SSL *s, const char *ipaddr)
{
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
if (sc == NULL)
return 0;
return X509_VERIFY_PARAM_add1_ip_asc(sc->param, ipaddr);
}
#if !defined(OPENSSL_NO_DEPRECATED_4_0)
int SSL_set1_host(SSL *s, const char *host)
{
SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
@@ -1190,6 +1231,7 @@ int SSL_add1_host(SSL *s, const char *host)
return X509_VERIFY_PARAM_add1_host(sc->param, host, 0);
}
#endif /* !defined(OPENSSL_NO_DEPRECATED_4_0) */
void SSL_set_hostflags(SSL *s, unsigned int flags)
{
@@ -783,7 +783,7 @@ static int setup_connection(char *hostname, char *port,
* Virtually all clients should do this unless you really know what you
* are doing.
*/
if (!SSL_set1_host(*ssl, hostname)) {
if (!SSL_set1_dnsname(*ssl, hostname)) {
fprintf(stderr, "Failed to set the certificate verification hostname");
goto end;
}
+427
View File
@@ -201,6 +201,431 @@ static int test_self_signed(const char *filename, int use_trusted, int expected)
return ret;
}
static const char *multiname_cert[] = {
"-----BEGIN CERTIFICATE-----\n"
"MIIFnDCCBISgAwIBAgIUTgfdSQm2hjgUZoA8jeQX7sDPAoowDQYJKoZIhvcNAQEL\n"
"BQAwgYUxCzAJBgNVBAYTAkNBMRAwDgYDVQQIDAdBbGJlcnRhMREwDwYDVQQHDAhF\n"
"ZG1vbnRvbjERMA8GA1UECgwITXVwcGV0cnkxITAfBgNVBAsMGFN0YXRsZXIgYW5k\n"
"IFdhbGRvcmYgUiBVUzEbMBkGA1UEAwwSYmVha2VyLm11cHBldHJ5LmNhMB4XDTI2\n"
"MDExMjIwNTUwOVoXDTI3MDExMjIwNTUwOVowgYUxCzAJBgNVBAYTAkNBMRAwDgYD\n"
"VQQIDAdBbGJlcnRhMREwDwYDVQQHDAhFZG1vbnRvbjERMA8GA1UECgwITXVwcGV0\n"
"cnkxITAfBgNVBAsMGFN0YXRsZXIgYW5kIFdhbGRvcmYgUiBVUzEbMBkGA1UEAwwS\n"
"YmVha2VyLm11cHBldHJ5LmNhMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC\n"
"AQEA+EsGQCX4YyZF3QbVcFUcWpYDp8MJHr5vF0cosvj9afGPhpLREWR7EmnNA8Gf\n"
"wb+ef/jNrDg8W81uDD3N29PvbM+hHAQPaHrRupQZ+W+uIVEAu/lpI359jIRS1Sey\n"
"IcU2vIgn3Tlnv4UX3o3QMyH8+RcCvSNrWu4+f9ipMAy/xq3PWBm+fHi/+bI03eDy\n"
"0xNm8kpXbhqZQiZ1tAhsTa3V2pIufqAnctDgl2GUHtfmKO095OHimjhQXHxO8Ctk\n"
"R+vFv0nleJoAAfkmaMdtdTd1O8m3AtQv6xQC4X5Tu/+FKKQOXjf/8OtqW2lrlxxR\n"
"pbFuy66I9HVyf+gGWEbZyqbCpwIDAQABo4ICADCCAfwwggG3BgNVHREEggGuMIIB\n"
"qoILbXVwcGV0cnkuY2GCD3d3dy5tdXBwZXRyeS5jYYITc3RhdGxlci5tdXBwZXRy\n"
"eS5jYYITd2FsZG9yZi5tdXBwZXRyeS5jYYETc3RhdGxlckBtdXBwdGVyeS5jYYET\n"
"d2FsZG9yZkBtdXBwdGVyeS5jYYcExikABIcQIAEFA7o+AAAAAAAAAAIAMIcEqveq\n"
"AocQKAEBuAAQAAAAAAAAAAAAC4cEwCEEDIcQIAEFAAACAAAAAAAAAAAADIcExwdb\n"
"DYcQIAEFAAAtAAAAAAAAAAAADYcEwMvmCocQIAEFAACoAAAAAAAAAAAADocEwAUF\n"
"8YcQIAEFAAAvAAAAAAAAAAAAD4cEwHAkBIcQIAEFAAASAAAAAAAAAAANDYcExmG+\n"
"NYcQIAEFAAABAAAAAAAAAAAAU4cEwCSUEYcQIAEH/gAAAAAAAAAAAAAAU4cEwDqA\n"
"HocQIAEFAwwnAAAAAAAAAAIAMIcEwQAOgYcQIAEH/QAAAAAAAAAAAAAAAYcExwdT\n"
"KocQIAEFAACfAAAAAAAAAAAAQocEygwbIYcQIAENwwAAAAAAAAAAAAAANTALBgNV\n"
"HQ8EBAMCBDAwEwYDVR0lBAwwCgYIKwYBBQUHAwEwHQYDVR0OBBYEFCutBN63ufhB\n"
"IY4dOuFcYfC3p+mMMA0GCSqGSIb3DQEBCwUAA4IBAQBBWfTvwxV1s3xaS5Ko6T7B\n"
"vS7TPih0MO8auv0mvZXG3jy/LfAfgu05PbGIf0dzFhBpoZD0VrrugmdemLkJd+u6\n"
"pbEttGFZtcGb//MtjUAYQnEq6fYgDeT0dGU0upwQPWGgh5LpFSab+71C6Ofc3YFM\n"
"WPH7UaRBUV2mqNtUokOce6kYtl97St7p6cGpQW9Q1uFQODvAm3ZPq/YNGnTJAOdb\n"
"9UX8Td1T5fH86H0hb6qB0AEhVdgjPUgs33zYNWRPg8fYleT6w1MpE2HaUqqhld3B\n"
"ZtVZ5IznkY+8qH0rua89m4TV3qzUqNVUL0uxkWnQI3W8g3Adin7QN3EA6ZYrTD3q\n"
"-----END CERTIFICATE-----\n",
NULL,
};
static const time_t multiname_valid_at = 1768253189;
static const char *multiname_dnsnames[] = {
"muppetry.ca",
"www.muppetry.ca",
"statler.muppetry.ca",
"waldorf.muppetry.ca",
NULL,
};
static const char *multiname_emails[] = {
"statler@mupptery.ca",
"waldorf@mupptery.ca",
NULL,
};
static const char *multiname_ips[] = {
"198.41.0.4",
"2001:503:ba3e::2:30",
"170.247.170.2",
"2801:1b8:10::b",
"192.33.4.12",
"2001:500:2::c",
"199.7.91.13",
"2001:500:2d::d",
"192.203.230.10",
"2001:500:a8::e",
"192.5.5.241",
"2001:500:2f::f",
"192.112.36.4",
"2001:500:12::d0d",
"198.97.190.53",
"2001:500:1::53",
"192.36.148.17",
"2001:7fe::53",
"192.58.128.30",
"2001:503:c27::2:30",
"193.0.14.129",
"2001:7fd::1",
"199.7.83.42",
"2001:500:9f::42",
"202.12.27.33",
"2001:dc3::35",
NULL,
};
static int test_multiname_selfsigned(void)
{
X509 *cert = NULL;
X509_STORE_CTX *ctx = NULL;
X509_STORE *store = NULL;
X509_VERIFY_PARAM *vpm = NULL;
int fails = 0;
int ret = 0;
if (!TEST_ptr((cert = X509_from_strings(multiname_cert))))
goto err;
if (!TEST_true(X509_self_signed(cert, 1)))
goto err;
if (!TEST_ptr(store = X509_STORE_new()))
goto err;
if (!TEST_true(X509_STORE_add_cert(store, cert)))
goto err;
if (!TEST_ptr((vpm = X509_STORE_get0_param(store))))
goto err;
if (!TEST_ptr(ctx = X509_STORE_CTX_new()))
goto err;
X509_VERIFY_PARAM_set_time(vpm, multiname_valid_at);
for (size_t i = 0; multiname_dnsnames[i] != NULL; i++) {
/* Try one not in the certificate */
if (!TEST_true(X509_VERIFY_PARAM_set1_host(vpm, "bunsen.muppetry.ca", 0)))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_false(X509_verify_cert(ctx))) {
TEST_info("Verify succeeded for non-present name bunsen.muppetry.ca\n");
goto err;
}
X509_STORE_CTX_cleanup(ctx);
if (!TEST_true(X509_VERIFY_PARAM_set1_host(vpm, NULL, 0)))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_true(X509_verify_cert(ctx)))
goto err;
X509_STORE_CTX_cleanup(ctx);
if (!TEST_true(X509_VERIFY_PARAM_set1_host(vpm, multiname_dnsnames[i], strlen(multiname_dnsnames[i]))))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_true(X509_verify_cert(ctx))) {
TEST_info("Verify failed for initial name %s\n", multiname_dnsnames[i]);
fails++;
}
X509_STORE_CTX_cleanup(ctx);
for (size_t j = 0; multiname_dnsnames[j] != NULL; j++) {
if (j != i) {
if (!TEST_true(X509_VERIFY_PARAM_add1_host(vpm, multiname_dnsnames[j], 0)))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_true(X509_verify_cert(ctx))) {
TEST_info("Verify failed with added name %s\n", multiname_dnsnames[j]);
fails++;
}
X509_STORE_CTX_cleanup(ctx);
}
}
/* Try the CN */
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_true(X509_VERIFY_PARAM_set1_host(vpm, "beaker.muppetry.ca", 0)))
goto err;
if (!TEST_true(X509_verify_cert(ctx))) {
TEST_info("Verify failed for CN name beaker.muppetry.ca\n");
fails++;
}
X509_STORE_CTX_cleanup(ctx);
if (!TEST_true(X509_VERIFY_PARAM_set1_host(vpm, NULL, 0)))
goto err;
}
for (size_t i = 0; multiname_emails[i] != NULL; i++) {
/* Try one not in the certificate */
if (!TEST_true(X509_VERIFY_PARAM_set1_email(vpm, "bunsen@muppetry.ca", 0)))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_false(X509_verify_cert(ctx))) {
TEST_info("Verify succeeded for non-present name bunsen@muppetry.ca\n");
goto err;
}
X509_STORE_CTX_cleanup(ctx);
if (!TEST_true(X509_VERIFY_PARAM_set1_email(vpm, NULL, 0)))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_true(X509_verify_cert(ctx)))
goto err;
X509_STORE_CTX_cleanup(ctx);
if (!TEST_true(X509_VERIFY_PARAM_set1_email(vpm, multiname_emails[i], strlen(multiname_emails[i]))))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_true(X509_verify_cert(ctx))) {
TEST_info("Verify failed for initial name %s\n", multiname_emails[i]);
fails++;
}
X509_STORE_CTX_cleanup(ctx);
for (size_t j = 0; multiname_emails[j] != NULL; j++) {
if (j != i) {
if (!TEST_true(X509_VERIFY_PARAM_add1_rfc822(vpm, multiname_emails[j], 0)))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_true(X509_verify_cert(ctx))) {
TEST_info("Verify failed with added name %s\n", multiname_emails[j]);
fails++;
}
X509_STORE_CTX_cleanup(ctx);
}
}
X509_STORE_CTX_cleanup(ctx);
if (!TEST_true(X509_VERIFY_PARAM_set1_email(vpm, NULL, 0)))
goto err;
}
for (size_t i = 0; multiname_ips[i] != NULL; i++) {
/* Try one not in the certificate */
if (!TEST_true(X509_VERIFY_PARAM_set1_ip_asc(vpm, "8.8.8.8")))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_false(X509_verify_cert(ctx))) {
TEST_info("Verify succeeded for non-present name 8.8.8.8\n");
goto err;
}
X509_STORE_CTX_cleanup(ctx);
if (!TEST_true(X509_VERIFY_PARAM_set1_ip_asc(vpm, NULL)))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_true(X509_verify_cert(ctx)))
goto err;
X509_STORE_CTX_cleanup(ctx);
if (!TEST_true(X509_VERIFY_PARAM_set1_ip_asc(vpm, multiname_ips[i])))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_true(X509_verify_cert(ctx))) {
TEST_info("Verify failed for initial name %s\n", multiname_ips[i]);
fails++;
}
X509_STORE_CTX_cleanup(ctx);
for (size_t j = 0; multiname_ips[j] != NULL; j++) {
if (j != i) {
if (!TEST_true(X509_VERIFY_PARAM_add1_ip_asc(vpm, multiname_ips[j])))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_true(X509_verify_cert(ctx))) {
TEST_info("Verify failed with added name %s\n", multiname_ips[j]);
fails++;
}
X509_STORE_CTX_cleanup(ctx);
}
}
X509_STORE_CTX_cleanup(ctx);
if (!TEST_true(X509_VERIFY_PARAM_set1_ip_asc(vpm, NULL)))
goto err;
}
/*
* Test that individual categories work together, and a non-match will still fail validation
*/
/* A dnsname, email and ip that are all valid in the cert should succeed */
if (!TEST_true(X509_VERIFY_PARAM_set1_host(vpm, "www.muppetry.ca", 0)))
goto err;
if (!TEST_true(X509_VERIFY_PARAM_set1_ip_asc(vpm, "2001:503:ba3e::2:30")))
goto err;
if (!TEST_true(X509_VERIFY_PARAM_set1_email(vpm, "waldorf@mupptery.ca", 0)))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_true(X509_verify_cert(ctx)))
fails++;
X509_STORE_CTX_cleanup(ctx);
/* Setting an non-matching email should fail validation even with valid dnsname and ip */
if (!TEST_true(X509_VERIFY_PARAM_set1_email(vpm, "bunsen@mupptery.ca", 0)))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_false(X509_verify_cert(ctx)))
fails++;
X509_STORE_CTX_cleanup(ctx);
/* reset */
if (!TEST_true(X509_VERIFY_PARAM_set1_email(vpm, "waldorf@mupptery.ca", 0)))
goto err;
/* Setting an non-matching ip should fail validation even with valid dnsname and email */
if (!TEST_true(X509_VERIFY_PARAM_set1_ip_asc(vpm, "199.185.178.80")))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_false(X509_verify_cert(ctx)))
fails++;
X509_STORE_CTX_cleanup(ctx);
/* reset */
if (!TEST_true(X509_VERIFY_PARAM_set1_ip_asc(vpm, "2001:503:ba3e::2:30")))
goto err;
/* Setting an non-matching dnsname should fail validation even with valid ip and email */
if (!TEST_true(X509_VERIFY_PARAM_set1_host(vpm, "www.libressl.org", 0)))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_false(X509_verify_cert(ctx)))
fails++;
X509_STORE_CTX_cleanup(ctx);
/* reset */
if (!TEST_true(X509_VERIFY_PARAM_set1_host(vpm, "www.muppetry.ca", 0)))
goto err;
/* Adding non-matching values to each category with a match will still succeed */
if (!TEST_true(X509_VERIFY_PARAM_add1_host(vpm, "www.libressl.org", 0)))
goto err;
if (!TEST_true(X509_VERIFY_PARAM_add1_ip_asc(vpm, "199.185.178.80")))
goto err;
if (!TEST_true(X509_VERIFY_PARAM_add1_rfc822(vpm, "beck@openbsd.org", 0)))
goto err;
if (!TEST_true(X509_VERIFY_PARAM_add1_smtputf8(vpm, "学生@muppetry.ca", 0)))
goto err;
if (!TEST_true(X509_STORE_CTX_init(ctx, store, cert, NULL)))
goto err;
if (!TEST_true(X509_verify_cert(ctx)))
fails++;
X509_STORE_CTX_cleanup(ctx);
ret = fails == 0;
err:
X509_STORE_free(store);
X509_STORE_CTX_free(ctx);
X509_free(cert);
return ret;
}
static int yolo_name_validation(const char *name, size_t len)
{
return 1;
}
static int yolo_ip_validation(const uint8_t *name, size_t len)
{
return 1;
}
static int test_vpm_input_validation(void)
{
const char *utf8mail = "学生@muppetry.ca";
const char *rfc822mail = "beaker@muppetry.ca";
X509_VERIFY_PARAM *vpm = NULL;
int ret = 0;
if (!TEST_ptr(vpm = X509_VERIFY_PARAM_new()))
goto err;
if (!TEST_false(X509_VERIFY_PARAM_set1_rfc822(vpm, utf8mail, 0)))
goto err;
if (!TEST_false(X509_VERIFY_PARAM_set1_smtputf8(vpm, rfc822mail, 0)))
goto err;
if (!TEST_true(X509_VERIFY_PARAM_set1_rfc822(vpm, rfc822mail, 0)))
goto err;
if (!TEST_true(X509_VERIFY_PARAM_set1_smtputf8(vpm, utf8mail, 0)))
goto err;
if (!TEST_true(X509_VERIFY_PARAM_set1_email(vpm, rfc822mail, 0)))
goto err;
if (!TEST_true(X509_VERIFY_PARAM_set1_email(vpm, utf8mail, 0)))
goto err;
for (size_t i = 0; multiname_dnsnames[i] != NULL; i++) {
if (!TEST_true(X509_VERIFY_PARAM_set1_host(vpm, multiname_dnsnames[i], 0)))
goto err;
if (!TEST_false(X509_VERIFY_PARAM_set1_email(vpm, multiname_dnsnames[i], 0)))
goto err;
}
for (size_t i = 0; multiname_emails[i] != NULL; i++) {
if (!TEST_true(X509_VERIFY_PARAM_set1_email(vpm, multiname_emails[i], 0)))
goto err;
if (!TEST_false(X509_VERIFY_PARAM_set1_host(vpm, multiname_emails[i], 0)))
goto err;
}
for (size_t i = 0; multiname_ips[i] != NULL; i++) {
size_t l = strlen(multiname_ips[i]);
if (!TEST_true(X509_VERIFY_PARAM_set1_ip_asc(vpm, multiname_ips[i])))
goto err;
if (l == 4 || l == 16) {
if (!TEST_true(X509_VERIFY_PARAM_set1_ip(vpm, (const uint8_t *)multiname_ips[i], l)))
goto err;
} else {
if (!TEST_false(X509_VERIFY_PARAM_set1_ip(vpm, (const uint8_t *)multiname_ips[i], l)))
goto err;
}
}
X509_VERIFY_PARAM_set1_host_input_validation(vpm, yolo_name_validation);
X509_VERIFY_PARAM_set1_rfc822_input_validation(vpm, yolo_name_validation);
X509_VERIFY_PARAM_set1_smtputf8_input_validation(vpm, yolo_name_validation);
X509_VERIFY_PARAM_set1_ip_input_validation(vpm, yolo_ip_validation);
for (size_t i = 0; multiname_dnsnames[i] != NULL; i++) {
/* should still work */
if (!TEST_true(X509_VERIFY_PARAM_set1_host(vpm, multiname_dnsnames[i], 0)))
goto err;
/* should be accepted now */
if (!TEST_true(X509_VERIFY_PARAM_set1_email(vpm, multiname_dnsnames[i], 0)))
goto err;
}
for (size_t i = 0; multiname_emails[i] != NULL; i++) {
/* should still work */
if (!TEST_true(X509_VERIFY_PARAM_set1_email(vpm, multiname_emails[i], 0)))
goto err;
/* should be accepted now */
if (!TEST_true(X509_VERIFY_PARAM_set1_host(vpm, multiname_emails[i], 0)))
goto err;
}
for (size_t i = 0; multiname_ips[i] != NULL; i++) {
if (!TEST_true(X509_VERIFY_PARAM_set1_ip_asc(vpm, multiname_ips[i])))
goto err;
/* should be accepted now */
if (!TEST_true(X509_VERIFY_PARAM_set1_ip(vpm, (const uint8_t *)multiname_ips[i], strlen(multiname_ips[i]))))
goto err;
}
ret = 1;
err:
X509_VERIFY_PARAM_free(vpm);
return ret;
}
static int test_self_signed_good(void)
{
return test_self_signed(root_f, 1, 1);
@@ -321,6 +746,8 @@ int setup_tests(void)
ADD_TEST(test_purpose_ssl_client);
ADD_TEST(test_purpose_ssl_server);
ADD_TEST(test_purpose_any);
ADD_TEST(test_multiname_selfsigned);
ADD_TEST(test_vpm_input_validation);
return 1;
err:
cleanup_tests();
+10
View File
@@ -5149,15 +5149,25 @@ X509_VERIFY_PARAM_get_inh_flags ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_get0_host ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_set1_host ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_add1_host ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_set1_host_input_validation ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_set_hostflags ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_get_hostflags ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_get0_peername ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_move_peername ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_get0_email ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_set1_email ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_set1_rfc822 ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_add1_rfc822 ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_set1_rfc822_input_validation ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_set1_smtputf8 ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_add1_smtputf8 ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_set1_smtputf8_input_validation ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_get1_ip_asc ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_set1_ip ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_set1_ip_asc ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_add1_ip ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_add1_ip_asc ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_set1_ip_input_validation ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_get_depth ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_get_auth_level ? 4_0_0 EXIST::FUNCTION:
X509_VERIFY_PARAM_get0_name ? 4_0_0 EXIST::FUNCTION:
+6 -2
View File
@@ -266,8 +266,12 @@ SSL_CTX_set_purpose ? 4_0_0 EXIST::FUNCTION:
SSL_set_purpose ? 4_0_0 EXIST::FUNCTION:
SSL_CTX_set_trust ? 4_0_0 EXIST::FUNCTION:
SSL_set_trust ? 4_0_0 EXIST::FUNCTION:
SSL_set1_host ? 4_0_0 EXIST::FUNCTION:
SSL_add1_host ? 4_0_0 EXIST::FUNCTION:
SSL_set1_host ? 4_0_0 EXIST::FUNCTION:DEPRECATEDIN_4_0
SSL_add1_host ? 4_0_0 EXIST::FUNCTION:DEPRECATEDIN_4_0
SSL_set1_dnsname ? 4_0_0 EXIST::FUNCTION:
SSL_add1_dnsname ? 4_0_0 EXIST::FUNCTION:
SSL_set1_ipaddr ? 4_0_0 EXIST::FUNCTION:
SSL_add1_ipaddr ? 4_0_0 EXIST::FUNCTION:
SSL_get0_peername ? 4_0_0 EXIST::FUNCTION:
SSL_set_hostflags ? 4_0_0 EXIST::FUNCTION:
SSL_CTX_dane_enable ? 4_0_0 EXIST::FUNCTION: