Allow an ALPN callback to pretend to not exist
authorBenjamin Kaduk <bkaduk@akamai.com>
Tue, 7 Feb 2017 22:23:16 +0000 (16:23 -0600)
committerRich Salz <rsalz@openssl.org>
Mon, 10 Apr 2017 15:57:37 +0000 (11:57 -0400)
RFC 7301 mandates that the server SHALL respond with a fatal
"no_application_protocol" alert when there is no overlap between
the client's supplied list and the server's list of supported protocols.
In commit 062178678f5374b09f00d70796f6e692e8775aca we changed from
ignoring non-success returns from the supplied alpn_select_cb() to
treating such non-success returns as indicative of non-overlap and
sending the fatal alert.

In effect, this is using the presence of an alpn_select_cb() as a proxy
to attempt to determine whether the application has configured a list
of supported protocols.  However, there may be cases in which an
application's architecture leads it to supply an alpn_select_cb() but
have that callback be configured to take no action on connections that
do not have ALPN configured; returning SSL_TLSEXT_ERR_NOACK from
the callback would be the natural way to do so.  Unfortunately, the
aforementioned behavior change also treated SSL_TLSEXT_ERR_NOACK as
indicative of no overlap and terminated the connection; this change
supplies special handling for SSL_TLSEXT_ERR_NOACK returns from the
callback.  In effect, it provides a way for a callback to obtain the
behavior that would have occurred if no callback was registered at
all, which was not possible prior to this change.

Reviewed-by: Matt Caswell <matt@openssl.org>
Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2570)

doc/man3/SSL_CTX_set_alpn_select_cb.pod
ssl/statem/extensions.c
test/handshake_helper.c

index 5ff5a93b523e6a05844cf166350f3680640b6547..5ad063eb7f3881b74c323c9df524d09c69d6c170 100644 (file)
@@ -113,9 +113,15 @@ The ALPN select callback B<cb>, must return one of the following:
 
 ALPN protocol selected.
 
 
 ALPN protocol selected.
 
+=item SSL_TLSEXT_ERR_ALERT_FATAL
+
+There was no overlap between the client's supplied list and the server
+configuration.
+
 =item SSL_TLSEXT_ERR_NOACK
 
 =item SSL_TLSEXT_ERR_NOACK
 
-ALPN protocol not selected.
+ALPN protocol not selected, e.g., because no ALPN protocols are configured for
+this connection.
 
 =back
 
 
 =back
 
index cd1d0bd3ecc069bc4344b88ea7c6c585d3db2ad8..7ec71281720938f29b5cbce6ab66a1f572f26499 100644 (file)
@@ -919,6 +919,9 @@ static int final_alpn(SSL *s, unsigned int context, int sent, int *al)
             /* ALPN takes precedence over NPN. */
             s->s3->npn_seen = 0;
 #endif
             /* ALPN takes precedence over NPN. */
             s->s3->npn_seen = 0;
 #endif
+        } else if (r == SSL_TLSEXT_ERR_NOACK) {
+            /* Behave as if no callback was present. */
+            return 1;
         } else {
             *al = SSL_AD_NO_APPLICATION_PROTOCOL;
             return 0;
         } else {
             *al = SSL_AD_NO_APPLICATION_PROTOCOL;
             return 0;
index 47af3fe396ccd282d4e249b9531ed2cd0f917a8c..94fa5c578fe34aea6f308ff21a23a3d0c9d21825 100644 (file)
@@ -413,7 +413,7 @@ static int server_alpn_cb(SSL *s, const unsigned char **out,
     *out = tmp_out;
     /* Unlike NPN, we don't tolerate a mismatch. */
     return ret == OPENSSL_NPN_NEGOTIATED ? SSL_TLSEXT_ERR_OK
     *out = tmp_out;
     /* Unlike NPN, we don't tolerate a mismatch. */
     return ret == OPENSSL_NPN_NEGOTIATED ? SSL_TLSEXT_ERR_OK
-        : SSL_TLSEXT_ERR_NOACK;
+        : SSL_TLSEXT_ERR_ALERT_FATAL;
 }
 
 #ifndef OPENSSL_NO_SRP
 }
 
 #ifndef OPENSSL_NO_SRP