Add Data-less Zero-RTT support.

This adds support on the server and client to accept data-less early
data. The server will still fail to parse early data with any
contents, so this should remain disabled.

BUG=76

Change-Id: Id85d192d8e0360b8de4b6971511b5e8a0e8012f7
Reviewed-on: https://boringssl-review.googlesource.com/12921
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c
index 9c8d1a1..4854002 100644
--- a/ssl/tls13_server.c
+++ b/ssl/tls13_server.c
@@ -43,6 +43,8 @@
   state_send_server_certificate_verify,
   state_complete_server_certificate_verify,
   state_send_server_finished,
+  state_read_second_client_flight,
+  state_process_end_of_early_data,
   state_process_client_certificate,
   state_process_client_certificate_verify,
   state_process_channel_id,
@@ -289,6 +291,19 @@
       /* Carry over authentication information from the previous handshake into
        * a fresh session. */
       hs->new_session = SSL_SESSION_dup(session, SSL_SESSION_DUP_AUTH_ONLY);
+
+      if (/* Early data must be acceptable for this ticket. */
+          ssl->ctx->enable_early_data &&
+          session->ticket_max_early_data != 0 &&
+          /* The client must have offered early data. */
+          hs->early_data_offered &&
+          /* The negotiated ALPN must match the one in the ticket. */
+          ssl->s3->alpn_selected_len == session->early_alpn_len &&
+          OPENSSL_memcmp(ssl->s3->alpn_selected, session->early_alpn,
+                         ssl->s3->alpn_selected_len) == 0) {
+        ssl->early_data_accepted = 1;
+      }
+
       SSL_SESSION_free(session);
       if (hs->new_session == NULL) {
         ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
@@ -323,6 +338,7 @@
     }
   }
 
+  /* Store the initial negotiated ALPN in the session. */
   if (ssl->s3->alpn_selected != NULL) {
     hs->new_session->early_alpn =
         BUF_memdup(ssl->s3->alpn_selected, ssl->s3->alpn_selected_len);
@@ -351,12 +367,22 @@
     return ssl_hs_error;
   }
 
+  if (ssl->early_data_accepted) {
+    if (!tls13_derive_early_secrets(hs)) {
+      return ssl_hs_error;
+    }
+  } else if (hs->early_data_offered) {
+    ssl->s3->skip_early_data = 1;
+  }
+
   ssl->method->received_flight(ssl);
 
   /* Resolve ECDHE and incorporate it into the secret. */
   int need_retry;
   if (!resolve_ecdhe_secret(hs, &need_retry, &client_hello)) {
     if (need_retry) {
+      ssl->early_data_accepted = 0;
+      ssl->s3->skip_early_data = 1;
       hs->tls13_state = state_send_hello_retry_request;
       return ssl_hs_ok;
     }
@@ -440,8 +466,6 @@
 
   /* Derive and enable the handshake traffic secrets. */
   if (!tls13_derive_handshake_secrets(hs) ||
-      !tls13_set_traffic_key(ssl, evp_aead_open, hs->client_handshake_secret,
-                             hs->hash_len) ||
       !tls13_set_traffic_key(ssl, evp_aead_seal, hs->server_handshake_secret,
                              hs->hash_len)) {
     goto err;
@@ -543,8 +567,33 @@
     return ssl_hs_error;
   }
 
+  hs->tls13_state = state_read_second_client_flight;
+  return ssl_hs_flush;
+}
+
+static enum ssl_hs_wait_t do_read_second_client_flight(SSL_HANDSHAKE *hs) {
+  SSL *const ssl = hs->ssl;
+  if (ssl->early_data_accepted) {
+    if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->early_traffic_secret,
+                               hs->hash_len)) {
+      return ssl_hs_error;
+    }
+    hs->tls13_state = state_process_end_of_early_data;
+    return ssl_hs_read_end_of_early_data;
+  }
+
+  hs->tls13_state = state_process_end_of_early_data;
+  return ssl_hs_ok;
+}
+
+static enum ssl_hs_wait_t do_process_end_of_early_data(SSL_HANDSHAKE *hs) {
+  SSL *const ssl = hs->ssl;
+  if (!tls13_set_traffic_key(ssl, evp_aead_open, hs->client_handshake_secret,
+                             hs->hash_len)) {
+    return ssl_hs_error;
+  }
   hs->tls13_state = state_process_client_certificate;
-  return ssl_hs_flush_and_read_message;
+  return ssl_hs_read_message;
 }
 
 static enum ssl_hs_wait_t do_process_client_certificate(SSL_HANDSHAKE *hs) {
@@ -720,10 +769,16 @@
       break;
       case state_complete_server_certificate_verify:
         ret = do_send_server_certificate_verify(hs, 0 /* complete */);
-      break;
+        break;
       case state_send_server_finished:
         ret = do_send_server_finished(hs);
         break;
+      case state_read_second_client_flight:
+        ret = do_read_second_client_flight(hs);
+        break;
+      case state_process_end_of_early_data:
+        ret = do_process_end_of_early_data(hs);
+        break;
       case state_process_client_certificate:
         ret = do_process_client_certificate(hs);
         break;