Extended master secret support.
This change implements support for the extended master secret. See https://tools.ietf.org/html/draft-ietf-tls-session-hash-01 https://secure-resumption.com/ Change-Id: Ifc7327763149ab0894b4f1d48cdc35e0f1093b93 Reviewed-on: https://boringssl-review.googlesource.com/1930 Reviewed-by: David Benjamin <davidben@chromium.org> Reviewed-by: Adam Langley <agl@google.com>
This commit is contained in:
parent
89abaea141
commit
7571292eac
@ -222,6 +222,43 @@ static int test_get_asn1(void) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int test_get_optional_asn1_bool(void) {
|
||||
CBS data;
|
||||
int val;
|
||||
|
||||
static const uint8_t kTrue[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0xff};
|
||||
static const uint8_t kFalse[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x00};
|
||||
static const uint8_t kInvalid[] = {0x0a, 3, CBS_ASN1_BOOLEAN, 1, 0x01};
|
||||
|
||||
CBS_init(&data, NULL, 0);
|
||||
val = 2;
|
||||
if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) ||
|
||||
val != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CBS_init(&data, kTrue, sizeof(kTrue));
|
||||
val = 2;
|
||||
if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 0) ||
|
||||
val != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CBS_init(&data, kFalse, sizeof(kFalse));
|
||||
val = 2;
|
||||
if (!CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1) ||
|
||||
val != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
CBS_init(&data, kInvalid, sizeof(kInvalid));
|
||||
if (CBS_get_optional_asn1_bool(&data, &val, 0x0a, 1)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int test_cbb_basic(void) {
|
||||
static const uint8_t kExpected[] = {1, 2, 3, 4, 5, 6, 7, 8};
|
||||
uint8_t *buf;
|
||||
@ -604,7 +641,8 @@ int main(void) {
|
||||
!test_cbb_prefixed() ||
|
||||
!test_cbb_asn1() ||
|
||||
!test_ber_convert() ||
|
||||
!test_asn1_uint64()) {
|
||||
!test_asn1_uint64() ||
|
||||
!test_get_optional_asn1_bool()) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
@ -356,3 +356,33 @@ int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out, unsigned tag,
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
|
||||
int default_value) {
|
||||
CBS child, child2;
|
||||
int present;
|
||||
if (!CBS_get_optional_asn1(cbs, &child, &present, tag)) {
|
||||
return 0;
|
||||
}
|
||||
if (present) {
|
||||
uint8_t boolean;
|
||||
|
||||
if (!CBS_get_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
|
||||
CBS_len(&child2) != 1 ||
|
||||
CBS_len(&child) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
boolean = CBS_data(&child2)[0];
|
||||
if (boolean == 0) {
|
||||
*out = 0;
|
||||
} else if (boolean == 0xff) {
|
||||
*out = 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
*out = default_value;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -193,6 +193,14 @@ OPENSSL_EXPORT int CBS_get_optional_asn1_uint64(CBS *cbs, uint64_t *out,
|
||||
unsigned tag,
|
||||
uint64_t default_value);
|
||||
|
||||
/* CBS_get_optional_asn1_bool gets an optional, explicitly-tagged BOOLEAN from
|
||||
* |cbs|. If present, it sets |*out| to either zero or one, based on the
|
||||
* boolean. Otherwise, it sets |*out| to |default_value|. It returns one on
|
||||
* success, whether or not the element was present, and zero on decode
|
||||
* failure. */
|
||||
OPENSSL_EXPORT int CBS_get_optional_asn1_bool(CBS *cbs, int *out, unsigned tag,
|
||||
int default_value);
|
||||
|
||||
|
||||
/* CRYPTO ByteBuilder.
|
||||
*
|
||||
|
@ -432,6 +432,11 @@ struct ssl_session_st
|
||||
* resumption. */
|
||||
unsigned char original_handshake_hash[EVP_MAX_MD_SIZE];
|
||||
unsigned int original_handshake_hash_len;
|
||||
|
||||
/* extended_master_secret is true if the master secret in this session
|
||||
* was generated using EMS and thus isn't vulnerable to the Triple
|
||||
* Handshake attack. */
|
||||
char extended_master_secret;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -485,6 +485,15 @@ typedef struct ssl3_state_st
|
||||
* this extension to the client. */
|
||||
uint16_t *peer_ellipticcurvelist;
|
||||
size_t peer_ellipticcurvelist_length;
|
||||
|
||||
/* extended_master_secret indicates whether the extended master
|
||||
* secret computation is used in this handshake. Note that this
|
||||
* is different from whether it was used for the current
|
||||
* session. If this is a resumption handshake then EMS might be
|
||||
* negotiated in the client and server hello messages, but it
|
||||
* doesn't matter if the session that's being resumed didn't
|
||||
* use it to create the master secret initially. */
|
||||
char extended_master_secret;
|
||||
} tmp;
|
||||
|
||||
/* Connection binding to prevent renegotiation attacks */
|
||||
|
@ -240,6 +240,9 @@ extern "C" {
|
||||
*/
|
||||
#define TLSEXT_TYPE_padding 21
|
||||
|
||||
/* https://tools.ietf.org/html/draft-ietf-tls-session-hash-01 */
|
||||
#define TLSEXT_TYPE_extended_master_secret 23
|
||||
|
||||
/* ExtensionType value from RFC4507 */
|
||||
#define TLSEXT_TYPE_session_ticket 35
|
||||
|
||||
@ -704,6 +707,8 @@ SSL_CTX_callback_ctrl(ssl,SSL_CTRL_SET_TLSEXT_TICKET_KEY_CB,(void (*)(void))cb)
|
||||
#define TLS_MD_IV_BLOCK_CONST_SIZE 8
|
||||
#define TLS_MD_MASTER_SECRET_CONST "master secret"
|
||||
#define TLS_MD_MASTER_SECRET_CONST_SIZE 13
|
||||
#define TLS_MD_EXTENDED_MASTER_SECRET_CONST "extended master secret"
|
||||
#define TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE 22
|
||||
|
||||
|
||||
/* TLS Session Ticket extension struct */
|
||||
|
@ -229,7 +229,7 @@ dtls1_hm_fragment_free(hm_fragment *frag)
|
||||
}
|
||||
|
||||
/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
|
||||
int dtls1_do_write(SSL *s, int type)
|
||||
int dtls1_do_write(SSL *s, int type, enum should_add_to_finished_hash should_add_to_finished_hash)
|
||||
{
|
||||
int ret;
|
||||
int curr_mtu;
|
||||
@ -365,7 +365,8 @@ int dtls1_do_write(SSL *s, int type)
|
||||
* message got sent. but why would this happen? */
|
||||
assert(len == (unsigned int)ret);
|
||||
|
||||
if (type == SSL3_RT_HANDSHAKE && ! s->d1->retransmitting)
|
||||
if (type == SSL3_RT_HANDSHAKE && !s->d1->retransmitting &&
|
||||
should_add_to_finished_hash == add_to_finished_hash)
|
||||
{
|
||||
/* should not be done for 'Hello Request's, but in that case
|
||||
* we'll ignore the result anyway */
|
||||
@ -967,7 +968,7 @@ int dtls1_send_change_cipher_spec(SSL *s, int a, int b)
|
||||
}
|
||||
|
||||
/* SSL3_ST_CW_CHANGE_B */
|
||||
return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
|
||||
return(dtls1_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC, dont_add_to_finished_hash));
|
||||
}
|
||||
|
||||
int dtls1_read_failed(SSL *s, int code)
|
||||
@ -1181,7 +1182,7 @@ dtls1_retransmit_message(SSL *s, unsigned short seq, unsigned long frag_off,
|
||||
}
|
||||
|
||||
ret = dtls1_do_write(s, frag->msg_header.is_ccs ?
|
||||
SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE);
|
||||
SSL3_RT_CHANGE_CIPHER_SPEC : SSL3_RT_HANDSHAKE, add_to_finished_hash);
|
||||
|
||||
/* restore current state */
|
||||
s->enc_write_ctx = saved_state.enc_write_ctx;
|
||||
|
31
ssl/d1_lib.c
31
ssl/d1_lib.c
@ -74,8 +74,9 @@
|
||||
static void get_current_time(OPENSSL_timeval *t);
|
||||
static OPENSSL_timeval* dtls1_get_timeout(SSL *s, OPENSSL_timeval* timeleft);
|
||||
static void dtls1_set_handshake_header(SSL *s, int type, unsigned long len);
|
||||
static int dtls1_handshake_write(SSL *s);
|
||||
static int dtls1_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash);
|
||||
int dtls1_listen(SSL *s, struct sockaddr *client);
|
||||
static void dtls1_add_to_finished_hash(SSL *s);
|
||||
|
||||
SSL3_ENC_METHOD DTLSv1_enc_data={
|
||||
tls1_enc,
|
||||
@ -93,7 +94,8 @@ SSL3_ENC_METHOD DTLSv1_enc_data={
|
||||
SSL_ENC_FLAG_DTLS|SSL_ENC_FLAG_EXPLICIT_IV,
|
||||
DTLS1_HM_HEADER_LENGTH,
|
||||
dtls1_set_handshake_header,
|
||||
dtls1_handshake_write
|
||||
dtls1_handshake_write,
|
||||
dtls1_add_to_finished_hash,
|
||||
};
|
||||
|
||||
SSL3_ENC_METHOD DTLSv1_2_enc_data={
|
||||
@ -113,7 +115,8 @@ SSL3_ENC_METHOD DTLSv1_2_enc_data={
|
||||
|SSL_ENC_FLAG_SHA256_PRF|SSL_ENC_FLAG_TLS1_2_CIPHERS,
|
||||
DTLS1_HM_HEADER_LENGTH,
|
||||
dtls1_set_handshake_header,
|
||||
dtls1_handshake_write
|
||||
dtls1_handshake_write,
|
||||
dtls1_add_to_finished_hash,
|
||||
};
|
||||
|
||||
int dtls1_new(SSL *s)
|
||||
@ -502,7 +505,25 @@ static void dtls1_set_handshake_header(SSL *s, int htype, unsigned long len)
|
||||
dtls1_buffer_message(s, 0);
|
||||
}
|
||||
|
||||
static int dtls1_handshake_write(SSL *s)
|
||||
static int dtls1_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash)
|
||||
{
|
||||
return dtls1_do_write(s, SSL3_RT_HANDSHAKE);
|
||||
return dtls1_do_write(s, SSL3_RT_HANDSHAKE, should_add_to_finished_hash);
|
||||
}
|
||||
|
||||
static void dtls1_add_to_finished_hash(SSL *s)
|
||||
{
|
||||
uint8_t *record = (uint8_t *) &s->init_buf->data[s->init_off];
|
||||
const struct hm_header_st *msg_hdr = &s->d1->w_msg_hdr;
|
||||
uint8_t serialised_header[DTLS1_HM_HEADER_LENGTH];
|
||||
uint8_t *p = serialised_header;
|
||||
|
||||
/* Construct the message header as if it were a single fragment. */
|
||||
*p++ = msg_hdr->type;
|
||||
l2n3(msg_hdr->msg_len, p);
|
||||
s2n (msg_hdr->seq, p);
|
||||
l2n3(0, p);
|
||||
l2n3(msg_hdr->msg_len, p);
|
||||
ssl3_finish_mac(s, serialised_header, sizeof(serialised_header));
|
||||
ssl3_finish_mac(s, record + DTLS1_HM_HEADER_LENGTH,
|
||||
s->init_num - DTLS1_HM_HEADER_LENGTH);
|
||||
}
|
||||
|
@ -687,5 +687,5 @@ int dtls1_send_hello_verify_request(SSL *s)
|
||||
}
|
||||
|
||||
/* s->state = DTLS1_ST_SW_HELLO_VERIFY_REQUEST_B */
|
||||
return(dtls1_do_write(s,SSL3_RT_HANDSHAKE));
|
||||
return(dtls1_do_write(s,SSL3_RT_HANDSHAKE, add_to_finished_hash));
|
||||
}
|
||||
|
@ -127,17 +127,19 @@
|
||||
#include "ssl_locl.h"
|
||||
|
||||
/* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or SSL3_RT_CHANGE_CIPHER_SPEC) */
|
||||
int ssl3_do_write(SSL *s, int type)
|
||||
int ssl3_do_write(SSL *s, int type, enum should_add_to_finished_hash should_add_to_finished_hash)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret=ssl3_write_bytes(s,type,&s->init_buf->data[s->init_off],
|
||||
s->init_num);
|
||||
if (ret < 0) return(-1);
|
||||
if (type == SSL3_RT_HANDSHAKE)
|
||||
if (type == SSL3_RT_HANDSHAKE && should_add_to_finished_hash == add_to_finished_hash)
|
||||
{
|
||||
/* should not be done for 'Hello Request's, but in that case
|
||||
* we'll ignore the result anyway */
|
||||
ssl3_finish_mac(s,(unsigned char *)&s->init_buf->data[s->init_off],ret);
|
||||
}
|
||||
|
||||
if (ret == s->init_num)
|
||||
{
|
||||
@ -320,7 +322,7 @@ int ssl3_send_change_cipher_spec(SSL *s, int a, int b)
|
||||
}
|
||||
|
||||
/* SSL3_ST_CW_CHANGE_B */
|
||||
return(ssl3_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC));
|
||||
return(ssl3_do_write(s,SSL3_RT_CHANGE_CIPHER_SPEC, dont_add_to_finished_hash));
|
||||
}
|
||||
|
||||
unsigned long ssl3_output_cert_chain(SSL *s, CERT_PKEY *cpk)
|
||||
|
144
ssl/s3_clnt.c
144
ssl/s3_clnt.c
@ -982,7 +982,7 @@ int ssl3_get_server_hello(SSL *s)
|
||||
/* Don't digest cached records if no sigalgs: we may need them for
|
||||
* client authentication.
|
||||
*/
|
||||
if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s))
|
||||
if (!SSL_USE_SIGALGS(s) && !ssl3_digest_cached_records(s, free_handshake_buffer))
|
||||
goto f_err;
|
||||
|
||||
/* Only the NULL compression algorithm is supported. */
|
||||
@ -1637,7 +1637,7 @@ int ssl3_get_certificate_request(SSL *s)
|
||||
*/
|
||||
if (s->s3->handshake_buffer)
|
||||
{
|
||||
if (!ssl3_digest_cached_records(s))
|
||||
if (!ssl3_digest_cached_records(s, free_handshake_buffer))
|
||||
goto err;
|
||||
}
|
||||
return(1);
|
||||
@ -1909,6 +1909,8 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
BN_CTX * bn_ctx = NULL;
|
||||
unsigned int psk_len = 0;
|
||||
unsigned char psk[PSK_MAX_PSK_LEN];
|
||||
uint8_t *pms = NULL;
|
||||
size_t pms_len = 0;
|
||||
|
||||
if (s->state == SSL3_ST_CW_KEY_EXCH_A)
|
||||
{
|
||||
@ -1921,9 +1923,6 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
{
|
||||
char identity[PSK_MAX_IDENTITY_LEN + 1];
|
||||
size_t identity_len;
|
||||
unsigned char *t = NULL;
|
||||
unsigned char pre_ms[PSK_MAX_PSK_LEN*2+4];
|
||||
unsigned int pre_ms_len = 0;
|
||||
int psk_err = 1;
|
||||
|
||||
n = 0;
|
||||
@ -1955,21 +1954,26 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
|
||||
if (!(alg_k & SSL_kEECDH))
|
||||
{
|
||||
uint8_t *t;
|
||||
|
||||
/* Create the shared secret now if we're not using ECDHE-PSK.
|
||||
* TODO(davidben): Refactor this logic similarly
|
||||
* to ssl3_get_client_key_exchange. */
|
||||
pre_ms_len = 2+psk_len+2+psk_len;
|
||||
t = pre_ms;
|
||||
pms_len = 2+psk_len+2+psk_len;
|
||||
pms = OPENSSL_malloc(pms_len);
|
||||
if (pms == NULL)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
|
||||
goto psk_err;
|
||||
}
|
||||
|
||||
t = pms;
|
||||
s2n(psk_len, t);
|
||||
memset(t, 0, psk_len);
|
||||
t+=psk_len;
|
||||
t += psk_len;
|
||||
s2n(psk_len, t);
|
||||
memcpy(t, psk, psk_len);
|
||||
|
||||
s->session->master_key_length =
|
||||
s->method->ssl3_enc->generate_master_secret(s,
|
||||
s->session->master_key,
|
||||
pre_ms, pre_ms_len);
|
||||
s2n(identity_len, p);
|
||||
memcpy(p, identity, identity_len);
|
||||
n = 2 + identity_len;
|
||||
@ -1986,7 +1990,6 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
psk_err = 0;
|
||||
psk_err:
|
||||
OPENSSL_cleanse(identity, sizeof(identity));
|
||||
OPENSSL_cleanse(pre_ms, sizeof(pre_ms));
|
||||
if (psk_err != 0)
|
||||
{
|
||||
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
|
||||
@ -1997,7 +2000,14 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
if (alg_k & SSL_kRSA)
|
||||
{
|
||||
RSA *rsa;
|
||||
unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
|
||||
|
||||
pms_len = SSL_MAX_MASTER_KEY_LENGTH;
|
||||
pms = OPENSSL_malloc(pms_len);
|
||||
if (pms == NULL)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
|
||||
if (s->session->sess_cert == NULL)
|
||||
{
|
||||
@ -2022,19 +2032,19 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
EVP_PKEY_free(pkey);
|
||||
}
|
||||
|
||||
tmp_buf[0]=s->client_version>>8;
|
||||
tmp_buf[1]=s->client_version&0xff;
|
||||
if (RAND_bytes(&(tmp_buf[2]),sizeof tmp_buf-2) <= 0)
|
||||
pms[0]=s->client_version>>8;
|
||||
pms[1]=s->client_version&0xff;
|
||||
if (RAND_bytes(&pms[2],SSL_MAX_MASTER_KEY_LENGTH-2) <= 0)
|
||||
goto err;
|
||||
|
||||
s->session->master_key_length=sizeof tmp_buf;
|
||||
s->session->master_key_length=SSL_MAX_MASTER_KEY_LENGTH;
|
||||
|
||||
q=p;
|
||||
/* Fix buf for TLS and beyond */
|
||||
if (s->version > SSL3_VERSION)
|
||||
p+=2;
|
||||
n=RSA_public_encrypt(sizeof tmp_buf,
|
||||
tmp_buf,p,rsa,RSA_PKCS1_PADDING);
|
||||
n=RSA_public_encrypt(SSL_MAX_MASTER_KEY_LENGTH,
|
||||
pms,p,rsa,RSA_PKCS1_PADDING);
|
||||
if (n <= 0)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_BAD_RSA_ENCRYPT);
|
||||
@ -2043,7 +2053,7 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
|
||||
/* Log the premaster secret, if logging is enabled. */
|
||||
if (!ssl_ctx_log_rsa_client_key_exchange(s->ctx,
|
||||
p, n, tmp_buf, sizeof(tmp_buf)))
|
||||
p, n, pms, SSL_MAX_MASTER_KEY_LENGTH))
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
@ -2054,12 +2064,6 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
s2n(n,q);
|
||||
n+=2;
|
||||
}
|
||||
|
||||
s->session->master_key_length=
|
||||
s->method->ssl3_enc->generate_master_secret(s,
|
||||
s->session->master_key,
|
||||
tmp_buf,sizeof tmp_buf);
|
||||
OPENSSL_cleanse(tmp_buf,sizeof tmp_buf);
|
||||
}
|
||||
else if (alg_k & SSL_kEDH)
|
||||
{
|
||||
@ -2093,23 +2097,23 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* use the 'p' output buffer for the DH key, but
|
||||
* make sure to clear it out afterwards */
|
||||
pms_len = DH_size(dh_clnt);
|
||||
pms = OPENSSL_malloc(pms_len);
|
||||
if (pms == NULL)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
|
||||
DH_free(dh_clnt);
|
||||
goto err;
|
||||
}
|
||||
|
||||
n=DH_compute_key(p,dh_srvr->pub_key,dh_clnt);
|
||||
n=DH_compute_key(pms,dh_srvr->pub_key,dh_clnt);
|
||||
if (n <= 0)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_DH_LIB);
|
||||
DH_free(dh_clnt);
|
||||
goto err;
|
||||
}
|
||||
|
||||
/* generate master key from the result */
|
||||
s->session->master_key_length=
|
||||
s->method->ssl3_enc->generate_master_secret(s,
|
||||
s->session->master_key,p,n);
|
||||
/* clean up */
|
||||
memset(p,0,n);
|
||||
pms_len = n;
|
||||
|
||||
/* send off the data */
|
||||
n=BN_num_bytes(dh_clnt->pub_key);
|
||||
@ -2118,8 +2122,6 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
n+=2;
|
||||
|
||||
DH_free(dh_clnt);
|
||||
|
||||
/* perhaps clean things up a bit EAY EAY EAY EAY*/
|
||||
}
|
||||
|
||||
else if (alg_k & SSL_kEECDH)
|
||||
@ -2127,9 +2129,6 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
const EC_GROUP *srvr_group = NULL;
|
||||
EC_KEY *tkey;
|
||||
int field_size = 0;
|
||||
unsigned char *pre_ms;
|
||||
unsigned char *t;
|
||||
unsigned int pre_ms_len;
|
||||
unsigned int i;
|
||||
|
||||
if (s->session->sess_cert == NULL)
|
||||
@ -2193,32 +2192,35 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
/* ECDHE PSK ciphersuites from RFC 5489 */
|
||||
if ((alg_a & SSL_aPSK) && psk_len != 0)
|
||||
{
|
||||
pre_ms_len = 2+psk_len+2+n;
|
||||
pre_ms = OPENSSL_malloc(pre_ms_len);
|
||||
if (pre_ms == NULL)
|
||||
uint8_t *t;
|
||||
|
||||
pms_len = 2+psk_len+2+n;
|
||||
pms = OPENSSL_malloc(pms_len);
|
||||
if (pms == NULL)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
memset(pre_ms, 0, pre_ms_len);
|
||||
t = pre_ms;
|
||||
|
||||
t = pms;
|
||||
memset(t, 0, pms_len);
|
||||
s2n(psk_len, t);
|
||||
memcpy(t, psk, psk_len);
|
||||
t += psk_len;
|
||||
s2n(n, t);
|
||||
memcpy(t, p, n);
|
||||
s->session->master_key_length = s->method->ssl3_enc \
|
||||
-> generate_master_secret(s,
|
||||
s->session->master_key, pre_ms, pre_ms_len);
|
||||
OPENSSL_cleanse(pre_ms, pre_ms_len);
|
||||
OPENSSL_free(pre_ms);
|
||||
}
|
||||
if (!(alg_a & SSL_aPSK))
|
||||
{
|
||||
/* generate master key from the result */
|
||||
s->session->master_key_length = s->method->ssl3_enc \
|
||||
-> generate_master_secret(s,
|
||||
s->session->master_key, p, n);
|
||||
pms_len = n;
|
||||
pms = OPENSSL_malloc(pms_len);
|
||||
if (pms == NULL)
|
||||
{
|
||||
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
memcpy(pms, p, n);
|
||||
}
|
||||
memset(p, 0, n); /* clean up */
|
||||
|
||||
@ -2283,17 +2285,37 @@ int ssl3_send_client_key_exchange(SSL *s)
|
||||
|
||||
ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n);
|
||||
s->state=SSL3_ST_CW_KEY_EXCH_B;
|
||||
|
||||
/* The message must be added to the finished hash before
|
||||
* calculating the master secret. */
|
||||
s->method->ssl3_enc->add_to_finished_hash(s);
|
||||
|
||||
s->session->master_key_length =
|
||||
s->method->ssl3_enc->generate_master_secret(s,
|
||||
s->session->master_key,
|
||||
pms, pms_len);
|
||||
if (s->session->master_key_length == 0)
|
||||
{
|
||||
goto err;
|
||||
}
|
||||
s->session->extended_master_secret = s->s3->tmp.extended_master_secret;
|
||||
OPENSSL_cleanse(pms, pms_len);
|
||||
OPENSSL_free(pms);
|
||||
}
|
||||
|
||||
/* SSL3_ST_CW_KEY_EXCH_B */
|
||||
return ssl_do_write(s);
|
||||
/* The message has already been added to the finished hash. */
|
||||
return s->method->ssl3_enc->do_write(s, dont_add_to_finished_hash);
|
||||
|
||||
err:
|
||||
BN_CTX_free(bn_ctx);
|
||||
if (encodedPoint != NULL) OPENSSL_free(encodedPoint);
|
||||
if (clnt_ecdh != NULL)
|
||||
EC_KEY_free(clnt_ecdh);
|
||||
EVP_PKEY_free(srvr_pub_pkey);
|
||||
return(-1);
|
||||
if (pms)
|
||||
OPENSSL_free(pms);
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ssl3_send_cert_verify(SSL *s)
|
||||
@ -2332,7 +2354,7 @@ int ssl3_send_cert_verify(SSL *s)
|
||||
goto err;
|
||||
|
||||
/* The handshake buffer is no longer necessary. */
|
||||
if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
|
||||
if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer))
|
||||
goto err;
|
||||
|
||||
/* Sign the digest. */
|
||||
@ -2583,7 +2605,7 @@ int ssl3_send_next_proto(SSL *s)
|
||||
s->init_off = 0;
|
||||
}
|
||||
|
||||
return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
|
||||
return ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash);
|
||||
}
|
||||
|
||||
|
||||
@ -2597,7 +2619,7 @@ int ssl3_send_channel_id(SSL *s)
|
||||
unsigned char *public_key = NULL, *derp, *der_sig = NULL;
|
||||
|
||||
if (s->state != SSL3_ST_CW_CHANNEL_ID_A)
|
||||
return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
|
||||
return ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash);
|
||||
|
||||
if (!s->tlsext_channel_id_private && s->ctx->channel_id_cb)
|
||||
{
|
||||
@ -2700,7 +2722,7 @@ int ssl3_send_channel_id(SSL *s)
|
||||
s->init_num = 4 + 2 + 2 + TLSEXT_CHANNEL_ID_SIZE;
|
||||
s->init_off = 0;
|
||||
|
||||
ret = ssl3_do_write(s, SSL3_RT_HANDSHAKE);
|
||||
ret = ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash);
|
||||
|
||||
err:
|
||||
EVP_MD_CTX_cleanup(&md_ctx);
|
||||
|
14
ssl/s3_enc.c
14
ssl/s3_enc.c
@ -510,7 +510,7 @@ void ssl3_finish_mac(SSL *s, const unsigned char *buf, int len)
|
||||
}
|
||||
}
|
||||
|
||||
int ssl3_digest_cached_records(SSL *s)
|
||||
int ssl3_digest_cached_records(SSL *s, enum should_free_handshake_buffer_t should_free_handshake_buffer)
|
||||
{
|
||||
int i;
|
||||
long mask;
|
||||
@ -542,9 +542,13 @@ int ssl3_digest_cached_records(SSL *s)
|
||||
s->s3->handshake_dgst[i]=NULL;
|
||||
}
|
||||
}
|
||||
/* Free handshake_buffer BIO */
|
||||
BIO_free(s->s3->handshake_buffer);
|
||||
s->s3->handshake_buffer = NULL;
|
||||
|
||||
if (should_free_handshake_buffer == free_handshake_buffer)
|
||||
{
|
||||
/* Free handshake_buffer BIO */
|
||||
BIO_free(s->s3->handshake_buffer);
|
||||
s->s3->handshake_buffer = NULL;
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
@ -581,7 +585,7 @@ static int ssl3_handshake_mac(SSL *s, int md_nid,
|
||||
EVP_MD_CTX ctx,*d=NULL;
|
||||
|
||||
if (s->s3->handshake_buffer)
|
||||
if (!ssl3_digest_cached_records(s))
|
||||
if (!ssl3_digest_cached_records(s, free_handshake_buffer))
|
||||
return 0;
|
||||
|
||||
/* Search for digest of specified type in the handshake_dgst
|
||||
|
12
ssl/s3_lib.c
12
ssl/s3_lib.c
@ -942,7 +942,8 @@ SSL3_ENC_METHOD SSLv3_enc_data={
|
||||
0,
|
||||
SSL3_HM_HEADER_LENGTH,
|
||||
ssl3_set_handshake_header,
|
||||
ssl3_handshake_write
|
||||
ssl3_handshake_write,
|
||||
ssl3_add_to_finished_hash,
|
||||
};
|
||||
|
||||
int ssl3_num_ciphers(void)
|
||||
@ -975,9 +976,14 @@ void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len)
|
||||
s->init_off = 0;
|
||||
}
|
||||
|
||||
int ssl3_handshake_write(SSL *s)
|
||||
int ssl3_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash)
|
||||
{
|
||||
return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
|
||||
return ssl3_do_write(s, SSL3_RT_HANDSHAKE, should_add_to_finished_hash);
|
||||
}
|
||||
|
||||
void ssl3_add_to_finished_hash(SSL *s)
|
||||
{
|
||||
ssl3_finish_mac(s, (uint8_t*) s->init_buf->data, s->init_num);
|
||||
}
|
||||
|
||||
int ssl3_new(SSL *s)
|
||||
|
@ -444,7 +444,7 @@ int ssl3_accept(SSL *s)
|
||||
s->s3->tmp.cert_request=0;
|
||||
s->state=SSL3_ST_SW_SRVR_DONE_A;
|
||||
if (s->s3->handshake_buffer)
|
||||
if (!ssl3_digest_cached_records(s))
|
||||
if (!ssl3_digest_cached_records(s, free_handshake_buffer))
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
@ -1144,7 +1144,7 @@ int ssl3_get_client_hello(SSL *s)
|
||||
|
||||
if (!SSL_USE_SIGALGS(s) || !(s->verify_mode & SSL_VERIFY_PEER))
|
||||
{
|
||||
if (!ssl3_digest_cached_records(s))
|
||||
if (!ssl3_digest_cached_records(s, free_handshake_buffer))
|
||||
goto f_err;
|
||||
}
|
||||
|
||||
@ -2203,6 +2203,9 @@ int ssl3_get_client_key_exchange(SSL *s)
|
||||
s->session->master_key_length = s->method->ssl3_enc
|
||||
->generate_master_secret(s,
|
||||
s->session->master_key, premaster_secret, premaster_secret_len);
|
||||
if (s->session->master_key_length == 0)
|
||||
goto err;
|
||||
s->session->extended_master_secret = s->s3->tmp.extended_master_secret;
|
||||
|
||||
OPENSSL_cleanse(premaster_secret, premaster_secret_len);
|
||||
OPENSSL_free(premaster_secret);
|
||||
@ -2243,7 +2246,7 @@ int ssl3_get_cert_verify(SSL *s)
|
||||
* client certificate. */
|
||||
if (peer == NULL)
|
||||
{
|
||||
if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
|
||||
if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer))
|
||||
return -1;
|
||||
return 1;
|
||||
}
|
||||
@ -2284,7 +2287,7 @@ int ssl3_get_cert_verify(SSL *s)
|
||||
|
||||
/* The handshake buffer is no longer necessary, and we may hash the
|
||||
* current message.*/
|
||||
if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
|
||||
if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer))
|
||||
goto err;
|
||||
ssl3_hash_current_message(s);
|
||||
|
||||
@ -2453,7 +2456,7 @@ int ssl3_get_client_certificate(SSL *s)
|
||||
goto f_err;
|
||||
}
|
||||
/* No client certificate so digest cached records */
|
||||
if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s))
|
||||
if (s->s3->handshake_buffer && !ssl3_digest_cached_records(s, free_handshake_buffer))
|
||||
{
|
||||
al=SSL_AD_INTERNAL_ERROR;
|
||||
goto f_err;
|
||||
|
@ -117,6 +117,7 @@
|
||||
* -- contents of SCT extension
|
||||
* ocspResponse [16] OCTET STRING OPTIONAL,
|
||||
* -- stapled OCSP response from the server
|
||||
* extendedMasterSecret [17] BOOLEAN OPTIONAL,
|
||||
* }
|
||||
*
|
||||
* Note: When the relevant features were #ifdef'd out, support for
|
||||
@ -151,6 +152,8 @@ static const int kSignedCertTimestampListTag =
|
||||
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 15;
|
||||
static const int kOCSPResponseTag =
|
||||
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 16;
|
||||
static const int kExtendedMasterSecretTag =
|
||||
CBS_ASN1_CONSTRUCTED | CBS_ASN1_CONTEXT_SPECIFIC | 17;
|
||||
|
||||
int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp) {
|
||||
CBB cbb, session, child, child2;
|
||||
@ -321,6 +324,15 @@ int i2d_SSL_SESSION(SSL_SESSION *in, uint8_t **pp) {
|
||||
}
|
||||
}
|
||||
|
||||
if (in->extended_master_secret) {
|
||||
if (!CBB_add_asn1(&session, &child, kExtendedMasterSecretTag) ||
|
||||
!CBB_add_asn1(&child, &child2, CBS_ASN1_BOOLEAN) ||
|
||||
!CBB_add_u8(&child2, 0xff)) {
|
||||
OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
}
|
||||
}
|
||||
|
||||
if (!CBB_finish(&cbb, &out, &len)) {
|
||||
OPENSSL_PUT_ERROR(SSL, i2d_SSL_SESSION, ERR_R_MALLOC_FAILURE);
|
||||
goto err;
|
||||
@ -399,7 +411,7 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) {
|
||||
SSL_SESSION *ret = NULL;
|
||||
CBS cbs, session, cipher, session_id, master_key;
|
||||
CBS key_arg, peer, sid_ctx, peer_sha256, original_handshake_hash;
|
||||
int has_key_arg, has_peer, has_peer_sha256;
|
||||
int has_key_arg, has_peer, has_peer_sha256, extended_master_secret;
|
||||
uint64_t version, ssl_version;
|
||||
uint64_t session_time, timeout, verify_result, ticket_lifetime_hint;
|
||||
|
||||
@ -464,6 +476,13 @@ SSL_SESSION *d2i_SSL_SESSION(SSL_SESSION **a, const uint8_t **pp, long length) {
|
||||
kOCSPResponseTag)) {
|
||||
goto err;
|
||||
}
|
||||
if (!CBS_get_optional_asn1_bool(&session, &extended_master_secret,
|
||||
kExtendedMasterSecretTag,
|
||||
0 /* default to false */)) {
|
||||
OPENSSL_PUT_ERROR(SSL, d2i_SSL_SESSION, SSL_R_INVALID_SSL_SESSION);
|
||||
goto err;
|
||||
}
|
||||
ret->extended_master_secret = extended_master_secret;
|
||||
|
||||
/* Ignore |version|. The structure version number is ignored. */
|
||||
|
||||
|
@ -568,6 +568,11 @@ struct tls_sigalgs_st
|
||||
|
||||
#define FP_ICC (int (*)(const void *,const void *))
|
||||
|
||||
enum should_add_to_finished_hash {
|
||||
add_to_finished_hash,
|
||||
dont_add_to_finished_hash,
|
||||
};
|
||||
|
||||
/* This is for the SSLv3/TLSv1.0 differences in crypto/hash stuff
|
||||
* It is a bit of a mess of functions, but hell, think of it as
|
||||
* an opaque structure :-) */
|
||||
@ -597,7 +602,9 @@ typedef struct ssl3_enc_method
|
||||
/* Set the handshake header */
|
||||
void (*set_handshake_header)(SSL *s, int type, unsigned long len);
|
||||
/* Write out handshake message */
|
||||
int (*do_write)(SSL *s);
|
||||
int (*do_write)(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash);
|
||||
/* Add the current handshake message to the finished hash. */
|
||||
void (*add_to_finished_hash)(SSL *s);
|
||||
} SSL3_ENC_METHOD;
|
||||
|
||||
#define SSL_HM_HEADER_LENGTH(s) s->method->ssl3_enc->hhlen
|
||||
@ -605,7 +612,7 @@ typedef struct ssl3_enc_method
|
||||
(((unsigned char *)s->init_buf->data) + s->method->ssl3_enc->hhlen)
|
||||
#define ssl_set_handshake_header(s, htype, len) \
|
||||
s->method->ssl3_enc->set_handshake_header(s, htype, len)
|
||||
#define ssl_do_write(s) s->method->ssl3_enc->do_write(s)
|
||||
#define ssl_do_write(s) s->method->ssl3_enc->do_write(s, add_to_finished_hash)
|
||||
|
||||
/* Values for enc_flags */
|
||||
|
||||
@ -823,7 +830,7 @@ int ssl3_setup_key_block(SSL *s);
|
||||
int ssl3_send_change_cipher_spec(SSL *s,int state_a,int state_b);
|
||||
int ssl3_change_cipher_state(SSL *s,int which);
|
||||
void ssl3_cleanup_key_block(SSL *s);
|
||||
int ssl3_do_write(SSL *s,int type);
|
||||
int ssl3_do_write(SSL *s,int type, enum should_add_to_finished_hash should_add_to_finished_hash);
|
||||
int ssl3_send_alert(SSL *s,int level, int desc);
|
||||
int ssl3_generate_master_secret(SSL *s, unsigned char *out,
|
||||
unsigned char *p, int len);
|
||||
@ -865,7 +872,13 @@ int ssl3_setup_read_buffer(SSL *s);
|
||||
int ssl3_setup_write_buffer(SSL *s);
|
||||
int ssl3_release_read_buffer(SSL *s);
|
||||
int ssl3_release_write_buffer(SSL *s);
|
||||
int ssl3_digest_cached_records(SSL *s);
|
||||
|
||||
enum should_free_handshake_buffer_t {
|
||||
free_handshake_buffer,
|
||||
dont_free_handshake_buffer,
|
||||
};
|
||||
int ssl3_digest_cached_records(SSL *s, enum should_free_handshake_buffer_t);
|
||||
|
||||
int ssl3_new(SSL *s);
|
||||
void ssl3_free(SSL *s);
|
||||
int ssl3_accept(SSL *s);
|
||||
@ -885,13 +898,14 @@ void ssl3_record_sequence_update(unsigned char *seq);
|
||||
int ssl3_do_change_cipher_spec(SSL *ssl);
|
||||
|
||||
void ssl3_set_handshake_header(SSL *s, int htype, unsigned long len);
|
||||
int ssl3_handshake_write(SSL *s);
|
||||
int ssl3_handshake_write(SSL *s, enum should_add_to_finished_hash should_add_to_finished_hash);
|
||||
void ssl3_add_to_finished_hash(SSL *s);
|
||||
|
||||
int ssl23_read(SSL *s, void *buf, int len);
|
||||
int ssl23_peek(SSL *s, void *buf, int len);
|
||||
int ssl23_write(SSL *s, const void *buf, int len);
|
||||
|
||||
int dtls1_do_write(SSL *s,int type);
|
||||
int dtls1_do_write(SSL *s,int type, enum should_add_to_finished_hash should_add_to_finished_hash);
|
||||
int ssl3_read_n(SSL *s, int n, int max, int extend);
|
||||
int dtls1_read_bytes(SSL *s, int type, unsigned char *buf, int len, int peek);
|
||||
int ssl3_write_pending(SSL *s, int type, const unsigned char *buf,
|
||||
|
82
ssl/t1_enc.c
82
ssl/t1_enc.c
@ -152,8 +152,6 @@ static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
|
||||
const void *seed1, int seed1_len,
|
||||
const void *seed2, int seed2_len,
|
||||
const void *seed3, int seed3_len,
|
||||
const void *seed4, int seed4_len,
|
||||
const void *seed5, int seed5_len,
|
||||
unsigned char *out, int olen)
|
||||
{
|
||||
int chunk;
|
||||
@ -182,10 +180,6 @@ static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
|
||||
goto err;
|
||||
if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len))
|
||||
goto err;
|
||||
if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len))
|
||||
goto err;
|
||||
if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len))
|
||||
goto err;
|
||||
A1_len = EVP_MAX_MD_SIZE;
|
||||
if (!EVP_DigestSignFinal(&ctx,A1,&A1_len))
|
||||
goto err;
|
||||
@ -205,10 +199,6 @@ static int tls1_P_hash(const EVP_MD *md, const unsigned char *sec,
|
||||
goto err;
|
||||
if (seed3 && !EVP_DigestSignUpdate(&ctx,seed3,seed3_len))
|
||||
goto err;
|
||||
if (seed4 && !EVP_DigestSignUpdate(&ctx,seed4,seed4_len))
|
||||
goto err;
|
||||
if (seed5 && !EVP_DigestSignUpdate(&ctx,seed5,seed5_len))
|
||||
goto err;
|
||||
|
||||
if (olen > chunk)
|
||||
{
|
||||
@ -246,8 +236,6 @@ static int tls1_PRF(long digest_mask,
|
||||
const void *seed1, int seed1_len,
|
||||
const void *seed2, int seed2_len,
|
||||
const void *seed3, int seed3_len,
|
||||
const void *seed4, int seed4_len,
|
||||
const void *seed5, int seed5_len,
|
||||
const unsigned char *sec, int slen,
|
||||
unsigned char *out1,
|
||||
unsigned char *out2, int olen)
|
||||
@ -275,7 +263,7 @@ static int tls1_PRF(long digest_mask,
|
||||
goto err;
|
||||
}
|
||||
if (!tls1_P_hash(md ,S1,len+(slen&1),
|
||||
seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,seed4,seed4_len,seed5,seed5_len,
|
||||
seed1,seed1_len,seed2,seed2_len,seed3,seed3_len,
|
||||
out2,olen))
|
||||
goto err;
|
||||
S1+=len;
|
||||
@ -298,7 +286,6 @@ static int tls1_generate_key_block(SSL *s, unsigned char *km,
|
||||
TLS_MD_KEY_EXPANSION_CONST,TLS_MD_KEY_EXPANSION_CONST_SIZE,
|
||||
s->s3->server_random,SSL3_RANDOM_SIZE,
|
||||
s->s3->client_random,SSL3_RANDOM_SIZE,
|
||||
NULL,0,NULL,0,
|
||||
s->session->master_key,s->session->master_key_length,
|
||||
km,tmp,num);
|
||||
#ifdef KSSL_DEBUG
|
||||
@ -1011,8 +998,8 @@ int tls1_cert_verify_mac(SSL *s, int md_nid, unsigned char *out)
|
||||
EVP_MD_CTX ctx, *d=NULL;
|
||||
int i;
|
||||
|
||||
if (s->s3->handshake_buffer)
|
||||
if (!ssl3_digest_cached_records(s))
|
||||
if (s->s3->handshake_buffer)
|
||||
if (!ssl3_digest_cached_records(s, free_handshake_buffer))
|
||||
return 0;
|
||||
|
||||
for (i=0;i<SSL_MAX_DIGEST;i++)
|
||||
@ -1093,7 +1080,7 @@ int tls1_final_finish_mac(SSL *s,
|
||||
int digests_len;
|
||||
|
||||
if (s->s3->handshake_buffer)
|
||||
if (!ssl3_digest_cached_records(s))
|
||||
if (!ssl3_digest_cached_records(s, free_handshake_buffer))
|
||||
return 0;
|
||||
|
||||
digests_len = tls1_handshake_digest(s, buf, sizeof(buf));
|
||||
@ -1104,7 +1091,7 @@ int tls1_final_finish_mac(SSL *s,
|
||||
}
|
||||
|
||||
if (!tls1_PRF(ssl_get_algorithm2(s),
|
||||
str,slen, buf, digests_len, NULL,0, NULL,0, NULL,0,
|
||||
str,slen, buf, digests_len, NULL,0,
|
||||
s->session->master_key,s->session->master_key_length,
|
||||
out,buf2,sizeof buf2))
|
||||
err = 1;
|
||||
@ -1212,22 +1199,57 @@ int tls1_generate_master_secret(SSL *s, unsigned char *out, unsigned char *p,
|
||||
int len)
|
||||
{
|
||||
unsigned char buff[SSL_MAX_MASTER_KEY_LENGTH];
|
||||
const void *co = NULL, *so = NULL;
|
||||
int col = 0, sol = 0;
|
||||
|
||||
|
||||
#ifdef KSSL_DEBUG
|
||||
printf ("tls1_generate_master_secret(%p,%p, %p, %d)\n", s,out, p,len);
|
||||
#endif /* KSSL_DEBUG */
|
||||
|
||||
tls1_PRF(ssl_get_algorithm2(s),
|
||||
TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE,
|
||||
s->s3->client_random,SSL3_RANDOM_SIZE,
|
||||
co, col,
|
||||
s->s3->server_random,SSL3_RANDOM_SIZE,
|
||||
so, sol,
|
||||
p,len,
|
||||
s->session->master_key,buff,sizeof buff);
|
||||
if (s->s3->tmp.extended_master_secret)
|
||||
{
|
||||
uint8_t digests[2*EVP_MAX_MD_SIZE];
|
||||
int digests_len;
|
||||
|
||||
if (s->s3->handshake_buffer)
|
||||
{
|
||||
/* The master secret is based on the handshake hash
|
||||
* just after sending the ClientKeyExchange. However,
|
||||
* we might have a client certificate to send, in which
|
||||
* case we might need different hashes for the
|
||||
* verification and thus still need the handshake
|
||||
* buffer around. Keeping both a handshake buffer *and*
|
||||
* running hashes isn't yet supported so, when it comes
|
||||
* to calculating the Finished hash, we'll have to hash
|
||||
* the handshake buffer again. */
|
||||
if (!ssl3_digest_cached_records(s, dont_free_handshake_buffer))
|
||||
return 0;
|
||||
}
|
||||
|
||||
digests_len = tls1_handshake_digest(s, digests, sizeof(digests));
|
||||
|
||||
if (digests_len == -1)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
tls1_PRF(ssl_get_algorithm2(s),
|
||||
TLS_MD_EXTENDED_MASTER_SECRET_CONST,
|
||||
TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE,
|
||||
digests, digests_len,
|
||||
NULL, 0,
|
||||
p, len,
|
||||
s->session->master_key,
|
||||
buff, sizeof(buff));
|
||||
}
|
||||
else
|
||||
{
|
||||
tls1_PRF(ssl_get_algorithm2(s),
|
||||
TLS_MD_MASTER_SECRET_CONST,TLS_MD_MASTER_SECRET_CONST_SIZE,
|
||||
s->s3->client_random,SSL3_RANDOM_SIZE,
|
||||
s->s3->server_random,SSL3_RANDOM_SIZE,
|
||||
p, len,
|
||||
s->session->master_key,buff,sizeof buff);
|
||||
}
|
||||
|
||||
#ifdef SSL_DEBUG
|
||||
fprintf(stderr, "Premaster Secret:\n");
|
||||
BIO_dump_fp(stderr, (char *)p, len);
|
||||
@ -1330,8 +1352,6 @@ int tls1_export_keying_material(SSL *s, unsigned char *out, size_t olen,
|
||||
val, vallen,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
NULL, 0,
|
||||
s->session->master_key,s->session->master_key_length,
|
||||
out,buff,olen);
|
||||
|
||||
|
56
ssl/t1_lib.c
56
ssl/t1_lib.c
@ -140,7 +140,8 @@ SSL3_ENC_METHOD TLSv1_enc_data={
|
||||
0,
|
||||
SSL3_HM_HEADER_LENGTH,
|
||||
ssl3_set_handshake_header,
|
||||
ssl3_handshake_write
|
||||
ssl3_handshake_write,
|
||||
ssl3_add_to_finished_hash,
|
||||
};
|
||||
|
||||
SSL3_ENC_METHOD TLSv1_1_enc_data={
|
||||
@ -159,7 +160,8 @@ SSL3_ENC_METHOD TLSv1_1_enc_data={
|
||||
SSL_ENC_FLAG_EXPLICIT_IV,
|
||||
SSL3_HM_HEADER_LENGTH,
|
||||
ssl3_set_handshake_header,
|
||||
ssl3_handshake_write
|
||||
ssl3_handshake_write,
|
||||
ssl3_add_to_finished_hash,
|
||||
};
|
||||
|
||||
SSL3_ENC_METHOD TLSv1_2_enc_data={
|
||||
@ -179,7 +181,8 @@ SSL3_ENC_METHOD TLSv1_2_enc_data={
|
||||
|SSL_ENC_FLAG_TLS1_2_CIPHERS,
|
||||
SSL3_HM_HEADER_LENGTH,
|
||||
ssl3_set_handshake_header,
|
||||
ssl3_handshake_write
|
||||
ssl3_handshake_write,
|
||||
ssl3_add_to_finished_hash,
|
||||
};
|
||||
|
||||
static int compare_uint16_t(const void *p1, const void *p2)
|
||||
@ -978,6 +981,15 @@ unsigned char *ssl_add_clienthello_tlsext(SSL *s, unsigned char *buf, unsigned c
|
||||
ret += el;
|
||||
}
|
||||
|
||||
/* Add extended master secret. */
|
||||
if (s->version != SSL3_VERSION)
|
||||
{
|
||||
if (limit - ret - 4 < 0)
|
||||
return NULL;
|
||||
s2n(TLSEXT_TYPE_extended_master_secret,ret);
|
||||
s2n(0,ret);
|
||||
}
|
||||
|
||||
if (!(SSL_get_options(s) & SSL_OP_NO_TICKET))
|
||||
{
|
||||
int ticklen;
|
||||
@ -1246,6 +1258,14 @@ unsigned char *ssl_add_serverhello_tlsext(SSL *s, unsigned char *buf, unsigned c
|
||||
ret += el;
|
||||
}
|
||||
|
||||
if (s->s3->tmp.extended_master_secret)
|
||||
{
|
||||
if ((long)(limit - ret - 4) < 0) return NULL;
|
||||
|
||||
s2n(TLSEXT_TYPE_extended_master_secret,ret);
|
||||
s2n(0,ret);
|
||||
}
|
||||
|
||||
if (using_ecc)
|
||||
{
|
||||
const unsigned char *plist;
|
||||
@ -1423,6 +1443,7 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert)
|
||||
s->should_ack_sni = 0;
|
||||
s->s3->next_proto_neg_seen = 0;
|
||||
s->s3->tmp.certificate_status_expected = 0;
|
||||
s->s3->tmp.extended_master_secret = 0;
|
||||
|
||||
if (s->s3->alpn_selected)
|
||||
{
|
||||
@ -1782,6 +1803,18 @@ static int ssl_scan_clienthello_tlsext(SSL *s, CBS *cbs, int *out_alert)
|
||||
if (!ssl_parse_clienthello_use_srtp_ext(s, &extension, out_alert))
|
||||
return 0;
|
||||
}
|
||||
|
||||
else if (type == TLSEXT_TYPE_extended_master_secret &&
|
||||
s->version != SSL3_VERSION)
|
||||
{
|
||||
if (CBS_len(&extension) != 0)
|
||||
{
|
||||
*out_alert = SSL_AD_DECODE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->s3->tmp.extended_master_secret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
ri_check:
|
||||
@ -1851,6 +1884,7 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert)
|
||||
|
||||
s->tlsext_ticket_expected = 0;
|
||||
s->s3->tmp.certificate_status_expected = 0;
|
||||
s->s3->tmp.extended_master_secret = 0;
|
||||
|
||||
if (s->s3->alpn_selected)
|
||||
{
|
||||
@ -2086,6 +2120,20 @@ static int ssl_scan_serverhello_tlsext(SSL *s, CBS *cbs, int *out_alert)
|
||||
if (!ssl_parse_serverhello_use_srtp_ext(s, &extension, out_alert))
|
||||
return 0;
|
||||
}
|
||||
|
||||
else if (type == TLSEXT_TYPE_extended_master_secret)
|
||||
{
|
||||
if (/* It is invalid for the server to select EMS and
|
||||
SSLv3. */
|
||||
s->version == SSL3_VERSION ||
|
||||
CBS_len(&extension) != 0)
|
||||
{
|
||||
*out_alert = SSL_AD_DECODE_ERROR;
|
||||
return 0;
|
||||
}
|
||||
|
||||
s->s3->tmp.extended_master_secret = 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (!s->hit && tlsext_servername == 1)
|
||||
@ -2779,7 +2827,7 @@ tls1_channel_id_hash(EVP_MD_CTX *md, SSL *s)
|
||||
static const char kClientIDMagic[] = "TLS Channel ID signature";
|
||||
|
||||
if (s->s3->handshake_buffer)
|
||||
if (!ssl3_digest_cached_records(s))
|
||||
if (!ssl3_digest_cached_records(s, free_handshake_buffer))
|
||||
return 0;
|
||||
|
||||
EVP_DigestUpdate(md, kClientIDMagic, sizeof(kClientIDMagic));
|
||||
|
@ -482,6 +482,13 @@ static int do_exchange(SSL_SESSION **out_session,
|
||||
}
|
||||
}
|
||||
|
||||
if (config->expect_extended_master_secret) {
|
||||
if (!ssl->session->extended_master_secret) {
|
||||
fprintf(stderr, "No EMS for session when expected");
|
||||
return 2;
|
||||
}
|
||||
}
|
||||
|
||||
if (config->write_different_record_sizes) {
|
||||
if (config->is_dtls) {
|
||||
fprintf(stderr, "write_different_record_sizes not supported for DTLS\n");
|
||||
|
@ -71,16 +71,17 @@ const (
|
||||
|
||||
// TLS extension numbers
|
||||
const (
|
||||
extensionServerName uint16 = 0
|
||||
extensionStatusRequest uint16 = 5
|
||||
extensionSupportedCurves uint16 = 10
|
||||
extensionSupportedPoints uint16 = 11
|
||||
extensionSignatureAlgorithms uint16 = 13
|
||||
extensionALPN uint16 = 16
|
||||
extensionSessionTicket uint16 = 35
|
||||
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
|
||||
extensionRenegotiationInfo uint16 = 0xff01
|
||||
extensionChannelID uint16 = 30032 // not IANA assigned
|
||||
extensionServerName uint16 = 0
|
||||
extensionStatusRequest uint16 = 5
|
||||
extensionSupportedCurves uint16 = 10
|
||||
extensionSupportedPoints uint16 = 11
|
||||
extensionSignatureAlgorithms uint16 = 13
|
||||
extensionALPN uint16 = 16
|
||||
extensionExtendedMasterSecret uint16 = 23
|
||||
extensionSessionTicket uint16 = 35
|
||||
extensionNextProtoNeg uint16 = 13172 // not IANA assigned
|
||||
extensionRenegotiationInfo uint16 = 0xff01
|
||||
extensionChannelID uint16 = 30032 // not IANA assigned
|
||||
)
|
||||
|
||||
// TLS signaling cipher suite values
|
||||
@ -189,12 +190,13 @@ const (
|
||||
// ClientSessionState contains the state needed by clients to resume TLS
|
||||
// sessions.
|
||||
type ClientSessionState struct {
|
||||
sessionTicket []uint8 // Encrypted ticket used for session resumption with server
|
||||
vers uint16 // SSL/TLS version negotiated for the session
|
||||
cipherSuite uint16 // Ciphersuite negotiated for the session
|
||||
masterSecret []byte // MasterSecret generated by client on a full handshake
|
||||
handshakeHash []byte // Handshake hash for Channel ID purposes.
|
||||
serverCertificates []*x509.Certificate // Certificate chain presented by the server
|
||||
sessionTicket []uint8 // Encrypted ticket used for session resumption with server
|
||||
vers uint16 // SSL/TLS version negotiated for the session
|
||||
cipherSuite uint16 // Ciphersuite negotiated for the session
|
||||
masterSecret []byte // MasterSecret generated by client on a full handshake
|
||||
handshakeHash []byte // Handshake hash for Channel ID purposes.
|
||||
serverCertificates []*x509.Certificate // Certificate chain presented by the server
|
||||
extendedMasterSecret bool // Whether an extended master secret was used to generate the session
|
||||
}
|
||||
|
||||
// ClientSessionCache is a cache of ClientSessionState objects that can be used
|
||||
@ -472,6 +474,14 @@ type ProtocolBugs struct {
|
||||
// OversizedSessionId causes the session id that is sent with a ticket
|
||||
// resumption attempt to be too large (33 bytes).
|
||||
OversizedSessionId bool
|
||||
|
||||
// RequireExtendedMasterSecret, if true, requires that the peer support
|
||||
// the extended master secret option.
|
||||
RequireExtendedMasterSecret bool
|
||||
|
||||
// NoExtendedMasterSecret causes the client and server to behave is if
|
||||
// they didn't support an extended master secret.
|
||||
NoExtendedMasterSecret bool
|
||||
}
|
||||
|
||||
func (c *Config) serverInit() {
|
||||
|
@ -29,16 +29,17 @@ type Conn struct {
|
||||
isClient bool
|
||||
|
||||
// constant after handshake; protected by handshakeMutex
|
||||
handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
|
||||
handshakeErr error // error resulting from handshake
|
||||
vers uint16 // TLS version
|
||||
haveVers bool // version has been negotiated
|
||||
config *Config // configuration passed to constructor
|
||||
handshakeComplete bool
|
||||
didResume bool // whether this connection was a session resumption
|
||||
cipherSuite uint16
|
||||
ocspResponse []byte // stapled OCSP response
|
||||
peerCertificates []*x509.Certificate
|
||||
handshakeMutex sync.Mutex // handshakeMutex < in.Mutex, out.Mutex, errMutex
|
||||
handshakeErr error // error resulting from handshake
|
||||
vers uint16 // TLS version
|
||||
haveVers bool // version has been negotiated
|
||||
config *Config // configuration passed to constructor
|
||||
handshakeComplete bool
|
||||
didResume bool // whether this connection was a session resumption
|
||||
extendedMasterSecret bool // whether this session used an extended master secret
|
||||
cipherSuite uint16
|
||||
ocspResponse []byte // stapled OCSP response
|
||||
peerCertificates []*x509.Certificate
|
||||
// verifiedChains contains the certificate chains that we built, as
|
||||
// opposed to the ones presented by the server.
|
||||
verifiedChains [][]*x509.Certificate
|
||||
|
@ -56,26 +56,31 @@ func (c *Conn) clientHandshake() error {
|
||||
}
|
||||
|
||||
hello := &clientHelloMsg{
|
||||
isDTLS: c.isDTLS,
|
||||
vers: c.config.maxVersion(),
|
||||
compressionMethods: []uint8{compressionNone},
|
||||
random: make([]byte, 32),
|
||||
ocspStapling: true,
|
||||
serverName: c.config.ServerName,
|
||||
supportedCurves: c.config.curvePreferences(),
|
||||
supportedPoints: []uint8{pointFormatUncompressed},
|
||||
nextProtoNeg: len(c.config.NextProtos) > 0,
|
||||
secureRenegotiation: true,
|
||||
alpnProtocols: c.config.NextProtos,
|
||||
duplicateExtension: c.config.Bugs.DuplicateExtension,
|
||||
channelIDSupported: c.config.ChannelID != nil,
|
||||
npnLast: c.config.Bugs.SwapNPNAndALPN,
|
||||
isDTLS: c.isDTLS,
|
||||
vers: c.config.maxVersion(),
|
||||
compressionMethods: []uint8{compressionNone},
|
||||
random: make([]byte, 32),
|
||||
ocspStapling: true,
|
||||
serverName: c.config.ServerName,
|
||||
supportedCurves: c.config.curvePreferences(),
|
||||
supportedPoints: []uint8{pointFormatUncompressed},
|
||||
nextProtoNeg: len(c.config.NextProtos) > 0,
|
||||
secureRenegotiation: true,
|
||||
alpnProtocols: c.config.NextProtos,
|
||||
duplicateExtension: c.config.Bugs.DuplicateExtension,
|
||||
channelIDSupported: c.config.ChannelID != nil,
|
||||
npnLast: c.config.Bugs.SwapNPNAndALPN,
|
||||
extendedMasterSecret: c.config.maxVersion() >= VersionTLS10,
|
||||
}
|
||||
|
||||
if c.config.Bugs.SendClientVersion != 0 {
|
||||
hello.vers = c.config.Bugs.SendClientVersion
|
||||
}
|
||||
|
||||
if c.config.Bugs.NoExtendedMasterSecret {
|
||||
hello.extendedMasterSecret = false
|
||||
}
|
||||
|
||||
possibleCipherSuites := c.config.cipherSuites()
|
||||
hello.cipherSuites = make([]uint16, 0, len(possibleCipherSuites))
|
||||
|
||||
@ -503,7 +508,15 @@ func (hs *clientHandshakeState) doFullHandshake() error {
|
||||
c.writeRecord(recordTypeHandshake, ckx.marshal())
|
||||
}
|
||||
|
||||
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
|
||||
if hs.serverHello.extendedMasterSecret && c.vers >= VersionTLS10 {
|
||||
hs.masterSecret = extendedMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.finishedHash)
|
||||
c.extendedMasterSecret = true
|
||||
} else {
|
||||
if c.config.Bugs.RequireExtendedMasterSecret {
|
||||
return errors.New("tls: extended master secret required but not supported by peer")
|
||||
}
|
||||
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
|
||||
}
|
||||
|
||||
if chainToSend != nil {
|
||||
var signed []byte
|
||||
@ -629,6 +642,7 @@ func (hs *clientHandshakeState) processServerHello() (bool, error) {
|
||||
// Restore masterSecret and peerCerts from previous state
|
||||
hs.masterSecret = hs.session.masterSecret
|
||||
c.peerCertificates = hs.session.serverCertificates
|
||||
c.extendedMasterSecret = hs.session.extendedMasterSecret
|
||||
hs.finishedHash.discardHandshakeBuffer()
|
||||
return true, nil
|
||||
}
|
||||
|
@ -7,27 +7,28 @@ package main
|
||||
import "bytes"
|
||||
|
||||
type clientHelloMsg struct {
|
||||
raw []byte
|
||||
isDTLS bool
|
||||
vers uint16
|
||||
random []byte
|
||||
sessionId []byte
|
||||
cookie []byte
|
||||
cipherSuites []uint16
|
||||
compressionMethods []uint8
|
||||
nextProtoNeg bool
|
||||
serverName string
|
||||
ocspStapling bool
|
||||
supportedCurves []CurveID
|
||||
supportedPoints []uint8
|
||||
ticketSupported bool
|
||||
sessionTicket []uint8
|
||||
signatureAndHashes []signatureAndHash
|
||||
secureRenegotiation bool
|
||||
alpnProtocols []string
|
||||
duplicateExtension bool
|
||||
channelIDSupported bool
|
||||
npnLast bool
|
||||
raw []byte
|
||||
isDTLS bool
|
||||
vers uint16
|
||||
random []byte
|
||||
sessionId []byte
|
||||
cookie []byte
|
||||
cipherSuites []uint16
|
||||
compressionMethods []uint8
|
||||
nextProtoNeg bool
|
||||
serverName string
|
||||
ocspStapling bool
|
||||
supportedCurves []CurveID
|
||||
supportedPoints []uint8
|
||||
ticketSupported bool
|
||||
sessionTicket []uint8
|
||||
signatureAndHashes []signatureAndHash
|
||||
secureRenegotiation bool
|
||||
alpnProtocols []string
|
||||
duplicateExtension bool
|
||||
channelIDSupported bool
|
||||
npnLast bool
|
||||
extendedMasterSecret bool
|
||||
}
|
||||
|
||||
func (m *clientHelloMsg) equal(i interface{}) bool {
|
||||
@ -56,7 +57,8 @@ func (m *clientHelloMsg) equal(i interface{}) bool {
|
||||
eqStrings(m.alpnProtocols, m1.alpnProtocols) &&
|
||||
m.duplicateExtension == m1.duplicateExtension &&
|
||||
m.channelIDSupported == m1.channelIDSupported &&
|
||||
m.npnLast == m1.npnLast
|
||||
m.npnLast == m1.npnLast &&
|
||||
m.extendedMasterSecret == m1.extendedMasterSecret
|
||||
}
|
||||
|
||||
func (m *clientHelloMsg) marshal() []byte {
|
||||
@ -118,6 +120,9 @@ func (m *clientHelloMsg) marshal() []byte {
|
||||
}
|
||||
numExtensions++
|
||||
}
|
||||
if m.extendedMasterSecret {
|
||||
numExtensions++
|
||||
}
|
||||
if numExtensions > 0 {
|
||||
extensionsLength += 4 * numExtensions
|
||||
length += 2 + extensionsLength
|
||||
@ -319,6 +324,12 @@ func (m *clientHelloMsg) marshal() []byte {
|
||||
z[1] = 0xff
|
||||
z = z[4:]
|
||||
}
|
||||
if m.extendedMasterSecret {
|
||||
// https://tools.ietf.org/html/draft-ietf-tls-session-hash-01
|
||||
z[0] = byte(extensionExtendedMasterSecret >> 8)
|
||||
z[1] = byte(extensionExtendedMasterSecret & 0xff)
|
||||
z = z[4:]
|
||||
}
|
||||
|
||||
m.raw = x
|
||||
|
||||
@ -385,6 +396,7 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
|
||||
m.sessionTicket = nil
|
||||
m.signatureAndHashes = nil
|
||||
m.alpnProtocols = nil
|
||||
m.extendedMasterSecret = false
|
||||
|
||||
if len(data) == 0 {
|
||||
// ClientHello is optionally followed by extension data
|
||||
@ -517,6 +529,11 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
|
||||
return false
|
||||
}
|
||||
m.channelIDSupported = true
|
||||
case extensionExtendedMasterSecret:
|
||||
if length != 0 {
|
||||
return false
|
||||
}
|
||||
m.extendedMasterSecret = true
|
||||
}
|
||||
data = data[length:]
|
||||
}
|
||||
@ -525,21 +542,22 @@ func (m *clientHelloMsg) unmarshal(data []byte) bool {
|
||||
}
|
||||
|
||||
type serverHelloMsg struct {
|
||||
raw []byte
|
||||
isDTLS bool
|
||||
vers uint16
|
||||
random []byte
|
||||
sessionId []byte
|
||||
cipherSuite uint16
|
||||
compressionMethod uint8
|
||||
nextProtoNeg bool
|
||||
nextProtos []string
|
||||
ocspStapling bool
|
||||
ticketSupported bool
|
||||
secureRenegotiation bool
|
||||
alpnProtocol string
|
||||
duplicateExtension bool
|
||||
channelIDRequested bool
|
||||
raw []byte
|
||||
isDTLS bool
|
||||
vers uint16
|
||||
random []byte
|
||||
sessionId []byte
|
||||
cipherSuite uint16
|
||||
compressionMethod uint8
|
||||
nextProtoNeg bool
|
||||
nextProtos []string
|
||||
ocspStapling bool
|
||||
ticketSupported bool
|
||||
secureRenegotiation bool
|
||||
alpnProtocol string
|
||||
duplicateExtension bool
|
||||
channelIDRequested bool
|
||||
extendedMasterSecret bool
|
||||
}
|
||||
|
||||
func (m *serverHelloMsg) equal(i interface{}) bool {
|
||||
@ -562,7 +580,8 @@ func (m *serverHelloMsg) equal(i interface{}) bool {
|
||||
m.secureRenegotiation == m1.secureRenegotiation &&
|
||||
m.alpnProtocol == m1.alpnProtocol &&
|
||||
m.duplicateExtension == m1.duplicateExtension &&
|
||||
m.channelIDRequested == m1.channelIDRequested
|
||||
m.channelIDRequested == m1.channelIDRequested &&
|
||||
m.extendedMasterSecret == m1.extendedMasterSecret
|
||||
}
|
||||
|
||||
func (m *serverHelloMsg) marshal() []byte {
|
||||
@ -606,6 +625,9 @@ func (m *serverHelloMsg) marshal() []byte {
|
||||
extensionsLength += 2 + 1 + alpnLen
|
||||
numExtensions++
|
||||
}
|
||||
if m.extendedMasterSecret {
|
||||
numExtensions++
|
||||
}
|
||||
|
||||
if numExtensions > 0 {
|
||||
extensionsLength += 4 * numExtensions
|
||||
@ -699,6 +721,11 @@ func (m *serverHelloMsg) marshal() []byte {
|
||||
z[1] = 0xff
|
||||
z = z[4:]
|
||||
}
|
||||
if m.extendedMasterSecret {
|
||||
z[0] = byte(extensionExtendedMasterSecret >> 8)
|
||||
z[1] = byte(extensionExtendedMasterSecret & 0xff)
|
||||
z = z[4:]
|
||||
}
|
||||
|
||||
m.raw = x
|
||||
|
||||
@ -730,6 +757,7 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
|
||||
m.ocspStapling = false
|
||||
m.ticketSupported = false
|
||||
m.alpnProtocol = ""
|
||||
m.extendedMasterSecret = false
|
||||
|
||||
if len(data) == 0 {
|
||||
// ServerHello is optionally followed by extension data
|
||||
@ -805,6 +833,11 @@ func (m *serverHelloMsg) unmarshal(data []byte) bool {
|
||||
return false
|
||||
}
|
||||
m.channelIDRequested = true
|
||||
case extensionExtendedMasterSecret:
|
||||
if length != 0 {
|
||||
return false
|
||||
}
|
||||
m.extendedMasterSecret = true
|
||||
}
|
||||
data = data[length:]
|
||||
}
|
||||
|
@ -237,6 +237,7 @@ Curves:
|
||||
hs.hello.nextProtos = config.NextProtos
|
||||
}
|
||||
}
|
||||
hs.hello.extendedMasterSecret = c.vers >= VersionTLS10 && hs.clientHello.extendedMasterSecret && !c.config.Bugs.NoExtendedMasterSecret
|
||||
|
||||
if len(config.Certificates) == 0 {
|
||||
c.sendAlert(alertInternalError)
|
||||
@ -373,6 +374,7 @@ func (hs *serverHandshakeState) doResumeHandshake() error {
|
||||
}
|
||||
|
||||
hs.masterSecret = hs.sessionState.masterSecret
|
||||
c.extendedMasterSecret = hs.sessionState.extendedMasterSecret
|
||||
|
||||
return nil
|
||||
}
|
||||
@ -387,6 +389,7 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
|
||||
hs.hello.ticketSupported = hs.clientHello.ticketSupported && !config.SessionTicketsDisabled
|
||||
hs.hello.cipherSuite = hs.suite.id
|
||||
c.extendedMasterSecret = hs.hello.extendedMasterSecret
|
||||
|
||||
hs.finishedHash = newFinishedHash(c.vers, hs.suite)
|
||||
hs.writeClientHash(hs.clientHello.marshal())
|
||||
@ -502,7 +505,14 @@ func (hs *serverHandshakeState) doFullHandshake() error {
|
||||
c.sendAlert(alertHandshakeFailure)
|
||||
return err
|
||||
}
|
||||
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
|
||||
if c.extendedMasterSecret {
|
||||
hs.masterSecret = extendedMasterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.finishedHash)
|
||||
} else {
|
||||
if c.config.Bugs.RequireExtendedMasterSecret {
|
||||
return errors.New("tls: extended master secret required but not supported by peer")
|
||||
}
|
||||
hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
|
||||
}
|
||||
|
||||
// If we received a client cert in response to our certificate request message,
|
||||
// the client will send us a certificateVerifyMsg immediately after the
|
||||
|
@ -117,6 +117,7 @@ const (
|
||||
)
|
||||
|
||||
var masterSecretLabel = []byte("master secret")
|
||||
var extendedMasterSecretLabel = []byte("extended master secret")
|
||||
var keyExpansionLabel = []byte("key expansion")
|
||||
var clientFinishedLabel = []byte("client finished")
|
||||
var serverFinishedLabel = []byte("server finished")
|
||||
@ -150,6 +151,15 @@ func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecr
|
||||
return masterSecret
|
||||
}
|
||||
|
||||
// extendedMasterFromPreMasterSecret generates the master secret from the
|
||||
// pre-master secret when the Triple Handshake fix is in effect. See
|
||||
// https://tools.ietf.org/html/draft-ietf-tls-session-hash-01
|
||||
func extendedMasterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret []byte, h finishedHash) []byte {
|
||||
masterSecret := make([]byte, masterSecretLength)
|
||||
prfForVersion(version, suite)(masterSecret, preMasterSecret, extendedMasterSecretLabel, h.Sum())
|
||||
return masterSecret
|
||||
}
|
||||
|
||||
// keysFromMasterSecret generates the connection keys from the master
|
||||
// secret, given the lengths of the MAC key, cipher key and IV, as defined in
|
||||
// RFC 2246, section 6.3.
|
||||
@ -221,6 +231,16 @@ func (h *finishedHash) Write(msg []byte) (n int, err error) {
|
||||
return len(msg), nil
|
||||
}
|
||||
|
||||
func (h finishedHash) Sum() []byte {
|
||||
if h.version >= VersionTLS12 {
|
||||
return h.client.Sum(nil)
|
||||
}
|
||||
|
||||
out := make([]byte, 0, md5.Size+sha1.Size)
|
||||
out = h.clientMD5.Sum(out)
|
||||
return h.client.Sum(out)
|
||||
}
|
||||
|
||||
// finishedSum30 calculates the contents of the verify_data member of a SSLv3
|
||||
// Finished message given the MD5 and SHA1 hashes of a set of handshake
|
||||
// messages.
|
||||
@ -264,15 +284,7 @@ func (h finishedHash) clientSum(masterSecret []byte) []byte {
|
||||
}
|
||||
|
||||
out := make([]byte, finishedVerifyLength)
|
||||
if h.version >= VersionTLS12 {
|
||||
seed := h.client.Sum(nil)
|
||||
h.prf(out, masterSecret, clientFinishedLabel, seed)
|
||||
} else {
|
||||
seed := make([]byte, 0, md5.Size+sha1.Size)
|
||||
seed = h.clientMD5.Sum(seed)
|
||||
seed = h.client.Sum(seed)
|
||||
h.prf(out, masterSecret, clientFinishedLabel, seed)
|
||||
}
|
||||
h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
|
||||
return out
|
||||
}
|
||||
|
||||
@ -284,15 +296,7 @@ func (h finishedHash) serverSum(masterSecret []byte) []byte {
|
||||
}
|
||||
|
||||
out := make([]byte, finishedVerifyLength)
|
||||
if h.version >= VersionTLS12 {
|
||||
seed := h.server.Sum(nil)
|
||||
h.prf(out, masterSecret, serverFinishedLabel, seed)
|
||||
} else {
|
||||
seed := make([]byte, 0, md5.Size+sha1.Size)
|
||||
seed = h.serverMD5.Sum(seed)
|
||||
seed = h.server.Sum(seed)
|
||||
h.prf(out, masterSecret, serverFinishedLabel, seed)
|
||||
}
|
||||
h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
|
||||
return out
|
||||
}
|
||||
|
||||
@ -334,14 +338,10 @@ func (h finishedHash) hashForClientCertificate(signatureAndHash signatureAndHash
|
||||
return digest[:], crypto.SHA256, nil
|
||||
}
|
||||
if signatureAndHash.signature == signatureECDSA {
|
||||
digest := h.server.Sum(nil)
|
||||
return digest, crypto.SHA1, nil
|
||||
return h.server.Sum(nil), crypto.SHA1, nil
|
||||
}
|
||||
|
||||
digest := make([]byte, 0, 36)
|
||||
digest = h.serverMD5.Sum(digest)
|
||||
digest = h.server.Sum(digest)
|
||||
return digest, crypto.MD5SHA1, nil
|
||||
return h.Sum(), crypto.MD5SHA1, nil
|
||||
}
|
||||
|
||||
// hashForChannelID returns the hash to be signed for TLS Channel
|
||||
|
130
ssl/test/runner/recordingconn.go
Normal file
130
ssl/test/runner/recordingconn.go
Normal file
@ -0,0 +1,130 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
)
|
||||
|
||||
// recordingConn is a net.Conn that records the traffic that passes through it.
|
||||
// WriteTo can be used to produce output that can be later be loaded with
|
||||
// ParseTestData.
|
||||
type recordingConn struct {
|
||||
net.Conn
|
||||
sync.Mutex
|
||||
flows [][]byte
|
||||
reading bool
|
||||
}
|
||||
|
||||
func (r *recordingConn) Read(b []byte) (n int, err error) {
|
||||
if n, err = r.Conn.Read(b); n == 0 {
|
||||
return
|
||||
}
|
||||
b = b[:n]
|
||||
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if l := len(r.flows); l == 0 || !r.reading {
|
||||
buf := make([]byte, len(b))
|
||||
copy(buf, b)
|
||||
r.flows = append(r.flows, buf)
|
||||
} else {
|
||||
r.flows[l-1] = append(r.flows[l-1], b[:n]...)
|
||||
}
|
||||
r.reading = true
|
||||
return
|
||||
}
|
||||
|
||||
func (r *recordingConn) Write(b []byte) (n int, err error) {
|
||||
if n, err = r.Conn.Write(b); n == 0 {
|
||||
return
|
||||
}
|
||||
b = b[:n]
|
||||
|
||||
r.Lock()
|
||||
defer r.Unlock()
|
||||
|
||||
if l := len(r.flows); l == 0 || r.reading {
|
||||
buf := make([]byte, len(b))
|
||||
copy(buf, b)
|
||||
r.flows = append(r.flows, buf)
|
||||
} else {
|
||||
r.flows[l-1] = append(r.flows[l-1], b[:n]...)
|
||||
}
|
||||
r.reading = false
|
||||
return
|
||||
}
|
||||
|
||||
// WriteTo writes hex dumps to w that contains the recorded traffic.
|
||||
func (r *recordingConn) WriteTo(w io.Writer) {
|
||||
// TLS always starts with a client to server flow.
|
||||
clientToServer := true
|
||||
|
||||
for i, flow := range r.flows {
|
||||
source, dest := "client", "server"
|
||||
if !clientToServer {
|
||||
source, dest = dest, source
|
||||
}
|
||||
fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest)
|
||||
dumper := hex.Dumper(w)
|
||||
dumper.Write(flow)
|
||||
dumper.Close()
|
||||
clientToServer = !clientToServer
|
||||
}
|
||||
}
|
||||
|
||||
func parseTestData(r io.Reader) (flows [][]byte, err error) {
|
||||
var currentFlow []byte
|
||||
|
||||
scanner := bufio.NewScanner(r)
|
||||
for scanner.Scan() {
|
||||
line := scanner.Text()
|
||||
// If the line starts with ">>> " then it marks the beginning
|
||||
// of a new flow.
|
||||
if strings.HasPrefix(line, ">>> ") {
|
||||
if len(currentFlow) > 0 || len(flows) > 0 {
|
||||
flows = append(flows, currentFlow)
|
||||
currentFlow = nil
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
// Otherwise the line is a line of hex dump that looks like:
|
||||
// 00000170 fc f5 06 bf (...) |.....X{&?......!|
|
||||
// (Some bytes have been omitted from the middle section.)
|
||||
|
||||
if i := strings.IndexByte(line, ' '); i >= 0 {
|
||||
line = line[i:]
|
||||
} else {
|
||||
return nil, errors.New("invalid test data")
|
||||
}
|
||||
|
||||
if i := strings.IndexByte(line, '|'); i >= 0 {
|
||||
line = line[:i]
|
||||
} else {
|
||||
return nil, errors.New("invalid test data")
|
||||
}
|
||||
|
||||
hexBytes := strings.Fields(line)
|
||||
for _, hexByte := range hexBytes {
|
||||
val, err := strconv.ParseUint(hexByte, 16, 8)
|
||||
if err != nil {
|
||||
return nil, errors.New("invalid hex byte in test data: " + err.Error())
|
||||
}
|
||||
currentFlow = append(currentFlow, byte(val))
|
||||
}
|
||||
}
|
||||
|
||||
if len(currentFlow) > 0 {
|
||||
flows = append(flows, currentFlow)
|
||||
}
|
||||
|
||||
return flows, nil
|
||||
}
|
@ -22,6 +22,8 @@ import (
|
||||
)
|
||||
|
||||
var useValgrind = flag.Bool("valgrind", false, "If true, run code under valgrind")
|
||||
var useGDB = flag.Bool("gdb", false, "If true, run BoringSSL code under gdb")
|
||||
var flagDebug *bool = flag.Bool("debug", false, "Hexdump the contents of the connection")
|
||||
|
||||
const (
|
||||
rsaCertificateFile = "cert.pem"
|
||||
@ -693,10 +695,11 @@ func runTest(test *testCase, buildDir string) error {
|
||||
var shim *exec.Cmd
|
||||
if *useValgrind {
|
||||
shim = valgrindOf(false, shim_path, flags...)
|
||||
} else if *useGDB {
|
||||
shim = gdbOf(shim_path, flags...)
|
||||
} else {
|
||||
shim = exec.Command(shim_path, flags...)
|
||||
}
|
||||
// shim = gdbOf(shim_path, flags...)
|
||||
shim.ExtraFiles = []*os.File{shimEnd, shimEndResume}
|
||||
shim.Stdin = os.Stdin
|
||||
var stdoutBuf, stderrBuf bytes.Buffer
|
||||
@ -717,8 +720,19 @@ func runTest(test *testCase, buildDir string) error {
|
||||
}
|
||||
}
|
||||
|
||||
var connDebug *recordingConn
|
||||
if *flagDebug {
|
||||
connDebug = &recordingConn{Conn: conn}
|
||||
conn = connDebug
|
||||
}
|
||||
|
||||
err := doExchange(test, &config, conn, test.messageLen,
|
||||
false /* not a resumption */)
|
||||
|
||||
if *flagDebug {
|
||||
connDebug.WriteTo(os.Stdout)
|
||||
}
|
||||
|
||||
conn.Close()
|
||||
if err == nil && test.resumeSession {
|
||||
var resumeConfig Config
|
||||
@ -1070,6 +1084,62 @@ func addClientAuthTests() {
|
||||
}
|
||||
}
|
||||
|
||||
func addExtendedMasterSecretTests() {
|
||||
const expectEMSFlag = "-expect-extended-master-secret"
|
||||
|
||||
for _, with := range []bool{false, true} {
|
||||
prefix := "No"
|
||||
var flags []string
|
||||
if with {
|
||||
prefix = ""
|
||||
flags = []string{expectEMSFlag}
|
||||
}
|
||||
|
||||
for _, isClient := range []bool{false, true} {
|
||||
suffix := "-Server"
|
||||
testType := serverTest
|
||||
if isClient {
|
||||
suffix = "-Client"
|
||||
testType = clientTest
|
||||
}
|
||||
|
||||
for _, ver := range tlsVersions {
|
||||
test := testCase{
|
||||
testType: testType,
|
||||
name: prefix + "ExtendedMasterSecret-" + ver.name + suffix,
|
||||
config: Config{
|
||||
MinVersion: ver.version,
|
||||
MaxVersion: ver.version,
|
||||
Bugs: ProtocolBugs{
|
||||
NoExtendedMasterSecret: !with,
|
||||
RequireExtendedMasterSecret: with,
|
||||
},
|
||||
},
|
||||
flags: flags,
|
||||
shouldFail: ver.version == VersionSSL30 && with,
|
||||
}
|
||||
if test.shouldFail {
|
||||
test.expectedLocalError = "extended master secret required but not supported by peer"
|
||||
}
|
||||
testCases = append(testCases, test)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When a session is resumed, it should still be aware that its master
|
||||
// secret was generated via EMS and thus it's safe to use tls-unique.
|
||||
testCases = append(testCases, testCase{
|
||||
name: "ExtendedMasterSecret-Resume",
|
||||
config: Config{
|
||||
Bugs: ProtocolBugs{
|
||||
RequireExtendedMasterSecret: true,
|
||||
},
|
||||
},
|
||||
flags: []string{expectEMSFlag},
|
||||
resumeSession: true,
|
||||
})
|
||||
}
|
||||
|
||||
// Adds tests that try to cover the range of the handshake state machine, under
|
||||
// various conditions. Some of these are redundant with other tests, but they
|
||||
// only cover the synchronous case.
|
||||
@ -1568,7 +1638,7 @@ func addExtensionTests() {
|
||||
},
|
||||
},
|
||||
resumeSession: true,
|
||||
shouldFail: true,
|
||||
shouldFail: true,
|
||||
expectedError: ":DECODE_ERROR:",
|
||||
})
|
||||
}
|
||||
@ -1690,6 +1760,7 @@ func main() {
|
||||
addD5BugTests()
|
||||
addExtensionTests()
|
||||
addResumptionVersionTests()
|
||||
addExtendedMasterSecretTests()
|
||||
for _, async := range []bool{false, true} {
|
||||
for _, splitHandshake := range []bool{false, true} {
|
||||
for _, protocol := range []protocol{tls, dtls} {
|
||||
|
@ -18,11 +18,12 @@ import (
|
||||
// sessionState contains the information that is serialized into a session
|
||||
// ticket in order to later resume a connection.
|
||||
type sessionState struct {
|
||||
vers uint16
|
||||
cipherSuite uint16
|
||||
masterSecret []byte
|
||||
handshakeHash []byte
|
||||
certificates [][]byte
|
||||
vers uint16
|
||||
cipherSuite uint16
|
||||
masterSecret []byte
|
||||
handshakeHash []byte
|
||||
certificates [][]byte
|
||||
extendedMasterSecret bool
|
||||
}
|
||||
|
||||
func (s *sessionState) equal(i interface{}) bool {
|
||||
@ -34,7 +35,8 @@ func (s *sessionState) equal(i interface{}) bool {
|
||||
if s.vers != s1.vers ||
|
||||
s.cipherSuite != s1.cipherSuite ||
|
||||
!bytes.Equal(s.masterSecret, s1.masterSecret) ||
|
||||
!bytes.Equal(s.handshakeHash, s1.handshakeHash) {
|
||||
!bytes.Equal(s.handshakeHash, s1.handshakeHash) ||
|
||||
s.extendedMasterSecret != s1.extendedMasterSecret {
|
||||
return false
|
||||
}
|
||||
|
||||
@ -56,6 +58,7 @@ func (s *sessionState) marshal() []byte {
|
||||
for _, cert := range s.certificates {
|
||||
length += 4 + len(cert)
|
||||
}
|
||||
length++
|
||||
|
||||
ret := make([]byte, length)
|
||||
x := ret
|
||||
@ -88,6 +91,11 @@ func (s *sessionState) marshal() []byte {
|
||||
x = x[4+len(cert):]
|
||||
}
|
||||
|
||||
if s.extendedMasterSecret {
|
||||
x[0] = 1
|
||||
}
|
||||
x = x[1:]
|
||||
|
||||
return ret
|
||||
}
|
||||
|
||||
@ -144,6 +152,16 @@ func (s *sessionState) unmarshal(data []byte) bool {
|
||||
data = data[certLen:]
|
||||
}
|
||||
|
||||
if len(data) < 1 {
|
||||
return false
|
||||
}
|
||||
|
||||
s.extendedMasterSecret = false
|
||||
if data[0] == 1 {
|
||||
s.extendedMasterSecret = true
|
||||
}
|
||||
data = data[1:]
|
||||
|
||||
if len(data) > 0 {
|
||||
return false
|
||||
}
|
||||
|
@ -57,6 +57,8 @@ const BoolFlag kBoolFlags[] = {
|
||||
{ "-shim-writes-first", &TestConfig::shim_writes_first },
|
||||
{ "-tls-d5-bug", &TestConfig::tls_d5_bug },
|
||||
{ "-expect-session-miss", &TestConfig::expect_session_miss },
|
||||
{ "-expect-extended-master-secret",
|
||||
&TestConfig::expect_extended_master_secret },
|
||||
};
|
||||
|
||||
const size_t kNumBoolFlags = sizeof(kBoolFlags) / sizeof(kBoolFlags[0]);
|
||||
@ -105,7 +107,8 @@ TestConfig::TestConfig()
|
||||
cookie_exchange(false),
|
||||
shim_writes_first(false),
|
||||
tls_d5_bug(false),
|
||||
expect_session_miss(false) {
|
||||
expect_session_miss(false),
|
||||
expect_extended_master_secret(false) {
|
||||
}
|
||||
|
||||
bool ParseConfig(int argc, char **argv, TestConfig *out_config) {
|
||||
|
@ -53,6 +53,7 @@ struct TestConfig {
|
||||
std::string expected_advertised_alpn;
|
||||
std::string select_alpn;
|
||||
bool expect_session_miss;
|
||||
bool expect_extended_master_secret;
|
||||
};
|
||||
|
||||
bool ParseConfig(int argc, char **argv, TestConfig *out_config);
|
||||
|
Loading…
x
Reference in New Issue
Block a user