Add the key_share processing to the server side At the moment the server doesn't yet do anything with this information. We still need to send the server's key_share info back to the client. That will happen in subsequent commits. Reviewed-by: Rich Salz <rsalz@openssl.org>
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index d78ea68..37e6841 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c
@@ -2201,8 +2201,108 @@ } #endif else if (currext->type == TLSEXT_TYPE_encrypt_then_mac - && !(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)) + && !(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)) { s->s3->flags |= TLS1_FLAGS_ENCRYPT_THEN_MAC; + } else if (currext->type == TLSEXT_TYPE_key_share + && s->version == TLS1_3_VERSION) { + unsigned int group_id; + PACKET key_share_list, encoded_pt; + const unsigned char *curves; + size_t num_curves, i; + int group_nid; + unsigned int curve_flags; + + /* Sanity check */ + if (s->s3->peer_tmp != NULL) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, ERR_R_INTERNAL_ERROR); + return 0; + } + + if (!PACKET_as_length_prefixed_2(&currext->data, &key_share_list)) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, + SSL_R_LENGTH_MISMATCH); + return 0; + } + + while (PACKET_remaining(&key_share_list) > 0) { + if (!PACKET_get_net_2(&key_share_list, &group_id) + || !PACKET_get_length_prefixed_2(&key_share_list, + &encoded_pt)) { + *al = SSL_AD_HANDSHAKE_FAILURE; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, + SSL_R_LENGTH_MISMATCH); + return 0; + } + + /* Find a share that we can use */ + if (!tls1_get_curvelist(s, 0, &curves, &num_curves)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, + ERR_R_INTERNAL_ERROR); + return 0; + } + for (i = 0; i < num_curves; i++, curves += 2) { + unsigned int share_id = (curves[0] << 8) | (curves[1]); + if (group_id == share_id + && tls_curve_allowed(s, curves, + SSL_SECOP_CURVE_CHECK)) { + break; + } + } + + if (i == num_curves) { + /* Share not suitable */ + continue; + } + + group_nid = tls1_ec_curve_id2nid(group_id, &curve_flags); + + if (group_nid == 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, + SSL_R_UNABLE_TO_FIND_ECDH_PARAMETERS); + return 0; + } + + if ((curve_flags & TLS_CURVE_TYPE) == TLS_CURVE_CUSTOM) { + /* Can happen for some curves, e.g. X25519 */ + EVP_PKEY *key = EVP_PKEY_new(); + + if (key == NULL || !EVP_PKEY_set_type(key, group_nid)) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, ERR_R_EVP_LIB); + EVP_PKEY_free(key); + return 0; + } + s->s3->peer_tmp = key; + } else { + /* Set up EVP_PKEY with named curve as parameters */ + EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new_id(EVP_PKEY_EC, NULL); + if (pctx == NULL + || EVP_PKEY_paramgen_init(pctx) <= 0 + || EVP_PKEY_CTX_set_ec_paramgen_curve_nid(pctx, + group_nid) <= 0 + || EVP_PKEY_paramgen(pctx, &s->s3->peer_tmp) <= 0) { + *al = SSL_AD_INTERNAL_ERROR; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, ERR_R_EVP_LIB); + EVP_PKEY_CTX_free(pctx); + return 0; + } + EVP_PKEY_CTX_free(pctx); + pctx = NULL; + } + + if (!EVP_PKEY_set1_tls_encodedpoint(s->s3->peer_tmp, + PACKET_data(&encoded_pt), + PACKET_remaining(&encoded_pt))) { + *al = SSL_AD_DECODE_ERROR; + SSLerr(SSL_F_SSL_SCAN_CLIENTHELLO_TLSEXT, SSL_R_BAD_ECPOINT); + return 0; + } + } + } /* * Note: extended master secret extension handled in * tls_check_client_ems_support()