aboutsummaryrefslogtreecommitdiff
path: root/ssl/statem/statem_srvr.c
diff options
context:
space:
mode:
authorBenjamin Kaduk <bkaduk@akamai.com>2017-08-01 14:50:22 -0500
committerBenjamin Kaduk <kaduk@mit.edu>2017-08-15 10:52:21 -0500
commit5626f634c31cfde48ccbbee243be29e0eb77171e (patch)
treeb0828a3ee9c94307d96504856836cb962b6a18a0 /ssl/statem/statem_srvr.c
parent12997aa984cf0e5def1045fd22d7b0675caaa0a1 (diff)
downloadopenssl-5626f634c31cfde48ccbbee243be29e0eb77171e.zip
openssl-5626f634c31cfde48ccbbee243be29e0eb77171e.tar.gz
openssl-5626f634c31cfde48ccbbee243be29e0eb77171e.tar.bz2
Move ALPN handling from finalizer to delayed call
Commit 02f0274e8c0596dcf7e2d104250232a42c650b96 moved ALPN processing into an extension finalization function, as the only documented ordering requirement from previous commits was that ALPN processing occur after SNI processing, and SNI processing is performed before the extension finalization step. However, it is useful for applications' alpn_select callbacks to run after ciphersuite selection as well -- at least one application protocol specification (HTTP/2) imposes restrictions on which ciphersuites are usable with that protocol. Since it is generally more preferrable to have a successful TLS connection with a default application protocol than to fail the TLS connection and not be able to have the preferred application protocol, it is good to give the alpn_select callback information about the ciphersuite to be used, so that appropriate restrctions can be enforced in application code. Accordingly, split the ALPN handling out into a separate tls_handl_alpn() function akin to tls_handle_status_request(), called from tls_post_process_client_hello(). This is an alternative to resuscitating ssl_check_clienthello_tlsext_late(), something of an awkwward name itself. Reviewed-by: Matt Caswell <matt@openssl.org> (Merged from https://github.com/openssl/openssl/pull/4070)
Diffstat (limited to 'ssl/statem/statem_srvr.c')
-rw-r--r--ssl/statem/statem_srvr.c48
1 files changed, 48 insertions, 0 deletions
diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c
index fad339a..8c5f77b 100644
--- a/ssl/statem/statem_srvr.c
+++ b/ssl/statem/statem_srvr.c
@@ -1934,6 +1934,45 @@ static int tls_handle_status_request(SSL *s, int *al)
return 1;
}
+/*
+ * Call the alpn_select callback if needed. Upon success, returns 1.
+ * Upon failure, returns 0 and sets |*al| to the appropriate fatal alert.
+ */
+static int tls_handle_alpn(SSL *s, int *al)
+{
+ const unsigned char *selected = NULL;
+ unsigned char selected_len = 0;
+
+ if (s->ctx->ext.alpn_select_cb != NULL && s->s3->alpn_proposed != NULL) {
+ int r = s->ctx->ext.alpn_select_cb(s, &selected, &selected_len,
+ s->s3->alpn_proposed,
+ (unsigned int)s->s3->alpn_proposed_len,
+ s->ctx->ext.alpn_select_cb_arg);
+
+ if (r == SSL_TLSEXT_ERR_OK) {
+ OPENSSL_free(s->s3->alpn_selected);
+ s->s3->alpn_selected = OPENSSL_memdup(selected, selected_len);
+ if (s->s3->alpn_selected == NULL) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ return 0;
+ }
+ s->s3->alpn_selected_len = selected_len;
+#ifndef OPENSSL_NO_NEXTPROTONEG
+ /* 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;
+ }
+ }
+
+ return 1;
+}
+
WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
{
int al = SSL_AD_HANDSHAKE_FAILURE;
@@ -2018,6 +2057,15 @@ WORK_STATE tls_post_process_client_hello(SSL *s, WORK_STATE wst)
SSL_R_CLIENTHELLO_TLSEXT);
goto f_err;
}
+ /*
+ * Call alpn_select callback if needed. Has to be done after SNI and
+ * cipher negotiation (HTTP/2 restricts permitted ciphers).
+ */
+ if (!tls_handle_alpn(s, &al)) {
+ SSLerr(SSL_F_TLS_POST_PROCESS_CLIENT_HELLO,
+ SSL_R_CLIENTHELLO_TLSEXT);
+ goto f_err;
+ }
wst = WORK_MORE_C;
}