/*
* Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved.
*
- * Licensed under the OpenSSL license (the "License"). You may not use
+ * Licensed under the Apache License 2.0 (the "License"). You may not use
* this file except in compliance with the License. You can obtain a copy
* in the file LICENSE in the source distribution or at
* https://www.openssl.org/source/license.html
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_renegotiate)
|| !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_sub_memcpy_u8(pkt, s->s3->previous_client_finished,
- s->s3->previous_client_finished_len)
+ || !WPACKET_sub_memcpy_u8(pkt, s->s3.previous_client_finished,
+ s->s3.previous_client_finished_len)
|| !WPACKET_close(pkt)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_RENEGOTIATE,
ERR_R_INTERNAL_ERROR);
{
const uint16_t *pgroups = NULL;
size_t num_groups = 0, i;
+ int min_version, max_version, reason;
if (!use_ecc(s))
return EXT_RETURN_NOT_SENT;
+ reason = ssl_get_min_max_version(s, &min_version, &max_version, NULL);
+ if (reason != 0) {
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS, reason);
+ return EXT_RETURN_FAIL;
+ }
+
/*
* Add TLS extension supported_groups to the ClientHello message
*/
- /* TODO(TLS1.3): Add support for DHE groups */
tls1_get_supported_groups(s, &pgroups, &num_groups);
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_supported_groups)
/* Sub-packet for supported_groups extension */
|| !WPACKET_start_sub_packet_u16(pkt)
- || !WPACKET_start_sub_packet_u16(pkt)) {
+ || !WPACKET_start_sub_packet_u16(pkt)
+ || !WPACKET_set_flags(pkt, WPACKET_FLAGS_NON_ZERO_LENGTH)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR,
SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
- /* Copy curve ID if supported */
+ /* Copy group ID if supported */
for (i = 0; i < num_groups; i++) {
uint16_t ctmp = pgroups[i];
- if (tls_curve_allowed(s, ctmp, SSL_SECOP_CURVE_SUPPORTED)) {
+ if (tls_valid_group(s, ctmp, max_version)
+ && tls_curve_allowed(s, ctmp, SSL_SECOP_CURVE_SUPPORTED)) {
if (!WPACKET_put_bytes_u16(pkt, ctmp)) {
- SSLfatal(s, SSL_AD_INTERNAL_ERROR,
- SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
- ERR_R_INTERNAL_ERROR);
- return EXT_RETURN_FAIL;
- }
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_CTOS_SUPPORTED_GROUPS,
+ ERR_R_INTERNAL_ERROR);
+ return EXT_RETURN_FAIL;
+ }
}
}
if (!WPACKET_close(pkt) || !WPACKET_close(pkt)) {
EXT_RETURN tls_construct_ctos_alpn(SSL *s, WPACKET *pkt, unsigned int context,
X509 *x, size_t chainidx)
{
- s->s3->alpn_sent = 0;
+ s->s3.alpn_sent = 0;
if (s->ext.alpn == NULL || !SSL_IS_FIRST_HANDSHAKE(s))
return EXT_RETURN_NOT_SENT;
ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
- s->s3->alpn_sent = 1;
+ s->s3.alpn_sent = 1;
return EXT_RETURN_SENT;
}
EXT_RETURN tls_construct_ctos_ems(SSL *s, WPACKET *pkt, unsigned int context,
X509 *x, size_t chainidx)
{
+ if (s->options & SSL_OP_NO_EXTENDED_MASTER_SECRET)
+ return EXT_RETURN_NOT_SENT;
+
if (!WPACKET_put_bytes_u16(pkt, TLSEXT_TYPE_extended_master_secret)
|| !WPACKET_put_bytes_u16(pkt, 0)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CTOS_EMS,
EVP_PKEY *key_share_key = NULL;
size_t encodedlen;
- if (s->s3->tmp.pkey != NULL) {
+ if (s->s3.tmp.pkey != NULL) {
if (!ossl_assert(s->hello_retry_request == SSL_HRR_PENDING)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_ADD_KEY_SHARE,
ERR_R_INTERNAL_ERROR);
/*
* Could happen if we got an HRR that wasn't requesting a new key_share
*/
- key_share_key = s->s3->tmp.pkey;
+ key_share_key = s->s3.tmp.pkey;
} else {
key_share_key = ssl_generate_pkey_group(s, curve_id);
if (key_share_key == NULL) {
* going to need to be able to save more than one EVP_PKEY. For now
* we reuse the existing tmp.pkey
*/
- s->s3->tmp.pkey = key_share_key;
- s->s3->group_id = curve_id;
+ s->s3.tmp.pkey = key_share_key;
+ s->s3.group_id = curve_id;
OPENSSL_free(encoded_point);
return 1;
err:
- if (s->s3->tmp.pkey == NULL)
+ if (s->s3.tmp.pkey == NULL)
EVP_PKEY_free(key_share_key);
OPENSSL_free(encoded_point);
return 0;
* TODO(TLS1.3): Make the number of key_shares sent configurable. For
* now, just send one
*/
- if (s->s3->group_id != 0) {
- curve_id = s->s3->group_id;
+ if (s->s3.group_id != 0) {
+ curve_id = s->s3.group_id;
} else {
for (i = 0; i < num_groups; i++) {
const EVP_MD *handmd = NULL, *mdres = NULL, *mdpsk = NULL;
int dores = 0;
- s->session->ext.tick_identity = TLSEXT_PSK_BAD_IDENTITY;
+ s->ext.tick_identity = 0;
/*
* Note: At this stage of the code we only support adding a single
agems += s->session->ext.tick_age_add;
reshashsize = EVP_MD_size(mdres);
+ s->ext.tick_identity++;
dores = 1;
}
ERR_R_INTERNAL_ERROR);
return EXT_RETURN_FAIL;
}
+ s->ext.tick_identity++;
}
if (!WPACKET_close(pkt)
return EXT_RETURN_FAIL;
}
- if (dores)
- s->session->ext.tick_identity = 0;
- if (s->psksession != NULL)
- s->psksession->ext.tick_identity = (dores ? 1 : 0);
-
return EXT_RETURN_SENT;
#else
return EXT_RETURN_NOT_SENT;
int tls_parse_stoc_renegotiate(SSL *s, PACKET *pkt, unsigned int context,
X509 *x, size_t chainidx)
{
- size_t expected_len = s->s3->previous_client_finished_len
- + s->s3->previous_server_finished_len;
+ size_t expected_len = s->s3.previous_client_finished_len
+ + s->s3.previous_server_finished_len;
size_t ilen;
const unsigned char *data;
/* Check for logic errors */
if (!ossl_assert(expected_len == 0
- || s->s3->previous_client_finished_len != 0)
+ || s->s3.previous_client_finished_len != 0)
|| !ossl_assert(expected_len == 0
- || s->s3->previous_server_finished_len != 0)) {
+ || s->s3.previous_server_finished_len != 0)) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
ERR_R_INTERNAL_ERROR);
return 0;
return 0;
}
- if (!PACKET_get_bytes(pkt, &data, s->s3->previous_client_finished_len)
- || memcmp(data, s->s3->previous_client_finished,
- s->s3->previous_client_finished_len) != 0) {
+ if (!PACKET_get_bytes(pkt, &data, s->s3.previous_client_finished_len)
+ || memcmp(data, s->s3.previous_client_finished,
+ s->s3.previous_client_finished_len) != 0) {
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
SSL_R_RENEGOTIATION_MISMATCH);
return 0;
}
- if (!PACKET_get_bytes(pkt, &data, s->s3->previous_server_finished_len)
- || memcmp(data, s->s3->previous_server_finished,
- s->s3->previous_server_finished_len) != 0) {
+ if (!PACKET_get_bytes(pkt, &data, s->s3.previous_server_finished_len)
+ || memcmp(data, s->s3.previous_server_finished,
+ s->s3.previous_server_finished_len) != 0) {
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_RENEGOTIATE,
SSL_R_RENEGOTIATION_MISMATCH);
return 0;
}
- s->s3->send_connection_binding = 1;
+ s->s3.send_connection_binding = 1;
return 1;
}
memcpy(s->ext.npn, selected, selected_len);
s->ext.npn_len = selected_len;
- s->s3->npn_seen = 1;
+ s->s3.npn_seen = 1;
return 1;
}
size_t len;
/* We must have requested it. */
- if (!s->s3->alpn_sent) {
+ if (!s->s3.alpn_sent) {
SSLfatal(s, SSL_AD_UNSUPPORTED_EXTENSION, SSL_F_TLS_PARSE_STOC_ALPN,
SSL_R_BAD_EXTENSION);
return 0;
SSL_R_BAD_EXTENSION);
return 0;
}
- OPENSSL_free(s->s3->alpn_selected);
- s->s3->alpn_selected = OPENSSL_malloc(len);
- if (s->s3->alpn_selected == NULL) {
+ OPENSSL_free(s->s3.alpn_selected);
+ s->s3.alpn_selected = OPENSSL_malloc(len);
+ if (s->s3.alpn_selected == NULL) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_ALPN,
ERR_R_INTERNAL_ERROR);
return 0;
}
- if (!PACKET_copy_bytes(pkt, s->s3->alpn_selected, len)) {
+ if (!PACKET_copy_bytes(pkt, s->s3.alpn_selected, len)) {
SSLfatal(s, SSL_AD_DECODE_ERROR, SSL_F_TLS_PARSE_STOC_ALPN,
SSL_R_BAD_EXTENSION);
return 0;
}
- s->s3->alpn_selected_len = len;
+ s->s3.alpn_selected_len = len;
if (s->session->ext.alpn_selected == NULL
|| s->session->ext.alpn_selected_len != len
- || memcmp(s->session->ext.alpn_selected, s->s3->alpn_selected, len)
+ || memcmp(s->session->ext.alpn_selected, s->s3.alpn_selected, len)
!= 0) {
/* ALPN not consistent with the old session so cannot use early_data */
s->ext.early_data_ok = 0;
return 0;
}
s->session->ext.alpn_selected =
- OPENSSL_memdup(s->s3->alpn_selected, s->s3->alpn_selected_len);
+ OPENSSL_memdup(s->s3.alpn_selected, s->s3.alpn_selected_len);
if (s->session->ext.alpn_selected == NULL) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_ALPN,
ERR_R_INTERNAL_ERROR);
return 0;
}
- s->session->ext.alpn_selected_len = s->s3->alpn_selected_len;
+ s->session->ext.alpn_selected_len = s->s3.alpn_selected_len;
}
return 1;
{
/* Ignore if inappropriate ciphersuite */
if (!(s->options & SSL_OP_NO_ENCRYPT_THEN_MAC)
- && s->s3->tmp.new_cipher->algorithm_mac != SSL_AEAD
- && s->s3->tmp.new_cipher->algorithm_enc != SSL_RC4)
+ && s->s3.tmp.new_cipher->algorithm_mac != SSL_AEAD
+ && s->s3.tmp.new_cipher->algorithm_enc != SSL_RC4)
s->ext.use_etm = 1;
return 1;
int tls_parse_stoc_ems(SSL *s, PACKET *pkt, unsigned int context, X509 *x,
size_t chainidx)
{
- s->s3->flags |= TLS1_FLAGS_RECEIVED_EXTMS;
+ if (s->options & SSL_OP_NO_EXTENDED_MASTER_SECRET)
+ return 1;
+ s->s3.flags |= TLS1_FLAGS_RECEIVED_EXTMS;
if (!s->hit)
s->session->flags |= SSL_SESS_FLAG_EXTMS;
#ifndef OPENSSL_NO_TLS1_3
unsigned int group_id;
PACKET encoded_pt;
- EVP_PKEY *ckey = s->s3->tmp.pkey, *skey = NULL;
+ EVP_PKEY *ckey = s->s3.tmp.pkey, *skey = NULL;
/* Sanity check */
- if (ckey == NULL || s->s3->peer_tmp != NULL) {
+ if (ckey == NULL || s->s3.peer_tmp != NULL) {
SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_KEY_SHARE,
ERR_R_INTERNAL_ERROR);
return 0;
* It is an error if the HelloRetryRequest wants a key_share that we
* already sent in the first ClientHello
*/
- if (group_id == s->s3->group_id) {
+ if (group_id == s->s3.group_id) {
SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
SSL_F_TLS_PARSE_STOC_KEY_SHARE, SSL_R_BAD_KEY_SHARE);
return 0;
return 0;
}
- s->s3->group_id = group_id;
- EVP_PKEY_free(s->s3->tmp.pkey);
- s->s3->tmp.pkey = NULL;
+ s->s3.group_id = group_id;
+ EVP_PKEY_free(s->s3.tmp.pkey);
+ s->s3.tmp.pkey = NULL;
return 1;
}
- if (group_id != s->s3->group_id) {
+ if (group_id != s->s3.group_id) {
/*
* This isn't for the group that we sent in the original
* key_share!
EVP_PKEY_free(skey);
return 0;
}
- s->s3->peer_tmp = skey;
+ s->s3.peer_tmp = skey;
#endif
return 1;
}
if (!s->ext.early_data_ok
- || !s->hit
- || s->session->ext.tick_identity != 0) {
+ || !s->hit) {
/*
* If we get here then we didn't send early data, or we didn't resume
* using the first identity, or the SNI/ALPN is not consistent so the
return 0;
}
- if (s->session->ext.tick_identity == (int)identity) {
+ if (identity >= (unsigned int)s->ext.tick_identity) {
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_PSK,
+ SSL_R_BAD_PSK_IDENTITY);
+ return 0;
+ }
+
+ /*
+ * Session resumption tickets are always sent before PSK tickets. If the
+ * ticket index is 0 then it must be for a session resumption ticket if we
+ * sent two tickets, or if we didn't send a PSK ticket.
+ */
+ if (identity == 0 && (s->psksession == NULL || s->ext.tick_identity == 2)) {
s->hit = 1;
SSL_SESSION_free(s->psksession);
s->psksession = NULL;
return 1;
}
- if (s->psksession == NULL
- || s->psksession->ext.tick_identity != (int)identity) {
- SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_PARSE_STOC_PSK,
- SSL_R_BAD_PSK_IDENTITY);
+ if (s->psksession == NULL) {
+ /* Should never happen */
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_PARSE_STOC_PSK,
+ ERR_R_INTERNAL_ERROR);
return 0;
}
s->session = s->psksession;
s->psksession = NULL;
s->hit = 1;
+ /* Early data is only allowed if we used the first ticket */
+ if (identity != 0)
+ s->ext.early_data_ok = 0;
#endif
return 1;