diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 95b53925ac..b8e2188651 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2275,10 +2275,22 @@ int ERR_load_SSL_strings(void); # define SSL_F_TLS_CONSTRUCT_HELLO_REQUEST 373 # define SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET 428 # define SSL_F_TLS_CONSTRUCT_NEXT_PROTO 426 +# define SSL_F_TLS_CONSTRUCT_SERVER_ALPN 451 # define SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE 374 +# define SSL_F_TLS_CONSTRUCT_SERVER_CRYPTOPRO_BUG 452 # define SSL_F_TLS_CONSTRUCT_SERVER_DONE 375 +# define SSL_F_TLS_CONSTRUCT_SERVER_EC_PT_FORMATS 453 +# define SSL_F_TLS_CONSTRUCT_SERVER_EMS 454 +# define SSL_F_TLS_CONSTRUCT_SERVER_ETM 455 # define SSL_F_TLS_CONSTRUCT_SERVER_HELLO 376 # define SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE 377 +# define SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE 456 +# define SSL_F_TLS_CONSTRUCT_SERVER_NEXT_PROTO_NEG 457 +# define SSL_F_TLS_CONSTRUCT_SERVER_RENEGOTIATE 458 +# define SSL_F_TLS_CONSTRUCT_SERVER_SERVER_NAME 459 +# define SSL_F_TLS_CONSTRUCT_SERVER_SESSION_TICKET 460 +# define SSL_F_TLS_CONSTRUCT_SERVER_STATUS_REQUEST 461 +# define SSL_F_TLS_CONSTRUCT_SERVER_USE_SRTP 462 # define SSL_F_TLS_GET_MESSAGE_BODY 351 # define SSL_F_TLS_GET_MESSAGE_HEADER 387 # define SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE 445 diff --git a/ssl/ssl_err.c b/ssl/ssl_err.c index b5b9857ebd..af87a349a5 100644 --- a/ssl/ssl_err.c +++ b/ssl/ssl_err.c @@ -282,13 +282,34 @@ static ERR_STRING_DATA SSL_str_functs[] = { {ERR_FUNC(SSL_F_TLS_CONSTRUCT_NEW_SESSION_TICKET), "tls_construct_new_session_ticket"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_NEXT_PROTO), "tls_construct_next_proto"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_ALPN), "tls_construct_server_alpn"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_CERTIFICATE), "tls_construct_server_certificate"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_CRYPTOPRO_BUG), + "tls_construct_server_cryptopro_bug"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_DONE), "tls_construct_server_done"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_EC_PT_FORMATS), + "tls_construct_server_ec_pt_formats"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_EMS), "tls_construct_server_ems"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_ETM), "tls_construct_server_etm"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_HELLO), "tls_construct_server_hello"}, {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_KEY_EXCHANGE), "tls_construct_server_key_exchange"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE), + "tls_construct_server_key_share"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_NEXT_PROTO_NEG), + "tls_construct_server_next_proto_neg"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_RENEGOTIATE), + "tls_construct_server_renegotiate"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_SERVER_NAME), + "tls_construct_server_server_name"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_SESSION_TICKET), + "tls_construct_server_session_ticket"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_STATUS_REQUEST), + "tls_construct_server_status_request"}, + {ERR_FUNC(SSL_F_TLS_CONSTRUCT_SERVER_USE_SRTP), + "tls_construct_server_use_srtp"}, {ERR_FUNC(SSL_F_TLS_GET_MESSAGE_BODY), "tls_get_message_body"}, {ERR_FUNC(SSL_F_TLS_GET_MESSAGE_HEADER), "tls_get_message_header"}, {ERR_FUNC(SSL_F_TLS_PARSE_CLIENTHELLO_KEY_SHARE), diff --git a/ssl/ssl_locl.h b/ssl/ssl_locl.h index 5821968bd8..926c6c6396 100644 --- a/ssl/ssl_locl.h +++ b/ssl/ssl_locl.h @@ -2064,6 +2064,8 @@ __owur int tls1_set_groups(unsigned char **pext, size_t *pextlen, int *curves, size_t ncurves); __owur int tls1_set_groups_list(unsigned char **pext, size_t *pextlen, const char *str); +void tls1_get_formatlist(SSL *s, const unsigned char **pformats, + size_t *num_formats); __owur int tls1_check_ec_tmp_key(SSL *s, unsigned long id); __owur EVP_PKEY *ssl_generate_pkey_curve(int id); # endif /* OPENSSL_NO_EC */ @@ -2076,18 +2078,17 @@ __owur int tls1_get_curvelist(SSL *s, int sess, const unsigned char **pcurves, size_t *num_curves); __owur int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al); -__owur int ssl_add_serverhello_tlsext(SSL *s, WPACKET *pkt, int *al); void ssl_set_default_md(SSL *s); __owur int tls1_set_server_sigalgs(SSL *s); __owur int ssl_check_clienthello_tlsext_late(SSL *s, int *al); __owur int ssl_parse_serverhello_tlsext(SSL *s, PACKET *pkt); __owur int ssl_prepare_clienthello_tlsext(SSL *s); -__owur int ssl_prepare_serverhello_tlsext(SSL *s); __owur RAW_EXTENSION *tls_get_extension_by_type(RAW_EXTENSION *exts, size_t numexts, unsigned int type); __owur int tls_get_ticket_from_client(SSL *s, CLIENTHELLO_MSG *hello, SSL_SESSION **ret); +__owur int tls_use_ticket(SSL *s); __owur int tls12_get_sigandhash(WPACKET *pkt, const EVP_PKEY *pk, const EVP_MD *md); @@ -2116,7 +2117,6 @@ __owur int ssl_security_cert_chain(SSL *s, STACK_OF(X509) *sk, X509 *ex, __owur EVP_MD_CTX *ssl_replace_hash(EVP_MD_CTX **hash, const EVP_MD *md); void ssl_clear_hash_ctx(EVP_MD_CTX **hash); -__owur int ssl_add_serverhello_renegotiate_ext(SSL *s, WPACKET *pkt); __owur int ssl_parse_serverhello_renegotiate_ext(SSL *s, PACKET *pkt, int *al); __owur long ssl_get_algorithm2(SSL *s); __owur int tls12_copy_sigalgs(SSL *s, WPACKET *pkt, diff --git a/ssl/statem/extensions.c b/ssl/statem/extensions.c index 8bea0746e1..0b82ad7ea7 100644 --- a/ssl/statem/extensions.c +++ b/ssl/statem/extensions.c @@ -31,7 +31,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_renegotiate, tls_parse_clienthello_renegotiate, NULL, - NULL, + tls_construct_server_renegotiate, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_SSL3_ALLOWED | EXT_TLS1_2_AND_BELOW_ONLY @@ -40,7 +40,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_server_name, tls_parse_clienthello_server_name, NULL, - NULL, + tls_construct_server_server_name, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | /*EXT_TLS1_3_ENCRYPTED_EXTENSIONS*/EXT_TLS1_3_SERVER_HELLO @@ -60,7 +60,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_ec_point_formats, tls_parse_clienthello_ec_pt_formats, NULL, - NULL, + tls_construct_server_ec_pt_formats, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_AND_BELOW_ONLY }, @@ -68,7 +68,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_supported_groups, tls_parse_clienthello_supported_groups, NULL, - NULL, + NULL /* TODO(TLS1.3): Need to add this */, NULL, EXT_CLIENT_HELLO | /*EXT_TLS1_3_ENCRYPTED_EXTENSIONS*/EXT_TLS1_3_SERVER_HELLO @@ -78,7 +78,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_session_ticket, tls_parse_clienthello_session_ticket, NULL, - NULL, + tls_construct_server_session_ticket, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY }, @@ -94,7 +94,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_status_request, tls_parse_clienthello_status_request, NULL, - NULL, + tls_construct_server_status_request, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | /*EXT_TLS1_3_CERTIFICATE*/EXT_TLS1_3_SERVER_HELLO @@ -104,7 +104,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_next_proto_neg, tls_parse_clienthello_npn, NULL, - NULL, + tls_construct_server_next_proto_neg, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY }, @@ -113,25 +113,27 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_application_layer_protocol_negotiation, tls_parse_clienthello_alpn, NULL, - NULL, + tls_construct_server_alpn, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | /*EXT_TLS1_3_ENCRYPTED_EXTENSIONS*/EXT_TLS1_3_SERVER_HELLO }, +#ifndef OPENSSL_NO_SRTP { TLSEXT_TYPE_use_srtp, tls_parse_clienthello_use_srtp, NULL, - NULL, + tls_construct_server_use_srtp, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_3_ENCRYPTED_EXTENSIONS | EXT_DTLS_ONLY }, +#endif { TLSEXT_TYPE_encrypt_then_mac, tls_parse_clienthello_etm, NULL, - NULL, + tls_construct_server_etm, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY }, @@ -153,7 +155,7 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_extended_master_secret, tls_parse_clienthello_ems, NULL, - NULL, + tls_construct_server_ems, NULL, EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY }, @@ -179,11 +181,23 @@ static const EXTENSION_DEFINITION ext_defs[] = { TLSEXT_TYPE_key_share, tls_parse_clienthello_key_share, NULL, - NULL, + tls_construct_server_key_share, NULL, EXT_CLIENT_HELLO | EXT_TLS1_3_SERVER_HELLO | EXT_TLS1_3_HELLO_RETRY_REQUEST | EXT_TLS_IMPLEMENTATION_ONLY | EXT_TLS1_3_ONLY + }, + { + /* + * Special unsolicited ServerHello extension only used when + * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set + */ + TLSEXT_TYPE_cryptopro_bug, + NULL, + NULL, + tls_construct_server_cryptopro_bug, + NULL, + EXT_TLS1_2_SERVER_HELLO | EXT_TLS1_2_AND_BELOW_ONLY } }; @@ -440,15 +454,21 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context, size_t loop; int addcustom = 0; + /* + * Normally if something goes wrong during construction its an internal + * error. We can always override this later. + */ + *al = SSL_AD_INTERNAL_ERROR; + if (!WPACKET_start_sub_packet_u16(pkt) /* * If extensions are of zero length then we don't even add the - * extensions length bytes to a ClientHello + * extensions length bytes to a ClientHello/ServerHello in SSLv3 */ - || ((context & EXT_CLIENT_HELLO) != 0 + || ((context & (EXT_CLIENT_HELLO | EXT_TLS1_2_SERVER_HELLO)) != 0 + && s->version == SSL3_VERSION && !WPACKET_set_flags(pkt, WPACKET_FLAGS_ABANDON_ON_ZERO_LENGTH))) { - *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, ERR_R_INTERNAL_ERROR); return 0; } @@ -504,7 +524,6 @@ int tls_construct_extensions(SSL *s, WPACKET *pkt, unsigned int context, } if (!WPACKET_close(pkt)) { - *al = SSL_AD_INTERNAL_ERROR; SSLerr(SSL_F_TLS_CONSTRUCT_EXTENSIONS, ERR_R_INTERNAL_ERROR); return 0; } diff --git a/ssl/statem/extensions_srvr.c b/ssl/statem/extensions_srvr.c index 38a6bef862..e313e9aa5c 100644 --- a/ssl/statem/extensions_srvr.c +++ b/ssl/statem/extensions_srvr.c @@ -647,3 +647,373 @@ int tls_parse_clienthello_ems(SSL *s, PACKET *pkt, int *al) 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; +} + +/* + * 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; +} + +/* Add the server's renegotiation binding */ +int tls_construct_server_renegotiate(SSL *s, WPACKET *pkt, int *al) +{ + if (!s->s3->send_connection_binding) + return 1; + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate) + || !WPACKET_start_sub_packet_u16(pkt) + || !WPACKET_start_sub_packet_u8(pkt) + || !WPACKET_memcpy(pkt, s->s3->previous_client_finished, + s->s3->previous_client_finished_len) + || !WPACKET_memcpy(pkt, s->s3->previous_server_finished, + s->s3->previous_server_finished_len) + || !WPACKET_close(pkt) + || !WPACKET_close(pkt)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_RENEGOTIATE, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + +int tls_construct_server_server_name(SSL *s, WPACKET *pkt, int *al) +{ + if (s->hit || s->servername_done != 1 + || s->session->tlsext_hostname == NULL) + return 1; + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_server_name) + || !WPACKET_put_bytes_u16(pkt, 0)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_SERVER_NAME, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + +#ifndef OPENSSL_NO_EC +int tls_construct_server_ec_pt_formats(SSL *s, WPACKET *pkt, int *al) +{ + 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); + const unsigned char *plist; + size_t plistlen; + + if (!using_ecc) + return 1; + + 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_TLS_CONSTRUCT_SERVER_EC_PT_FORMATS, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} +#endif + +int tls_construct_server_session_ticket(SSL *s, WPACKET *pkt, int *al) +{ + if (!s->tlsext_ticket_expected || !tls_use_ticket(s)) { + s->tlsext_ticket_expected = 0; + return 1; + } + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_session_ticket) + || !WPACKET_put_bytes_u16(pkt, 0)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_SESSION_TICKET, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + +int tls_construct_server_status_request(SSL *s, WPACKET *pkt, int *al) +{ + if (!s->tlsext_status_expected) + return 1; + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_status_request) + || !WPACKET_put_bytes_u16(pkt, 0)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_STATUS_REQUEST, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + + +#ifndef OPENSSL_NO_NEXTPROTONEG +int tls_construct_server_next_proto_neg(SSL *s, WPACKET *pkt, int *al) +{ + const unsigned char *npa; + unsigned int npalen; + int ret; + int 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 == NULL) + return 1; + + ret = s->ctx->next_protos_advertised_cb(s, &npa, &npalen, + s->ctx->next_protos_advertised_cb_arg); + if (ret == 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_TLS_CONSTRUCT_SERVER_NEXT_PROTO_NEG, + ERR_R_INTERNAL_ERROR); + return 0; + } + s->s3->next_proto_neg_seen = 1; + } + + return 1; +} +#endif + +int tls_construct_server_alpn(SSL *s, WPACKET *pkt, int *al) +{ + if (s->s3->alpn_selected == NULL) + return 1; + + 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_TLS_CONSTRUCT_SERVER_ALPN, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + +#ifndef OPENSSL_NO_SRTP +int tls_construct_server_use_srtp(SSL *s, WPACKET *pkt, int *al) +{ + if (s->srtp_profile == NULL) + return 1; + + 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_TLS_CONSTRUCT_SERVER_USE_SRTP, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} +#endif + +int tls_construct_server_etm(SSL *s, WPACKET *pkt, int *al) +{ + if ((s->s3->flags & TLS1_FLAGS_ENCRYPT_THEN_MAC) == 0) + return 1; + + /* + * 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; + return 1; + } + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_encrypt_then_mac) + || !WPACKET_put_bytes_u16(pkt, 0)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_ETM, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + +int tls_construct_server_ems(SSL *s, WPACKET *pkt, int *al) +{ + if ((s->s3->flags & TLS1_FLAGS_RECEIVED_EXTMS) == 0) + return 1; + + if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret) + || !WPACKET_put_bytes_u16(pkt, 0)) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_EMS, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + +int tls_construct_server_key_share(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 (s->hit) + return 1; + + if (ckey == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE, 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_TLS_CONSTRUCT_SERVER_KEY_SHARE, ERR_R_INTERNAL_ERROR); + return 0; + } + + skey = ssl_generate_pkey(ckey); + if (skey == NULL) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE, 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_TLS_CONSTRUCT_SERVER_KEY_SHARE, 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_TLS_CONSTRUCT_SERVER_KEY_SHARE, 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) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_KEY_SHARE, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} + +int tls_construct_server_cryptopro_bug(SSL *s, WPACKET *pkt, int *al) +{ + 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 (((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) == 0) + return 1; + + if (!WPACKET_memcpy(pkt, cryptopro_ext, sizeof(cryptopro_ext))) { + SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_CRYPTOPRO_BUG, ERR_R_INTERNAL_ERROR); + return 0; + } + + return 1; +} diff --git a/ssl/statem/statem_locl.h b/ssl/statem/statem_locl.h index c884eab676..7032ab4eb4 100644 --- a/ssl/statem/statem_locl.h +++ b/ssl/statem/statem_locl.h @@ -179,3 +179,22 @@ int tls_parse_clienthello_use_srtp(SSL *s, PACKET *pkt, int *al); int tls_parse_clienthello_etm(SSL *s, PACKET *pkt, int *al); int tls_parse_clienthello_key_share(SSL *s, PACKET *pkt, int *al); int tls_parse_clienthello_ems(SSL *s, PACKET *pkt, int *al); + +int tls_construct_server_renegotiate(SSL *s, WPACKET *pkt, int *al); +int tls_construct_server_server_name(SSL *s, WPACKET *pkt, int *al); +int tls_construct_server_ec_pt_formats(SSL *s, WPACKET *pkt, int *al); +int tls_construct_server_session_ticket(SSL *s, WPACKET *pkt, int *al); +int tls_construct_server_status_request(SSL *s, WPACKET *pkt, int *al); +int tls_construct_server_next_proto_neg(SSL *s, WPACKET *pkt, int *al); +int tls_construct_server_alpn(SSL *s, WPACKET *pkt, int *al); +int tls_construct_server_use_srtp(SSL *s, WPACKET *pkt, int *al); +int tls_construct_server_etm(SSL *s, WPACKET *pkt, int *al); +int tls_construct_server_ems(SSL *s, WPACKET *pkt, int *al); +int tls_construct_server_key_share(SSL *s, WPACKET *pkt, int *al); + +/* + * Not in public headers as this is not an official extension. Only used when + * SSL_OP_CRYPTOPRO_TLSEXT_BUG is set. + */ +#define TLSEXT_TYPE_cryptopro_bug 0xfde8 +int tls_construct_server_cryptopro_bug(SSL *s, WPACKET *pkt, int *al); diff --git a/ssl/statem/statem_srvr.c b/ssl/statem/statem_srvr.c index 773e732642..cc4b8c3153 100644 --- a/ssl/statem/statem_srvr.c +++ b/ssl/statem/statem_srvr.c @@ -1980,15 +1980,20 @@ int tls_construct_server_hello(SSL *s, WPACKET *pkt) || !s->method->put_cipher_by_char(s->s3->tmp.new_cipher, pkt, &len) || (!SSL_IS_TLS13(s) && !WPACKET_put_bytes_u8(pkt, compm)) - || !ssl_prepare_serverhello_tlsext(s) - || !ssl_add_serverhello_tlsext(s, pkt, &al)) { + /* + * TODO(TLS1.3): For now we add all 1.2 and 1.3 extensions. Later + * we will do this based on the actual protocol + */ + || !tls_construct_extensions(s, pkt, + EXT_TLS1_2_SERVER_HELLO + | EXT_TLS1_3_SERVER_HELLO, &al)) { SSLerr(SSL_F_TLS_CONSTRUCT_SERVER_HELLO, ERR_R_INTERNAL_ERROR); goto err; } return 1; err: - ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR); + ssl3_send_alert(s, SSL3_AL_FATAL, al); return 0; } diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 1cc481cc49..e8019c0471 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c @@ -596,8 +596,8 @@ static int tls1_check_ec_key(SSL *s, 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 @@ int ssl_cipher_disabled(SSL *s, const SSL_CIPHER *c, int op) 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 @@ int ssl_add_clienthello_tlsext(SSL *s, WPACKET *pkt, int *al) 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 @@ int ssl_prepare_clienthello_tlsext(SSL *s) 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 @@ int tls1_set_server_sigalgs(SSL *s) 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; diff --git a/ssl/t1_reneg.c b/ssl/t1_reneg.c index 5e9c71eecc..4301a38be5 100644 --- a/ssl/t1_reneg.c +++ b/ssl/t1_reneg.c @@ -11,23 +11,6 @@ #include #include "ssl_locl.h" -/* Add the server's renegotiation binding */ -int ssl_add_serverhello_renegotiate_ext(SSL *s, WPACKET *pkt) -{ - if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate) - || !WPACKET_start_sub_packet_u16(pkt) - || !WPACKET_start_sub_packet_u8(pkt) - || !WPACKET_memcpy(pkt, s->s3->previous_client_finished, - s->s3->previous_client_finished_len) - || !WPACKET_memcpy(pkt, s->s3->previous_server_finished, - s->s3->previous_server_finished_len) - || !WPACKET_close(pkt) - || !WPACKET_close(pkt)) - return 0; - - return 1; -} - /* * Parse the server's renegotiation binding and abort if it's not right */