Adding ALPN to session.

0-RTT requires matching the selected ALPN parameters against those in
the session. Stash the ALPN value in the session in TLS 1.3, so we can
recover it.

BUG=76

Change-Id: I8668b287651ae4deb0bf540c0885a02d189adee0
Reviewed-on: https://boringssl-review.googlesource.com/13845
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/ssl_asn1.c b/ssl/ssl_asn1.c
index 3582864..3533225 100644
--- a/ssl/ssl_asn1.c
+++ b/ssl/ssl_asn1.c
@@ -130,6 +130,7 @@
  *     peerSignatureAlgorithm  [23] INTEGER OPTIONAL,
  *     ticketMaxEarlyData      [24] INTEGER OPTIONAL,
  *     authTimeout             [25] INTEGER OPTIONAL, -- defaults to timeout
+ *     earlyALPN               [26] OCTET STRING OPTIONAL,
  * }
  *
  * Note: historically this serialization has included other optional
@@ -186,6 +187,8 @@
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 24;
 static const int kAuthTimeoutTag =
     CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 25;
+static const int kEarlyALPNTag =
+    CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 26;
 
 static int SSL_SESSION_to_bytes_full(const SSL_SESSION *in, uint8_t **out_data,
                                      size_t *out_len, int for_ticket) {
@@ -412,6 +415,16 @@
     goto err;
   }
 
+  if (in->early_alpn) {
+    if (!CBB_add_asn1(&session, &child, kEarlyALPNTag) ||
+        !CBB_add_asn1(&child, &child2, CBS_ASN1_OCTETSTRING) ||
+        !CBB_add_bytes(&child2, (const uint8_t *)in->early_alpn,
+                       in->early_alpn_len)) {
+      OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
+      goto err;
+    }
+  }
+
   if (!CBB_finish(&cbb, out_data, out_len)) {
     OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
     goto err;
@@ -800,6 +813,8 @@
                              kTicketMaxEarlyDataTag, 0) ||
       !SSL_SESSION_parse_long(&session, &ret->auth_timeout, kAuthTimeoutTag,
                               ret->timeout) ||
+      !SSL_SESSION_parse_octet_string(&session, &ret->early_alpn,
+                                      &ret->early_alpn_len, kEarlyALPNTag) ||
       CBS_len(&session) != 0) {
     OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SSL_SESSION);
     goto err;
diff --git a/ssl/ssl_session.c b/ssl/ssl_session.c
index c30fe6e..60f20f4 100644
--- a/ssl/ssl_session.c
+++ b/ssl/ssl_session.c
@@ -280,6 +280,15 @@
     new_session->ticket_age_add = session->ticket_age_add;
     new_session->ticket_max_early_data = session->ticket_max_early_data;
     new_session->extended_master_secret = session->extended_master_secret;
+
+    if (session->early_alpn != NULL) {
+      new_session->early_alpn =
+          BUF_memdup(session->early_alpn, session->early_alpn_len);
+      if (new_session->early_alpn == NULL) {
+        goto err;
+      }
+    }
+    new_session->early_alpn_len = session->early_alpn_len;
   }
 
   /* Copy the ticket. */
@@ -373,6 +382,7 @@
   OPENSSL_free(session->tlsext_signed_cert_timestamp_list);
   OPENSSL_free(session->ocsp_response);
   OPENSSL_free(session->psk_identity);
+  OPENSSL_free(session->early_alpn);
   OPENSSL_cleanse(session, sizeof(*session));
   OPENSSL_free(session);
 }
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c
index 50f7e5a..815b30e 100644
--- a/ssl/tls13_client.c
+++ b/ssl/tls13_client.c
@@ -270,6 +270,17 @@
   ssl->s3->new_session->cipher = cipher;
   ssl->s3->tmp.new_cipher = cipher;
 
+  /* Store the initial negotiated ALPN in the session. */
+  if (ssl->s3->alpn_selected != NULL) {
+    ssl->s3->new_session->early_alpn =
+        BUF_memdup(ssl->s3->alpn_selected, ssl->s3->alpn_selected_len);
+    if (ssl->s3->new_session->early_alpn == NULL) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+      return ssl_hs_error;
+    }
+    ssl->s3->new_session->early_alpn_len = ssl->s3->alpn_selected_len;
+  }
+
   /* The PRF hash is now known. Set up the key schedule. */
   if (!tls13_init_key_schedule(hs)) {
     return ssl_hs_error;
diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c
index 0278b50..5c9e6db 100644
--- a/ssl/tls13_server.c
+++ b/ssl/tls13_server.c
@@ -251,6 +251,17 @@
     return ssl_hs_error;
   }
 
+  /* Store the initial negotiated ALPN in the session. */
+  if (ssl->s3->alpn_selected != NULL) {
+    ssl->s3->new_session->early_alpn =
+        BUF_memdup(ssl->s3->alpn_selected, ssl->s3->alpn_selected_len);
+    if (ssl->s3->new_session->early_alpn == NULL) {
+      ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+      return ssl_hs_error;
+    }
+    ssl->s3->new_session->early_alpn_len = ssl->s3->alpn_selected_len;
+  }
+
   /* Incorporate the PSK into the running secret. */
   if (ssl->s3->session_reused) {
     if (!tls13_advance_key_schedule(hs, ssl->s3->new_session->master_key,