Provide a key_share extension finaliser
authorMatt Caswell <matt@openssl.org>
Wed, 18 Jan 2017 11:31:37 +0000 (11:31 +0000)
committerMatt Caswell <matt@openssl.org>
Mon, 30 Jan 2017 10:18:20 +0000 (10:18 +0000)
This mops up various edge cases with key_shares and makes sure we still
generate the handshake secret if we haven't been provided with one but we
have a PSK.

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

include/openssl/ssl.h
ssl/ssl_err.c
ssl/statem/extensions.c
ssl/statem/extensions_srvr.c
ssl/statem/statem_srvr.c

index 52be4064fa2b99cc1e2aca33dce4c9103fced158..cee7549d9bea097fddeeceac407ae7471695322c 100644 (file)
@@ -2097,6 +2097,7 @@ int ERR_load_SSL_strings(void);
 # define SSL_F_DTLS_PROCESS_HELLO_VERIFY                  386
 # define SSL_F_FINAL_EC_PT_FORMATS                        485
 # define SSL_F_FINAL_EMS                                  486
+# define SSL_F_FINAL_KEY_SHARE                            503
 # define SSL_F_FINAL_RENEGOTIATE                          483
 # define SSL_F_FINAL_SIG_ALGS                             497
 # define SSL_F_NSS_KEYLOG_INT                             500
index 9b02c58737782229f372ebe11685a37930cb5243..9edee93727f2e7347d0c1939e829bf0a4840f7fb 100644 (file)
@@ -51,6 +51,7 @@ static ERR_STRING_DATA SSL_str_functs[] = {
     {ERR_FUNC(SSL_F_DTLS_PROCESS_HELLO_VERIFY), "dtls_process_hello_verify"},
     {ERR_FUNC(SSL_F_FINAL_EC_PT_FORMATS), "final_ec_pt_formats"},
     {ERR_FUNC(SSL_F_FINAL_EMS), "final_ems"},
+    {ERR_FUNC(SSL_F_FINAL_KEY_SHARE), "final_key_share"},
     {ERR_FUNC(SSL_F_FINAL_RENEGOTIATE), "final_renegotiate"},
     {ERR_FUNC(SSL_F_FINAL_SIG_ALGS), "final_sig_algs"},
     {ERR_FUNC(SSL_F_NSS_KEYLOG_INT), "nss_keylog_int"},
index 4c66b3362fcc49b8bda653377eb77204f12d29f8..f1a1675d66eff7f7e6056e96f1e46c641f8bb445 100644 (file)
@@ -36,6 +36,7 @@ static int init_etm(SSL *s, unsigned int context);
 static int init_ems(SSL *s, unsigned int context);
 static int final_ems(SSL *s, unsigned int context, int sent, int *al);
 static int init_psk_kex_modes(SSL *s, unsigned int context);
+static int final_key_share(SSL *s, unsigned int context, int sent, int *al);
 #ifndef OPENSSL_NO_SRTP
 static int init_srtp(SSL *s, unsigned int context);
 #endif
@@ -252,7 +253,8 @@ static const EXTENSION_DEFINITION ext_defs[] = {
         | EXT_TLS1_3_HELLO_RETRY_REQUEST | EXT_TLS_IMPLEMENTATION_ONLY
         | EXT_TLS1_3_ONLY,
         NULL, tls_parse_ctos_key_share, tls_parse_stoc_key_share,
-        tls_construct_stoc_key_share, tls_construct_ctos_key_share, NULL
+        tls_construct_stoc_key_share, tls_construct_ctos_key_share,
+        final_key_share
     },
     {
         /*
@@ -955,6 +957,45 @@ static int final_sig_algs(SSL *s, unsigned int context, int sent, int *al)
     return 1;
 }
 
+
+static int final_key_share(SSL *s, unsigned int context, int sent, int *al)
+{
+    if (!SSL_IS_TLS13(s))
+        return 1;
+
+    /*
+     * If
+     *     we have no key_share
+     *     AND
+     *     (we are not resuming
+     *      OR the kex_mode doesn't allow non key_share resumes)
+     * THEN
+     *     fail
+     */
+    if (((s->server && s->s3->peer_tmp == NULL) || (!s->server && !sent))
+            && (!s->hit
+                || (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE) == 0)) {
+        /* No suitable share */
+        /* TODO(TLS1.3): Send a HelloRetryRequest */
+        *al = SSL_AD_HANDSHAKE_FAILURE;
+        SSLerr(SSL_F_FINAL_KEY_SHARE, SSL_R_NO_SUITABLE_KEY_SHARE);
+        return 0;
+    }
+
+    /*
+     * For a client side resumption with no key_share we need to generate
+     * the handshake secret (otherwise this is done during key_share
+     * processing).
+     */
+    if (!sent && !s->server && !tls13_generate_handshake_secret(s, NULL, 0)) {
+        *al = SSL_AD_INTERNAL_ERROR;
+        SSLerr(SSL_F_FINAL_KEY_SHARE, ERR_R_INTERNAL_ERROR);
+        return 0;
+    }
+
+    return 1;
+}
+
 static int init_psk_kex_modes(SSL *s, unsigned int context)
 {
     s->ext.psk_kex_mode = TLSEXT_KEX_MODE_FLAG_NONE;
index 8ee292818e9513214d6ab89764fdfb0cd2829f20..1e10a10c4716413ddaaeeb34f68aa9a23b1f7f30 100644 (file)
@@ -523,7 +523,7 @@ int tls_parse_ctos_key_share(SSL *s, PACKET *pkt, X509 *x, size_t chainidx,
     int group_nid, found = 0;
     unsigned int curve_flags;
 
-    if (s->hit)
+    if (s->hit && (s->ext.psk_kex_mode & TLSEXT_KEX_MODE_FLAG_KE_DHE) == 0)
         return 1;
 
     /* Sanity check */
index 98171b948c07e94fbd5efb1cc7f8ff708a19b08f..f9659e2d9d81dc6d7b3754890d9ed00866b7427c 100644 (file)
@@ -1557,15 +1557,6 @@ MSG_PROCESS_RETURN tls_process_client_hello(SSL *s, PACKET *pkt)
         goto f_err;
     }
 
-    /* Check we've got a key_share for TLSv1.3 */
-    if (SSL_IS_TLS13(s) && s->s3->peer_tmp == NULL && !s->hit) {
-        /* No suitable share */
-        /* TODO(TLS1.3): Send a HelloRetryRequest */
-        al = SSL_AD_HANDSHAKE_FAILURE;
-        SSLerr(SSL_F_TLS_PROCESS_CLIENT_HELLO, SSL_R_NO_SUITABLE_KEY_SHARE);
-        goto f_err;
-    }
-
     /*
      * Check if we want to use external pre-shared secret for this handshake
      * for not reused session only. We need to generate server_random before