Skip early_data if appropriate after a HelloRetryRequest

Reviewed-by: Rich Salz <rsalz@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2737)
diff --git a/ssl/record/rec_layer_s3.c b/ssl/record/rec_layer_s3.c
index 6fa272c..1dc2956 100644
--- a/ssl/record/rec_layer_s3.c
+++ b/ssl/record/rec_layer_s3.c
@@ -1565,6 +1565,21 @@
         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);
diff --git a/ssl/record/record_locl.h b/ssl/record/record_locl.h
index 6394835..e249918 100644
--- a/ssl/record/record_locl.h
+++ b/ssl/record/record_locl.h
@@ -115,3 +115,4 @@
                                    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);
diff --git a/ssl/record/ssl3_record.c b/ssl/record/ssl3_record.c
index aebead2..50582d1 100644
--- a/ssl/record/ssl3_record.c
+++ b/ssl/record/ssl3_record.c
@@ -101,16 +101,16 @@
     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;
diff --git a/ssl/statem/statem.c b/ssl/statem/statem.c
index 9c74a29..2c202f4 100644
--- a/ssl/statem/statem.c
+++ b/ssl/statem/statem.c
@@ -157,8 +157,13 @@
     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;
 }