Add server side support for creating the Hello Retry Request message
Reviewed-by: Richard Levitte <levitte@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/2341)
diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c
index c4d20e5..f7b7990 100644
--- a/ssl/statem/extensions_srvr.c
+++ b/ssl/statem/extensions_srvr.c
@@ -116,6 +116,8 @@
return 0;
}
+ OPENSSL_free(s->session->ext.hostname);
+ s->session->ext.hostname = NULL;
if (!PACKET_strndup(&hostname, &s->session->ext.hostname)) {
*al = TLS1_AD_INTERNAL_ERROR;
return 0;
@@ -361,6 +363,9 @@
}
} while (PACKET_remaining(&protocol_list) != 0);
+ OPENSSL_free(s->s3->alpn_proposed);
+ s->s3->alpn_proposed = NULL;
+ s->s3->alpn_proposed_len = 0;
if (!PACKET_memdup(&save_protocol_list,
&s->s3->alpn_proposed, &s->s3->alpn_proposed_len)) {
*al = TLS1_AD_INTERNAL_ERROR;
@@ -659,6 +664,9 @@
return 0;
}
+ OPENSSL_free(s->session->ext.supportedgroups);
+ s->session->ext.supportedgroups = NULL;
+ s->session->ext.supportedgroups_len = 0;
if (!PACKET_memdup(&supported_groups_list,
&s->session->ext.supportedgroups,
&s->session->ext.supportedgroups_len)) {
@@ -1024,7 +1032,65 @@
EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL;
if (ckey == NULL) {
- /* No key_share received from client; must be resuming. */
+ /* No key_share received from client */
+ if (s->hello_retry_request) {
+ const unsigned char *pcurves, *pcurvestmp, *clntcurves;
+ size_t num_curves, clnt_num_curves, i;
+
+ /* Get the clients list of supported groups. */
+ if (!tls1_get_curvelist(s, 1, &clntcurves, &clnt_num_curves)) {
+ *al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /* Get our list of available groups */
+ if (!tls1_get_curvelist(s, 0, &pcurves, &num_curves)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
+ || !WPACKET_start_sub_packet_u16(pkt)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ /* Find first group we allow that is also in client's list */
+ for (i = 0, pcurvestmp = pcurves; i < num_curves;
+ i++, pcurvestmp += 2) {
+ unsigned int group_id = pcurvestmp[0] << 8 | pcurvestmp[1];
+
+ if (check_in_list(s, group_id, clntcurves, clnt_num_curves,
+ 1)) {
+ if (!WPACKET_put_bytes_u16(pkt, group_id)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ break;
+ }
+ }
+ if (i == num_curves) {
+ /* No common groups */
+ *al = SSL_AD_HANDSHAKE_FAILURE;
+ SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+ SSL_R_NO_SHARED_GROUPS);
+ return 0;
+ }
+ if (!WPACKET_close(pkt)) {
+ SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ return 1;
+ }
+
+ /* Must be resuming. */
if (!s->hit || !tls13_generate_handshake_secret(s, NULL, 0)) {
*al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_TLS_CONSTRUCT_STOC_KEY_SHARE, ERR_R_INTERNAL_ERROR);