Adding HelloRetryRequest.

[Tests added by davidben.]

Change-Id: I0d54a4f8b8fe91b348ff22658d95340cdb48b089
Reviewed-on: https://boringssl-review.googlesource.com/8850
Reviewed-by: Steven Valdez <svaldez@google.com>
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/t1_lib.c b/ssl/t1_lib.c
index f76d9f0..7549240 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -300,12 +300,9 @@
 #endif
 };
 
-/* tls1_get_grouplist sets |*out_group_ids| and |*out_group_ids_len| to the
- * list of allowed group IDs. If |get_peer_groups| is non-zero, return the
- * peer's group list. Otherwise, return the preferred list. */
-static void tls1_get_grouplist(SSL *ssl, int get_peer_groups,
-                               const uint16_t **out_group_ids,
-                               size_t *out_group_ids_len) {
+void tls1_get_grouplist(SSL *ssl, int get_peer_groups,
+                        const uint16_t **out_group_ids,
+                        size_t *out_group_ids_len) {
   if (get_peer_groups) {
     /* Only clients send a supported group list, so this function is only
      * called on the server. */
@@ -1973,7 +1970,24 @@
 
   const uint16_t *groups;
   size_t groups_len;
-  tls1_get_grouplist(ssl, 0 /* local groups */, &groups, &groups_len);
+  if (ssl->s3->hs->retry_group) {
+    /* Append the new key share to the old list. */
+    if (!CBB_add_bytes(&kse_bytes, ssl->s3->hs->key_share_bytes,
+                       ssl->s3->hs->key_share_bytes_len)) {
+      return 0;
+    }
+    OPENSSL_free(ssl->s3->hs->key_share_bytes);
+    ssl->s3->hs->key_share_bytes = NULL;
+
+    groups = &ssl->s3->hs->retry_group;
+    groups_len = 1;
+  } else {
+    tls1_get_grouplist(ssl, 0 /* local groups */, &groups, &groups_len);
+    /* Only send the top two preferred key shares. */
+    if (groups_len > 2) {
+      groups_len = 2;
+    }
+  }
 
   ssl->s3->hs->groups = OPENSSL_malloc(groups_len * sizeof(SSL_ECDH_CTX));
   if (ssl->s3->hs->groups == NULL) {
@@ -1996,6 +2010,17 @@
     }
   }
 
+  if (!ssl->s3->hs->retry_group) {
+    /* Save the contents of the extension to repeat it in the second
+     * ClientHello. */
+    ssl->s3->hs->key_share_bytes_len = CBB_len(&kse_bytes);
+    ssl->s3->hs->key_share_bytes = BUF_memdup(CBB_data(&kse_bytes),
+                                              CBB_len(&kse_bytes));
+    if (ssl->s3->hs->key_share_bytes == NULL) {
+      return 0;
+    }
+  }
+
   return CBB_flush(out);
 }
 
@@ -2030,16 +2055,12 @@
     return 0;
   }
 
-  for (size_t i = 0; i < ssl->s3->hs->groups_len; i++) {
-    SSL_ECDH_CTX_cleanup(&ssl->s3->hs->groups[i]);
-  }
-  OPENSSL_free(ssl->s3->hs->groups);
-  ssl->s3->hs->groups = NULL;
-
+  ssl_handshake_clear_groups(ssl->s3->hs);
   return 1;
 }
 
-int ext_key_share_parse_clienthello(SSL *ssl, uint8_t **out_secret,
+int ext_key_share_parse_clienthello(SSL *ssl, int *out_found,
+                                    uint8_t **out_secret,
                                     size_t *out_secret_len, uint8_t *out_alert,
                                     CBS *contents) {
   uint16_t group_id;
@@ -2049,7 +2070,7 @@
     return 0;
   }
 
-  int found = 0;
+  *out_found = 0;
   while (CBS_len(&key_shares) > 0) {
     uint16_t id;
     CBS peer_key;
@@ -2058,7 +2079,7 @@
       return 0;
     }
 
-    if (id != group_id || found) {
+    if (id != group_id || *out_found) {
       continue;
     }
 
@@ -2078,10 +2099,10 @@
     }
     SSL_ECDH_CTX_cleanup(&group);
 
-    found = 1;
+    *out_found = 1;
   }
 
-  return found;
+  return 1;
 }
 
 int ext_key_share_add_serverhello(SSL *ssl, CBB *out) {