]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Let's support multiple names for certificate verification
authorBob Beck <beck@openssl.org>
Sat, 20 Dec 2025 19:21:40 +0000 (12:21 -0700)
committerNeil Horman <nhorman@openssl.org>
Tue, 24 Feb 2026 14:03:39 +0000 (09:03 -0500)
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)

22 files changed:
crypto/x509/v3_utl.c
crypto/x509/x509_local.h
crypto/x509/x509_vfy.c
crypto/x509/x509_vpm.c
demos/bio/sconnect.c
demos/guide/quic-client-block.c
demos/guide/quic-client-non-block.c
demos/guide/quic-multi-stream.c
demos/guide/tls-client-block.c
demos/guide/tls-client-non-block.c
demos/http3/ossl-nghttp3.c
demos/sslecho/main.c
doc/man3/SSL_CTX_dane_enable.pod
doc/man3/SSL_set1_host.pod
doc/man3/X509_VERIFY_PARAM_set_flags.pod
include/openssl/ssl.h.in
include/openssl/x509_vfy.h.in
ssl/ssl_lib.c
test/quic-openssl-docker/hq-interop/quic-hq-interop.c
test/verify_extra_test.c
util/libcrypto.num
util/libssl.num

index ecb9e872d2f72959f8b09d6a27e86f63bcc6ecdc..09b445a64ce13a0cd1a7176a13978464e9b45b75 100644 (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)
index 58f2d9f79b793573d6dcac7be801fd190f01aae7..a2c3a6ca8616bdec160b9378ee815b72f61e0a0d 100644 (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"
 #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);
index 1fbc766891be2dcfbafb1fa84e68cc7679d0520b..c2467aaea6a737e6767c90b85bf3f466a5d9df91 100644 (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;
     }
index dc214409af2743cfa0da48fdc26882918c40f5e1..2f820a1be18e2d0be27eb2ea45efab8d625b0863 100644 (file)
 #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)
+    if (name[len - 1] == '\0')
+        len--;
+
+    /* Refuse the empty string */
+    if (len == 0)
         return 0;
-    if (namelen > 0 && name[namelen - 1] == '\0')
-        --namelen;
 
-    if (mode == SET_HOST) {
-        sk_OPENSSL_STRING_pop_free(vpm->hosts, str_free);
-        vpm->hosts = NULL;
-    }
-    if (name == NULL || namelen == 0)
+    /* Refuse values with embedded \0 bytes other than at the end */
+    if (memchr(name, '\0', len) != 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;
+}
 
-    copy = OPENSSL_strndup(name, namelen);
-    if (copy == NULL)
+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 (vpm->hosts == NULL && (vpm->hosts = sk_OPENSSL_STRING_new_null()) == NULL) {
-        OPENSSL_free(copy);
+    if (len < 2 || len > 256)
         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;
+    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 (!replace_buffer_stack(&dest->hosts, &src->hosts))
+            return 0;
+    }
+    x509_verify_param_copy(validate_host, NULL);
+
+    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(email, NULL)) {
-        if (!X509_VERIFY_PARAM_set1_email(dest, src->email, src->emaillen))
+    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(ip, NULL)) {
-        if (!X509_VERIFY_PARAM_set1_ip(dest, src->ip, src->iplen))
+    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)
+{
+    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))
 {
-    return int_x509_param_set_hosts(param, ADD_HOST, name, namelen);
+    param->validate_rfc822 = validate_rfc822;
 }
 
 void X509_VERIFY_PARAM_set_hostflags(X509_VERIFY_PARAM *param,
@@ -438,56 +846,57 @@ 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)
+int X509_VERIFY_PARAM_set1_ip_asc(X509_VERIFY_PARAM *param, const char *ipasc)
 {
-    if (iplen != 0 && iplen != 4 && iplen != 16) {
-        ERR_raise(ERR_LIB_X509, ERR_R_PASSED_INVALID_ARGUMENT);
+    unsigned char ipout[16];
+    size_t iplen;
+
+    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 int_x509_param_set1((char **)&param->ip, &param->iplen,
-        (char *)ip, iplen);
+    return X509_VERIFY_PARAM_set1_ip(param, ipout, 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)
 {
     unsigned char ipout[16];
-    size_t iplen = (size_t)ossl_a2i_ipadd(ipout, ipasc);
+    size_t iplen;
 
-    if (iplen == 0)
+    if ((iplen = (size_t)ossl_a2i_ipadd(ipout, ipasc)) == 0)
         return 0;
-    return X509_VERIFY_PARAM_set1_ip(param, ipout, iplen);
+    return X509_VERIFY_PARAM_add1_ip(param, ipout, iplen);
 }
 
 int X509_VERIFY_PARAM_get_depth(const X509_VERIFY_PARAM *param)
@@ -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;
index e069209e7261a58ec81aba60d5edc0cdc84a5db7..a3b3eabfc86aec31b2fd172d5b4734b553497dfc 100644 (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;
     }
index 80eccbab847220dcd51ebf0528e487431a7b6cea..a2208f5e11d84bd6f9df0c9fa8cc894eb1ab98dc 100644 (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;
     }
index 9e8760dde24fc261d54ce3d58be8e9c4e7f471ba..a38fdf411e0d046b62f247128e0bffd99e01ca4a 100644 (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;
     }
index d08ab4dac19cb7441f93e3a2c49113d1513edf16..7e6777d6a43ea6844790457822eaf424eefb0a36 100644 (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;
     }
index 4536b1ffa0919fd62d53003c89b1d787ac0716d3..8b51d6d84214fcfe7d1dc0591e75b3381532f342 100644 (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;
     }
index 3103e6725b8e1c42d4edc79e2cdc6202d57dfb39..31920acffc25efbdee07a0e23910e012496d4ec3 100644 (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;
     }
index 5be7b1a52cd1e0fd84f9c2a10d387dabf0c61d07..942a99acc9b57d81f1e2f896e8f1e14165295718 100644 (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 */
index 4d4fc969739295a471572981f1708acb13961528..a26ebc0ce73451a7451d300eae6ae2a83754c172 100644 (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;
         }
index d558e63895fda6c908f6ff7f18d3fc00cda16462..7a37540c87549b7e2cb8c21db84567947e9b9218 100644 (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)>,
index b65116a53f5f047952a397df7fa5573a29c7c6c6..6a3ada24eca07daeae1f44f7036fe1b508f8c2f0 100644 (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.
-
-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.
+* Any address in the IP address list, if not empty, matches any IP
+  address SAN in the certificate.
+
+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.
index f6634bb81e0bdb63e7f03491b87d6293ca5cceb8..67d6438b6759b85e7a5bd3ba1c575f6ed523d858 100644 (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
index b5a75720e794d0a7f6f51ba1d166500c324f3a08..ca2701a0ad42717c001b95f3cb921d58d86c647f 100644 (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);
 
index 0b3bd801d7cd60e575dc6d26526a01a81a7315c1..fda59129df1ea371f820c9128467baf3696f52f9 100644 (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);
index fc352ba68ff80899f4f368bd0f47d9d98bb2ae61..76615f4809792d0099940778872817307bff1839 100644 (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)
 {
index d1448854c604371eb0d7b27268f9597b57deff4e..d890bfee4fcfec0fc72ff888a2beee8cf1d2d8a0 100644 (file)
@@ -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;
     }
index ad2649034fa9868119f23bd0a17dde3ae630255d..1420c710348d2637a6eedac74a988664085350f8 100644 (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();
index 954486f390a9ea97bb4ff4fbc4814e7bdbf280a8..5e1c4b430dc46dbc479d9d71fc3fc328bf585f90 100644 (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:
index eb376dc72c96a411c57a081aa593101952065963..dca18a55c625f9e8d1b89ea8422d6c0aa5a0bf17 100644 (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: