Hi, This is a patch to support no_application_protocol alert(120) in ALPN as defined in 3.2. Protocol Selection of RFC7301.
In case of either selected_len is zero or SSL_TLSEXT_ERR_ALERT_FATAL is returned after alpn_select_cb, the alert is sent. Please let me know if it has insufficiencies. I can't find how to include a test for this kind of fix, so I tested it by using s_client as below. $ ./apps/openssl s_client -tls1 -quiet -alpn bar -connect localhost:8443 140247136798368:error:14094460:SSL routines:ssl3_read_bytes:reason(1120):s3_pkt.c:1561:SSL alert number 120 140247136798368:error:1409E0E5:SSL routines:ssl3_write_bytes:ssl handshake failure:s3_pkt.c:665: Regards,
>From cbd44553160845a60133412c1ffb280f5efa8437 Mon Sep 17 00:00:00 2001 From: Shigeki Ohtsu <[email protected]> Date: Wed, 16 Jul 2014 17:22:07 +0900 Subject: [PATCH] Add support of no_application_protocol alert in ALPN protocol selection --- apps/s_server.c | 9 +++++---- ssl/s3_enc.c | 1 + ssl/ssl.h | 1 + ssl/t1_enc.c | 1 + ssl/t1_lib.c | 9 ++++++++- ssl/tls1.h | 2 ++ 6 files changed, 18 insertions(+), 5 deletions(-) diff --git a/apps/s_server.c b/apps/s_server.c index 9d1a1fa..b889e63 100644 --- a/apps/s_server.c +++ b/apps/s_server.c @@ -923,6 +923,7 @@ typedef struct tlsextalpnctx_st { static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg) { + int ret; tlsextalpnctx *alpn_ctx = arg; if (!s_quiet) @@ -940,11 +941,11 @@ static int alpn_cb(SSL *s, const unsigned char **out, unsigned char *outlen, con BIO_write(bio_s_out, "\n", 1); } - if (SSL_select_next_proto((unsigned char**) out, outlen, alpn_ctx->data, alpn_ctx->len, in, inlen) != - OPENSSL_NPN_NEGOTIATED) + ret = SSL_select_next_proto((unsigned char**) out, outlen, alpn_ctx->data, alpn_ctx->len, in, inlen); + if (ret != OPENSSL_NPN_NEGOTIATED) { - return SSL_TLSEXT_ERR_NOACK; - } + return ret == OPENSSL_NPN_NO_OVERLAP ? SSL_TLSEXT_ERR_ALERT_FATAL : SSL_TLSEXT_ERR_NOACK; + } if (!s_quiet) { diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c index 6c103a0..97178ac 100644 --- a/ssl/s3_enc.c +++ b/ssl/s3_enc.c @@ -937,6 +937,7 @@ int ssl3_alert_code(int code) case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: return(SSL3_AD_HANDSHAKE_FAILURE); case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(SSL3_AD_HANDSHAKE_FAILURE); case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY); + case SSL_AD_NO_APPLICATION_PROTOCOL:return(TLS1_AD_NO_APPLICATION_PROTOCOL); default: return(-1); } } diff --git a/ssl/ssl.h b/ssl/ssl.h index d44a9d5..0d003e8 100644 --- a/ssl/ssl.h +++ b/ssl/ssl.h @@ -1736,6 +1736,7 @@ DECLARE_PEM_rw(SSL_SESSION, SSL_SESSION) #define SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE #define SSL_AD_BAD_CERTIFICATE_HASH_VALUE TLS1_AD_BAD_CERTIFICATE_HASH_VALUE #define SSL_AD_UNKNOWN_PSK_IDENTITY TLS1_AD_UNKNOWN_PSK_IDENTITY /* fatal */ +#define SSL_AD_NO_APPLICATION_PROTOCOL TLS1_AD_NO_APPLICATION_PROTOCOL /* fatal */ #define SSL_ERROR_NONE 0 #define SSL_ERROR_SSL 1 diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c index 98cf468..60912fe 100644 --- a/ssl/t1_enc.c +++ b/ssl/t1_enc.c @@ -1278,6 +1278,7 @@ int tls1_alert_code(int code) case SSL_AD_BAD_CERTIFICATE_STATUS_RESPONSE: return(TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE); case SSL_AD_BAD_CERTIFICATE_HASH_VALUE: return(TLS1_AD_BAD_CERTIFICATE_HASH_VALUE); case SSL_AD_UNKNOWN_PSK_IDENTITY:return(TLS1_AD_UNKNOWN_PSK_IDENTITY); + case SSL_AD_NO_APPLICATION_PROTOCOL:return(TLS1_AD_NO_APPLICATION_PROTOCOL); #if 0 /* not appropriate for TLS, not used for DTLS */ case DTLS1_AD_MISSING_HANDSHAKE_MESSAGE: return (DTLS1_AD_MISSING_HANDSHAKE_MESSAGE); diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 4374d6a..c27dee2 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -1817,7 +1817,7 @@ static int tls1_alpn_handle_client_hello(SSL *s, const unsigned char *data, unsigned i; unsigned proto_len; const unsigned char *selected; - unsigned char selected_len; + unsigned char selected_len = 0; int r; if (s->ctx->alpn_select_cb == NULL) @@ -1855,6 +1855,10 @@ static int tls1_alpn_handle_client_hello(SSL *s, const unsigned char *data, r = s->ctx->alpn_select_cb(s, &selected, &selected_len, data, data_len, s->ctx->alpn_select_cb_arg); if (r == SSL_TLSEXT_ERR_OK) { + if (selected_len == 0) { + *al = SSL_AD_NO_APPLICATION_PROTOCOL; + return -1; + } if (s->s3->alpn_selected) OPENSSL_free(s->s3->alpn_selected); s->s3->alpn_selected = OPENSSL_malloc(selected_len); @@ -1865,6 +1869,9 @@ static int tls1_alpn_handle_client_hello(SSL *s, const unsigned char *data, } memcpy(s->s3->alpn_selected, selected, selected_len); s->s3->alpn_selected_len = selected_len; + } else if (r == SSL_TLSEXT_ERR_ALERT_FATAL) { + *al = SSL_AD_NO_APPLICATION_PROTOCOL; + return -1; } return 0; diff --git a/ssl/tls1.h b/ssl/tls1.h index 3499584..2c09685 100644 --- a/ssl/tls1.h +++ b/ssl/tls1.h @@ -201,6 +201,8 @@ extern "C" { #define TLS1_AD_BAD_CERTIFICATE_STATUS_RESPONSE 113 #define TLS1_AD_BAD_CERTIFICATE_HASH_VALUE 114 #define TLS1_AD_UNKNOWN_PSK_IDENTITY 115 /* fatal */ +/* ALPN Protocol Selection Alert from RFC7301 */ +#define TLS1_AD_NO_APPLICATION_PROTOCOL 120 /* fatal */ /* ExtensionType values from RFC3546 / RFC4366 / RFC6066 */ #define TLSEXT_TYPE_server_name 0 -- 1.9.1
