Skip early_data if appropriate after a HelloRetryRequest
authorMatt Caswell <matt@openssl.org>
Fri, 24 Feb 2017 11:40:49 +0000 (11:40 +0000)
committerMatt Caswell <matt@openssl.org>
Thu, 2 Mar 2017 17:44:15 +0000 (17:44 +0000)
Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)

ssl/record/rec_layer_s3.c
ssl/record/record_locl.h
ssl/record/ssl3_record.c
ssl/statem/statem.c

index 6fa272c77a465ceaab2e557c7bde63a78f0565f6..1dc2956478b2874d736f6290f4768b9698803d8b 100644 (file)
@@ -1565,6 +1565,21 @@ int ssl3_read_bytes(SSL *s, int type, int *recvd_type, unsigned char *buf,
         if (ossl_statem_app_data_allowed(s)) {
             s->s3->in_read_app_data = 2;
             return -1;
+        } else if (ossl_statem_skip_early_data(s)) {
+            /*
+             * This can happen after a client sends a CH followed by early_data,
+             * but the server responds with a HelloRetryRequest. The server
+             * reads the next record from the client expecting to find a
+             * plaintext ClientHello but gets a record which appears to be
+             * application data. The trial decrypt "works" because null
+             * decryption was applied. We just skip it and move on to the next
+             * record.
+             */
+            if (!early_data_count_ok(s, rr->length,
+                                     EARLY_DATA_CIPHERTEXT_OVERHEAD, &al))
+                goto f_err;
+            SSL3_RECORD_set_read(rr);
+            goto start;
         } else {
             al = SSL_AD_UNEXPECTED_MESSAGE;
             SSLerr(SSL_F_SSL3_READ_BYTES, SSL_R_UNEXPECTED_RECORD);
index 639483540456f825f7319353cfb795169ae78797..e249918ef46cc0031871a47336dff0a1ac4b3f9a 100644 (file)
@@ -115,3 +115,4 @@ __owur int tls1_cbc_remove_padding(const SSL *s,
                                    size_t block_size, size_t mac_size);
 int dtls1_process_record(SSL *s, DTLS1_BITMAP *bitmap);
 __owur int dtls1_get_record(SSL *s);
+int early_data_count_ok(SSL *s, size_t length, size_t overhead, int *al);
index aebead23952ce0d6a7f2c7e6d5349d5d9de75da7..50582d1a73cbfe311ae98fa7c6f2465fb473d1c1 100644 (file)
@@ -101,16 +101,16 @@ static int ssl3_record_app_data_waiting(SSL *s)
     return 1;
 }
 
-static int early_data_count_ok(SSL *s, size_t length, size_t overhead, int *al)
+int early_data_count_ok(SSL *s, size_t length, size_t overhead, int *al)
 {
     uint32_t max_early_data = s->max_early_data;
 
     /*
      * We go with the lowest out of the max early data set in the session
-     * and the configured max_early_data
+     * and the configured max_early_data.
      */
-    if (s->session->ext.max_early_data < s->max_early_data)
-        max_early_data = s->max_early_data;
+    if (s->hit && s->session->ext.max_early_data < s->max_early_data)
+        max_early_data = s->session->ext.max_early_data;
 
     if (max_early_data == 0) {
         *al = SSL_AD_UNEXPECTED_MESSAGE;
index 9c74a2932e5d32c4f4371aa250d3900ac977d15a..2c202f4deb84ad2c4ed468f5491207e092929653 100644 (file)
@@ -157,8 +157,13 @@ int ossl_statem_skip_early_data(SSL *s)
     if (s->ext.early_data != SSL_EARLY_DATA_REJECTED)
         return 0;
 
-    if (s->statem.hand_state != TLS_ST_SW_FINISHED)
-        return 0;
+    if (s->hello_retry_request) {
+        if (s->statem.hand_state != TLS_ST_SW_HELLO_RETRY_REQUEST)
+            return 0;
+    } else {
+        if (s->statem.hand_state != TLS_ST_SW_FINISHED)
+            return 0;
+    }
 
     return 1;
 }