Move ServerHello extension construction into the new extensions framework
This lays the foundation for a later move to have the extensions built and
placed into the correct message for TLSv1.3 (e.g. ServerHello or
EncryptedExtensions).
Perl changes reviewed by Richard Levitte. Non-perl changes reviewed by Rich
Salz
Reviewed-by: Rich Salz <rsalz@openssl.org>
Reviewed-by: Richard Levitte <levitte@openssl.org>
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 1cc481c..e8019c0 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -596,8 +596,8 @@
return 1;
}
-static void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
- size_t *num_formats)
+void tls1_get_formatlist(SSL *s, const unsigned char **pformats,
+ size_t *num_formats)
{
/*
* If we have a custom point format list use it otherwise use default
@@ -939,7 +939,7 @@
return !ssl_security(s, op, c->strength_bits, 0, (void *)c);
}
-static int tls_use_ticket(SSL *s)
+int tls_use_ticket(SSL *s)
{
if ((s->options & SSL_OP_NO_TICKET) || SSL_IS_TLS13(s))
return 0;
@@ -1512,289 +1512,6 @@
return 1;
}
-/*
- * Add the key_share extension.
- *
- * Returns 1 on success or 0 on failure.
- */
-static int add_client_key_share_ext(SSL *s, WPACKET *pkt, int *al)
-{
- unsigned char *encodedPoint;
- size_t encoded_pt_len = 0;
- EVP_PKEY *ckey = s->s3->peer_tmp, *skey = NULL;
-
- if (ckey == NULL) {
- SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_key_share)
- || !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_put_bytes_u16(pkt, s->s3->group_id)) {
- SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- skey = ssl_generate_pkey(ckey);
- if (skey == NULL) {
- SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_MALLOC_FAILURE);
- return 0;
- }
-
- /* Generate encoding of server key */
- encoded_pt_len = EVP_PKEY_get1_tls_encodedpoint(skey, &encodedPoint);
- if (encoded_pt_len == 0) {
- SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_EC_LIB);
- EVP_PKEY_free(skey);
- return 0;
- }
-
- if (!WPACKET_sub_memcpy_u16(pkt, encodedPoint, encoded_pt_len)
- || !WPACKET_close(pkt)) {
- SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
- EVP_PKEY_free(skey);
- OPENSSL_free(encodedPoint);
- return 0;
- }
- OPENSSL_free(encodedPoint);
-
- /* This causes the crypto state to be updated based on the derived keys */
- s->s3->tmp.pkey = skey;
- if (ssl_derive(s, skey, ckey, 1) == 0) {
- *al = SSL_AD_INTERNAL_ERROR;
- SSLerr(SSL_F_ADD_CLIENT_KEY_SHARE_EXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- return 1;
-}
-
-int ssl_add_serverhello_tlsext(SSL *s, WPACKET *pkt, int *al)
-{
-#ifndef OPENSSL_NO_NEXTPROTONEG
- int next_proto_neg_seen;
-#endif
-#ifndef OPENSSL_NO_EC
- unsigned long alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
- unsigned long alg_a = s->s3->tmp.new_cipher->algorithm_auth;
- int using_ecc = (alg_k & SSL_kECDHE) || (alg_a & SSL_aECDSA);
- using_ecc = using_ecc && (s->session->tlsext_ecpointformatlist != NULL);
-#endif
-
- if (!WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_set_flags(pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- if (s->s3->send_connection_binding &&
- !ssl_add_serverhello_renegotiate_ext(s, pkt)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- /* Only add RI for SSLv3 */
- if (s->version == SSL3_VERSION)
- goto done;
-
- if (!s->hit && s->servername_done == 1
- && s->session->tlsext_hostname != NULL) {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name)
- || !WPACKET_put_bytes_u16(pkt, 0)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
-#ifndef OPENSSL_NO_EC
- if (using_ecc) {
- const unsigned char *plist;
- size_t plistlen;
- /*
- * Add TLS extension ECPointFormats to the ServerHello message
- */
- tls1_get_formatlist(s, &plist, &plistlen);
-
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_ec_point_formats)
- || !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_sub_memcpy_u8(pkt, plist, plistlen)
- || !WPACKET_close(pkt)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
- /*
- * Currently the server should not respond with a SupportedCurves
- * extension
- */
-#endif /* OPENSSL_NO_EC */
-
- if (s->tlsext_ticket_expected && tls_use_ticket(s)) {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket)
- || !WPACKET_put_bytes_u16(pkt, 0)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- } else {
- /*
- * if we don't add the above TLSEXT, we can't add a session ticket
- * later
- */
- s->tlsext_ticket_expected = 0;
- }
-
- if (s->tlsext_status_expected) {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request)
- || !WPACKET_put_bytes_u16(pkt, 0)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
-#ifndef OPENSSL_NO_SRTP
- if (SSL_IS_DTLS(s) && s->srtp_profile) {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_use_srtp)
- || !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_put_bytes_u16(pkt, 2)
- || !WPACKET_put_bytes_u16(pkt, s->srtp_profile->id)
- || !WPACKET_put_bytes_u8(pkt, 0)
- || !WPACKET_close(pkt)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
-#endif
-
- if (((s->s3->tmp.new_cipher->id & 0xFFFF) == 0x80
- || (s->s3->tmp.new_cipher->id & 0xFFFF) == 0x81)
- && (SSL_get_options(s) & SSL_OP_CRYPTOPRO_TLSEXT_BUG)) {
- const unsigned char cryptopro_ext[36] = {
- 0xfd, 0xe8, /* 65000 */
- 0x00, 0x20, /* 32 bytes length */
- 0x30, 0x1e, 0x30, 0x08, 0x06, 0x06, 0x2a, 0x85,
- 0x03, 0x02, 0x02, 0x09, 0x30, 0x08, 0x06, 0x06,
- 0x2a, 0x85, 0x03, 0x02, 0x02, 0x16, 0x30, 0x08,
- 0x06, 0x06, 0x2a, 0x85, 0x03, 0x02, 0x02, 0x17
- };
- if (!WPACKET_memcpy(pkt, cryptopro_ext, sizeof(cryptopro_ext))) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
-
-#ifndef OPENSSL_NO_NEXTPROTONEG
- next_proto_neg_seen = s->s3->next_proto_neg_seen;
- s->s3->next_proto_neg_seen = 0;
- if (next_proto_neg_seen && s->ctx->next_protos_advertised_cb) {
- const unsigned char *npa;
- unsigned int npalen;
- int r;
-
- r = s->ctx->next_protos_advertised_cb(s, &npa, &npalen,
- s->
- ctx->next_protos_advertised_cb_arg);
- if (r == SSL_TLSEXT_ERR_OK) {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_next_proto_neg)
- || !WPACKET_sub_memcpy_u16(pkt, npa, npalen)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- s->s3->next_proto_neg_seen = 1;
- }
- }
-#endif
-
- if (SSL_IS_TLS13(s) && !s->hit && !add_client_key_share_ext(s, pkt, al))
- return 0;
-
- if (!custom_ext_add(s, 1, pkt, al)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- if (s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) {
- /*
- * Don't use encrypt_then_mac if AEAD or RC4 might want to disable
- * for other cases too.
- */
- if (s->s3->tmp.new_cipher->algorithm_mac == SSL_AEAD
- || s->s3->tmp.new_cipher->algorithm_enc == SSL_RC4
- || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT
- || s->s3->tmp.new_cipher->algorithm_enc == SSL_eGOST2814789CNT12)
- s->s3->flags &= ~TLS1_FLAGS_ENCRYPT_THEN_MAC;
- else {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_encrypt_then_mac)
- || !WPACKET_put_bytes_u16(pkt, 0)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
- }
- if (s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) {
- if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
- || !WPACKET_put_bytes_u16(pkt, 0)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
-
- if (s->s3->alpn_selected != NULL) {
- if (!WPACKET_put_bytes_u16(pkt,
- TLSEXT_TYPE_application_layer_protocol_negotiation)
- || !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_sub_memcpy_u8(pkt, s->s3->alpn_selected,
- s->s3->alpn_selected_len)
- || !WPACKET_close(pkt)
- || !WPACKET_close(pkt)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- }
-
- done:
- if (!WPACKET_close(pkt)) {
- SSLerr(SSL_F_SSL_ADD_SERVERHELLO_TLSEXT, ERR_R_INTERNAL_ERROR);
- return 0;
- }
- return 1;
-}
-
-/*
- * Process the ALPN extension in a ClientHello.
- * al: a pointer to the alert value to send in the event of a failure.
- * returns 1 on success, 0 on error.
- */
-static int tls1_alpn_handle_client_hello_late(SSL *s, int *al)
-{
- const unsigned char *selected = NULL;
- unsigned char selected_len = 0;
-
- if (s->ctx->alpn_select_cb != NULL && s->s3->alpn_proposed != NULL) {
- int r = s->ctx->alpn_select_cb(s, &selected, &selected_len,
- s->s3->alpn_proposed,
- (unsigned int)s->s3->alpn_proposed_len,
- s->ctx->alpn_select_cb_arg);
-
- if (r == SSL_TLSEXT_ERR_OK) {
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = OPENSSL_memdup(selected, selected_len);
- if (s->s3->alpn_selected == NULL) {
- *al = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- s->s3->alpn_selected_len = selected_len;
-#ifndef OPENSSL_NO_NEXTPROTONEG
- /* ALPN takes precedence over NPN. */
- s->s3->next_proto_neg_seen = 0;
-#endif
- } else {
- *al = SSL_AD_NO_APPLICATION_PROTOCOL;
- return 0;
- }
- }
-
- return 1;
-}
-
#ifndef OPENSSL_NO_NEXTPROTONEG
/*
* ssl_next_proto_validate validates a Next Protocol Negotiation block. No
@@ -2161,11 +1878,6 @@
return 1;
}
-int ssl_prepare_serverhello_tlsext(SSL *s)
-{
- return 1;
-}
-
/* Initialise digests to default values */
void ssl_set_default_md(SSL *s)
{
@@ -2228,58 +1940,6 @@
return 0;
}
-/*
- * Upon success, returns 1.
- * Upon failure, returns 0 and sets |al| to the appropriate fatal alert.
- */
-int ssl_check_clienthello_tlsext_late(SSL *s, int *al)
-{
- s->tlsext_status_expected = 0;
-
- /*
- * If status request then ask callback what to do. Note: this must be
- * called after servername callbacks in case the certificate has changed,
- * and must be called after the cipher has been chosen because this may
- * influence which certificate is sent
- */
- if ((s->tlsext_status_type != -1) && s->ctx && s->ctx->tlsext_status_cb) {
- int ret;
- CERT_PKEY *certpkey;
- certpkey = ssl_get_server_send_pkey(s);
- /* If no certificate can't return certificate status */
- if (certpkey != NULL) {
- /*
- * Set current certificate to one we will use so SSL_get_certificate
- * et al can pick it up.
- */
- s->cert->key = certpkey;
- ret = s->ctx->tlsext_status_cb(s, s->ctx->tlsext_status_arg);
- switch (ret) {
- /* We don't want to send a status request response */
- case SSL_TLSEXT_ERR_NOACK:
- s->tlsext_status_expected = 0;
- break;
- /* status request response should be sent */
- case SSL_TLSEXT_ERR_OK:
- if (s->tlsext_ocsp_resp)
- s->tlsext_status_expected = 1;
- break;
- /* something bad happened */
- case SSL_TLSEXT_ERR_ALERT_FATAL:
- default:
- *al = SSL_AD_INTERNAL_ERROR;
- return 0;
- }
- }
- }
-
- if (!tls1_alpn_handle_client_hello_late(s, al)) {
- return 0;
- }
-
- return 1;
-}
-
int ssl_check_serverhello_tlsext(SSL *s)
{
int ret = SSL_TLSEXT_ERR_NOACK;