#include "ssl_locl.h"
#include "../crypto/dh/internal.h"
-static const SSL_METHOD *ssl3_get_client_method(int ver);
-
static const SSL_METHOD *ssl3_get_client_method(int ver)
{
- if (ver == SSL3_VERSION)
- return(SSLv3_client_method());
- else
- return(NULL);
+ switch (ver)
+ {
+ case TLS1_2_VERSION:
+ return TLSv1_2_client_method();
+ case TLS1_1_VERSION:
+ return TLSv1_1_client_method();
+ case TLS1_VERSION:
+ return TLSv1_client_method();
+ case SSL3_VERSION:
+ return SSLv3_client_method();
+ default:
+ return NULL;
+ }
}
-IMPLEMENT_ssl3_meth_func(SSLv3_client_method,
+IMPLEMENT_tls_meth_func(TLS1_2_VERSION, TLSv1_2_client_method,
+ ssl_undefined_function,
+ ssl3_connect,
+ ssl3_get_client_method,
+ TLSv1_2_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_1_VERSION, TLSv1_1_client_method,
ssl_undefined_function,
ssl3_connect,
- ssl3_get_client_method)
+ ssl3_get_client_method,
+ TLSv1_1_enc_data)
+
+IMPLEMENT_tls_meth_func(TLS1_VERSION, TLSv1_client_method,
+ ssl_undefined_function,
+ ssl3_connect,
+ ssl3_get_client_method,
+ TLSv1_enc_data)
+
+IMPLEMENT_tls_meth_func(SSL3_VERSION, SSLv3_client_method,
+ ssl_undefined_function,
+ ssl3_connect,
+ ssl3_get_client_method,
+ SSLv3_enc_data)
int ssl3_connect(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. */
}
else
{
- EVP_VerifyInit_ex(&md_ctx, md, NULL);
- EVP_VerifyUpdate(&md_ctx,&(s->s3->client_random[0]),SSL3_RANDOM_SIZE);
- EVP_VerifyUpdate(&md_ctx,&(s->s3->server_random[0]),SSL3_RANDOM_SIZE);
- EVP_VerifyUpdate(&md_ctx, CBS_data(¶meter), CBS_len(¶meter));
- if (EVP_VerifyFinal(&md_ctx, CBS_data(&signature), CBS_len(&signature), pkey) <= 0)
+ if (!EVP_DigestVerifyInit(&md_ctx, NULL, md, NULL, pkey) ||
+ !EVP_DigestVerifyUpdate(&md_ctx, s->s3->client_random, SSL3_RANDOM_SIZE) ||
+ !EVP_DigestVerifyUpdate(&md_ctx, s->s3->server_random, SSL3_RANDOM_SIZE) ||
+ !EVP_DigestVerifyUpdate(&md_ctx, CBS_data(¶meter), CBS_len(¶meter)) ||
+ !EVP_DigestVerifyFinal(&md_ctx, CBS_data(&signature), CBS_len(&signature)))
{
/* bad signature */
al=SSL_AD_DECRYPT_ERROR;
*/
if (s->s3->handshake_buffer)
{
- if (!ssl3_digest_cached_records(s))
+ if (!ssl3_digest_cached_records(s, free_handshake_buffer))
goto err;
}
return(1);
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)
{
alg_k=s->s3->tmp.new_cipher->algorithm_mkey;
alg_a=s->s3->tmp.new_cipher->algorithm_auth;
+ /* If using a PSK key exchange, prepare the pre-shared key. */
if (alg_a & SSL_aPSK)
{
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;
if (s->psk_client_callback == NULL)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_PSK_NO_CLIENT_CB);
if (psk_len > PSK_MAX_PSK_LEN)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
- goto psk_err;
+ goto err;
}
else if (psk_len == 0)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_PSK_IDENTITY_NOT_FOUND);
- goto psk_err;
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ goto err;
}
identity_len = OPENSSL_strnlen(identity, sizeof(identity));
if (identity_len > PSK_MAX_IDENTITY_LEN)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
- goto psk_err;
- }
-
- if (!(alg_k & SSL_kEECDH))
- {
- /* 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;
- s2n(psk_len, t);
- memset(t, 0, 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;
+ goto err;
}
if (s->session->psk_identity != NULL)
if (s->session->psk_identity == NULL)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
- goto psk_err;
- }
- psk_err = 0;
- psk_err:
- OPENSSL_cleanse(identity, PSK_MAX_IDENTITY_LEN);
- OPENSSL_cleanse(pre_ms, sizeof(pre_ms));
- if (psk_err != 0)
- {
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
goto err;
}
+
+ /* Write out psk_identity. */
+ s2n(identity_len, p);
+ memcpy(p, identity, identity_len);
+ p += identity_len;
+ n = 2 + identity_len;
}
+ /* Depending on the key exchange method, compute |pms|
+ * and |pms_len|. */
if (alg_k & SSL_kRSA)
{
RSA *rsa;
- unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
+ size_t enc_pms_len;
+
+ 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)
{
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 */
+ /* In TLS and beyond, reserve space for the length prefix. */
if (s->version > SSL3_VERSION)
- p+=2;
- n=RSA_public_encrypt(sizeof tmp_buf,
- tmp_buf,p,rsa,RSA_PKCS1_PADDING);
- if (n <= 0)
+ {
+ p += 2;
+ n += 2;
+ }
+ if (!RSA_encrypt(rsa, &enc_pms_len, p, RSA_size(rsa),
+ pms, pms_len, RSA_PKCS1_PADDING))
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, SSL_R_BAD_RSA_ENCRYPT);
goto err;
}
+ n += enc_pms_len;
/* 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, enc_pms_len, pms, pms_len))
{
goto err;
}
- /* Fix buf for TLS and beyond */
+ /* Fill in the length prefix. */
if (s->version > SSL3_VERSION)
{
- s2n(n,q);
- n+=2;
+ s2n(enc_pms_len, q);
}
-
- 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)
{
- DH *dh_srvr,*dh_clnt;
+ DH *dh_srvr, *dh_clnt;
SESS_CERT *scert = s->session->sess_cert;
+ int dh_len;
+ size_t pub_len;
if (scert == NULL)
{
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);
- if (n <= 0)
+ dh_len = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt);
+ if (dh_len <= 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 = dh_len;
/* send off the data */
- n=BN_num_bytes(dh_clnt->pub_key);
- s2n(n,p);
- BN_bn2bin(dh_clnt->pub_key,p);
- n+=2;
+ pub_len = BN_num_bytes(dh_clnt->pub_key);
+ s2n(pub_len, p);
+ BN_bn2bin(dh_clnt->pub_key, p);
+ n += 2 + pub_len;
DH_free(dh_clnt);
-
- /* perhaps clean things up a bit EAY EAY EAY EAY*/
}
else if (alg_k & SSL_kEECDH)
{
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;
+ int field_size = 0, ecdh_len;
if (s->session->sess_cert == NULL)
{
goto err;
}
- /* use the 'p' output buffer for the ECDH key, but
- * make sure to clear it out afterwards
- */
-
field_size = EC_GROUP_get_degree(srvr_group);
if (field_size <= 0)
{
OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
goto err;
}
- n=ECDH_compute_key(p, (field_size+7)/8, srvr_ecpoint, clnt_ecdh, NULL);
- if (n <= 0)
+
+ pms_len = (field_size + 7) / 8;
+ pms = OPENSSL_malloc(pms_len);
+ if (pms == NULL)
{
- OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
+ OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
goto err;
}
- /* ECDHE PSK ciphersuites from RFC 5489 */
- if ((alg_a & SSL_aPSK) && psk_len != 0)
+ ecdh_len = ECDH_compute_key(pms, pms_len, srvr_ecpoint, clnt_ecdh, NULL);
+ if (ecdh_len <= 0)
{
- pre_ms_len = 2+psk_len+2+n;
- pre_ms = OPENSSL_malloc(pre_ms_len);
- if (pre_ms == 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;
- 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);
+ OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_ECDH_LIB);
+ goto err;
}
- memset(p, 0, n); /* clean up */
+ pms_len = ecdh_len;
/* First check the size of encoding and
* allocate memory accordingly.
POINT_CONVERSION_UNCOMPRESSED,
encodedPoint, encoded_pt_len, bn_ctx);
- n = 0;
- if ((alg_a & SSL_aPSK) && psk_len != 0)
- {
- i = strlen(s->session->psk_identity);
- s2n(i, p);
- memcpy(p, s->session->psk_identity, i);
- p += i;
- n = i + 2;
- }
-
*p = encoded_pt_len; /* length of encoded point */
/* Encoded point will be copied here */
p += 1;
n += 1;
/* copy the point */
- memcpy((unsigned char *)p, encodedPoint, encoded_pt_len);
+ memcpy(p, encodedPoint, encoded_pt_len);
/* increment n to account for length field */
n += encoded_pt_len;
/* Free allocated memory */
BN_CTX_free(bn_ctx);
+ bn_ctx = NULL;
OPENSSL_free(encodedPoint);
+ encodedPoint = NULL;
EC_KEY_free(clnt_ecdh);
+ clnt_ecdh = NULL;
EVP_PKEY_free(srvr_pub_pkey);
+ srvr_pub_pkey = NULL;
+ }
+ else if (alg_k & SSL_kPSK)
+ {
+ /* For plain PSK, other_secret is a block of 0s with the same
+ * length as the pre-shared key. */
+ pms_len = psk_len;
+ pms = OPENSSL_malloc(pms_len);
+ if (pms == NULL)
+ {
+ OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ memset(pms, 0, pms_len);
}
- else if (!(alg_k & SSL_kPSK) || ((alg_k & SSL_kPSK) && !(alg_a & SSL_aPSK)))
+ else
{
ssl3_send_alert(s, SSL3_AL_FATAL,
SSL_AD_HANDSHAKE_FAILURE);
goto err;
}
+ /* For a PSK cipher suite, other_secret is combined
+ * with the pre-shared key. */
+ if ((alg_a & SSL_aPSK) && psk_len != 0)
+ {
+ CBB cbb, child;
+ uint8_t *new_pms;
+ size_t new_pms_len;
+
+ if (!CBB_init(&cbb, 2 + psk_len + 2 + pms_len))
+ {
+ OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ if (!CBB_add_u16_length_prefixed(&cbb, &child) ||
+ !CBB_add_bytes(&child, pms, pms_len) ||
+ !CBB_add_u16_length_prefixed(&cbb, &child) ||
+ !CBB_add_bytes(&child, psk, psk_len) ||
+ !CBB_finish(&cbb, &new_pms, &new_pms_len))
+ {
+ CBB_cleanup(&cbb);
+ OPENSSL_PUT_ERROR(SSL, ssl3_send_client_key_exchange, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ OPENSSL_cleanse(pms, pms_len);
+ OPENSSL_free(pms);
+ pms = new_pms;
+ pms_len = new_pms_len;
+ }
+
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_cleanse(pms, pms_len);
+ OPENSSL_free(pms);
+ }
+ return -1;
}
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. */
s->init_off = 0;
}
- return ssl3_do_write(s, SSL3_RT_HANDSHAKE);
+ return ssl3_do_write(s, SSL3_RT_HANDSHAKE, add_to_finished_hash);
}
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)
{
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);