mirror of
https://github.com/openssl/openssl.git
synced 2026-05-07 20:12:39 +00:00
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:
+29
-6
@@ -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)
|
||||
|
||||
@@ -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
@@ -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
@@ -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(¶m->hosts);
|
||||
clear_buffer_stack(¶m->ips);
|
||||
clear_buffer_stack(¶m->rfc822s);
|
||||
clear_buffer_stack(¶m->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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->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(¶m->email, ¶m->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 **)¶m->ip, ¶m->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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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 */
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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:
|
||||
|
||||
Reference in New Issue
Block a user