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

Reply via email to