]> git.ipfire.org Git - thirdparty/openssl.git/commitdiff
Fix SSL_{set1,add1}_host() handling of host name/IP address and related documentation
authorDr. David von Oheimb <dev@ddvo.net>
Mon, 21 Apr 2025 13:11:01 +0000 (15:11 +0200)
committerTomas Mraz <tomas@openssl.org>
Tue, 6 May 2025 13:11:49 +0000 (15:11 +0200)
Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/27457)

(cherry picked from commit 1eee02d3e710e01d864c37708f64e83511627e28)

doc/man3/SSL_set1_host.pod
include/openssl/ssl.h.in
ssl/ssl_lib.c

index fd16a943198644ca906d3edca89a54bf629ea46f..65689224fb9a8a01a5568b80427c400a4c56dafa 100644 (file)
@@ -9,8 +9,8 @@ SSL server verification parameters
 
  #include <openssl/ssl.h>
 
- int SSL_set1_host(SSL *s, const char *hostname);
- int SSL_add1_host(SSL *s, const char *hostname);
+ int SSL_set1_host(SSL *s, const char *host);
+ int SSL_add1_host(SSL *s, const char *host);
  void SSL_set_hostflags(SSL *s, unsigned int flags);
  const char *SSL_get0_peername(SSL *s);
 
@@ -18,34 +18,36 @@ SSL server verification parameters
 
 These functions configure server hostname checks in the SSL client.
 
-SSL_set1_host() sets the expected DNS hostname to B<name> clearing
-any previously specified hostname.  If B<name> is NULL
-or the empty string, the list of hostnames is cleared and name
-checks are not performed on the peer certificate.  When a nonempty
-B<name> is specified, certificate verification automatically checks
-the peer hostname via L<X509_check_host(3)> with B<flags> as specified
+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 B<name> as an additional reference identifier
-that can match the peer's certificate.  Any previous names set via
-SSL_set1_host() or SSL_add1_host() are retained, no change is made
-if B<name> is NULL or empty.  When multiple names are configured,
-the peer is considered verified when any name matches.  This function
-is required for DANE TLSA in the presence of service name indirection
-via CNAME, MX or SRV records as specified in RFC7671, RFC7672 or
-RFC7673.
+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.
 
-SSL_set_hostflags() sets the B<flags> that will be passed to
+SSL_set_hostflags() sets the I<flags> that will be passed to
 L<X509_check_host(3)> when name checks are applicable, by default
-the B<flags> value is 0.  See L<X509_check_host(3)> for the list
+the I<flags> value is 0.  See L<X509_check_host(3)> for the list
 of available flags and their meaning.
 
 SSL_get0_peername() returns the DNS hostname or subject CommonName
@@ -56,13 +58,13 @@ of the reference identifiers configured via SSL_set1_host() or
 SSL_add1_host() starts with ".", which indicates a parent domain prefix
 rather than a fixed name, the matched peer name may be a sub-domain
 of the reference identifier.  The returned string is allocated by
-the library and is no longer valid once the associated B<ssl> handle
+the library and is no longer valid once the associated I<ssl> handle
 is cleared or freed, or a renegotiation takes place.  Applications
 must not free the return value.
 
 SSL clients are advised to use these functions in preference to
 explicitly calling L<X509_check_host(3)>.  Hostname checks may be out
-of scope with the RFC7671 DANE-EE(3) certificate usage, and the
+of scope with the RFC 7671 DANE-EE(3) certificate usage, and the
 internal check will be suppressed as appropriate when DANE is
 enabled.
 
@@ -71,8 +73,10 @@ enabled.
 SSL_set1_host() and SSL_add1_host() return 1 for success and 0 for
 failure.
 
+SSL_set_hostflags() returns nothing at all.
+
 SSL_get0_peername() returns NULL if peername verification is not
-applicable (as with RFC7671 DANE-EE(3)), or no trusted peername was
+applicable (as with RFC 7671 DANE-EE(3)), or no trusted peername was
 matched.  Otherwise, it returns the matched peername.  To determine
 whether verification succeeded call L<SSL_get_verify_result(3)>.
 
@@ -105,8 +109,7 @@ the lifetime of the SSL connection.
 
 L<ssl(7)>,
 L<X509_check_host(3)>, L<SSL_set_tlsext_host_name(3)>,
-L<SSL_get_verify_result(3)>.
-L<SSL_dane_enable(3)>.
+L<SSL_get_verify_result(3)>, L<SSL_dane_enable(3)>
 
 =head1 HISTORY
 
index b3420799683b5ae8264a48ea65a9606695b97f1a..383c5bc411f1b990c815afd55e5d97c15e936f70 100644 (file)
@@ -1831,8 +1831,8 @@ __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 *hostname);
-__owur int SSL_add1_host(SSL *s, const char *hostname);
+__owur int SSL_set1_host(SSL *s, const char *host);
+__owur int SSL_add1_host(SSL *s, const char *host);
 __owur const char *SSL_get0_peername(SSL *s);
 void SSL_set_hostflags(SSL *s, unsigned int flags);
 
index efc6d66fb9c54a6e738f7a8d4f1575d7af8d3dbe..ab6a1233fb8253ae8854b06477fbc558cce0baed 100644 (file)
@@ -1135,52 +1135,55 @@ int SSL_set_trust(SSL *s, int trust)
     return X509_VERIFY_PARAM_set_trust(sc->param, trust);
 }
 
-int SSL_set1_host(SSL *s, const char *hostname)
+int SSL_set1_host(SSL *s, const char *host)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
     if (sc == NULL)
         return 0;
 
-    /* If a hostname is provided and parses as an IP address,
-     * treat it as such. */
-    if (hostname != NULL
-        && X509_VERIFY_PARAM_set1_ip_asc(sc->param, hostname) == 1)
+    /* clear hostname(s) and IP address in any case, also if host parses as an IP address */
+    (void)X509_VERIFY_PARAM_set1_host(sc->param, NULL, 0);
+    (void)X509_VERIFY_PARAM_set1_ip(sc->param, NULL, 0);
+    if (host == NULL)
         return 1;
 
-    return X509_VERIFY_PARAM_set1_host(sc->param, hostname, 0);
+    /* If a host is provided and parses as an IP address, treat it as such. */
+    return X509_VERIFY_PARAM_set1_ip_asc(sc->param, host)
+        || X509_VERIFY_PARAM_set1_host(sc->param, host, 0);
 }
 
-int SSL_add1_host(SSL *s, const char *hostname)
+int SSL_add1_host(SSL *s, const char *host)
 {
     SSL_CONNECTION *sc = SSL_CONNECTION_FROM_SSL(s);
 
     if (sc == NULL)
         return 0;
 
-    /* If a hostname is provided and parses as an IP address,
-     * treat it as such. */
-    if (hostname) {
+    /* If a host is provided and parses as an IP address, treat it as such. */
+    if (host != NULL) {
         ASN1_OCTET_STRING *ip;
         char *old_ip;
 
-        ip = a2i_IPADDRESS(hostname);
-        if (ip) {
+        ip = a2i_IPADDRESS(host);
+        if (ip != NULL) {
             /* We didn't want it; only to check if it *is* an IP address */
             ASN1_OCTET_STRING_free(ip);
 
             old_ip = X509_VERIFY_PARAM_get1_ip_asc(sc->param);
-            if (old_ip) {
+            if (old_ip != NULL) {
                 OPENSSL_free(old_ip);
                 /* There can be only one IP address */
+                ERR_raise_data(ERR_LIB_SSL, ERR_R_PASSED_INVALID_ARGUMENT,
+                               "IP address was already set");
                 return 0;
             }
 
-            return X509_VERIFY_PARAM_set1_ip_asc(sc->param, hostname);
+            return X509_VERIFY_PARAM_set1_ip_asc(sc->param, host);
         }
     }
 
-    return X509_VERIFY_PARAM_add1_host(sc->param, hostname, 0);
+    return X509_VERIFY_PARAM_add1_host(sc->param, host, 0);
 }
 
 void SSL_set_hostflags(SSL *s, unsigned int flags)