#endif
static int ca_dn_cmp(const X509_NAME *const *a, const X509_NAME *const *b);
+#ifndef OPENSSL_NO_TLSEXT
+static int ssl3_check_finished(SSL *s);
+#endif
#ifndef OPENSSL_NO_SSL3_METHOD
static const SSL_METHOD *ssl3_get_client_method(int ver)
cb = s->ctx->info_callback;
s->in_handshake++;
- if (!SSL_in_init(s) || SSL_in_before(s))
- SSL_clear(s);
+ if (!SSL_in_init(s) || SSL_in_before(s)) {
+ if (!SSL_clear(s))
+ return -1;
+ }
#ifndef OPENSSL_NO_HEARTBEATS
/*
if ((s->version & 0xff00) != 0x0300) {
SSLerr(SSL_F_SSL3_CONNECT, ERR_R_INTERNAL_ERROR);
+ s->state = SSL_ST_ERR;
ret = -1;
goto end;
}
if (s->init_buf == NULL) {
if ((buf = BUF_MEM_new()) == NULL) {
ret = -1;
+ s->state = SSL_ST_ERR;
goto end;
}
if (!BUF_MEM_grow(buf, SSL3_RT_MAX_PLAIN_LENGTH)) {
ret = -1;
+ s->state = SSL_ST_ERR;
goto end;
}
s->init_buf = buf;
/* setup buffing BIO */
if (!ssl_init_wbio_buffer(s, 0)) {
ret = -1;
+ s->state = SSL_ST_ERR;
goto end;
}
break;
case SSL3_ST_CR_CERT_A:
case SSL3_ST_CR_CERT_B:
+#ifndef OPENSSL_NO_TLSEXT
+ /* Noop (ret = 0) for everything but EAP-FAST. */
+ ret = ssl3_check_finished(s);
+ if (ret < 0)
+ goto end;
+ if (ret == 1) {
+ s->hit = 1;
+ s->state = SSL3_ST_CR_FINISHED_A;
+ s->init_num = 0;
+ break;
+ }
+#endif
/* Check if it is anon DH/ECDH, SRP auth */
/* or PSK */
if (!
*/
if (!ssl3_check_cert_and_algorithm(s)) {
ret = -1;
+ s->state = SSL_ST_ERR;
goto end;
}
break;
if ((ret = SRP_Calc_A_param(s)) <= 0) {
SSLerr(SSL_F_SSL3_CONNECT, SSL_R_SRP_A_CALC);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ s->state = SSL_ST_ERR;
goto end;
}
}
#endif
if (!s->method->ssl3_enc->setup_key_block(s)) {
ret = -1;
+ s->state = SSL_ST_ERR;
goto end;
}
SSL3_CHANGE_CIPHER_CLIENT_WRITE))
{
ret = -1;
+ s->state = SSL_ST_ERR;
goto end;
}
case SSL3_ST_CR_FINISHED_A:
case SSL3_ST_CR_FINISHED_B:
- s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ if (!s->s3->change_cipher_spec)
+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
ret = ssl3_get_finished(s, SSL3_ST_CR_FINISHED_A,
SSL3_ST_CR_FINISHED_B);
if (ret <= 0)
case SSL_ST_OK:
/* clean a few things up */
ssl3_cleanup_key_block(s);
-
- if (s->init_buf != NULL) {
- BUF_MEM_free(s->init_buf);
- s->init_buf = NULL;
- }
+ BUF_MEM_free(s->init_buf);
+ s->init_buf = NULL;
/*
* If we are not 'joining' the last two packets, remove the
goto end;
/* break; */
+ case SSL_ST_ERR:
default:
SSLerr(SSL_F_SSL3_CONNECT, SSL_R_UNKNOWN_STATE);
ret = -1;
}
end:
s->in_handshake--;
- if (buf != NULL)
- BUF_MEM_free(buf);
+ BUF_MEM_free(buf);
if (cb != NULL)
cb(s, SSL_CB_CONNECT_EXIT, ret);
return (ret);
buf = (unsigned char *)s->init_buf->data;
if (s->state == SSL3_ST_CW_CLNT_HELLO_A) {
SSL_SESSION *sess = s->session;
- if ((sess == NULL) ||
- (sess->ssl_version != s->version) ||
- !sess->session_id_length || (sess->not_resumable)) {
+ if ((sess == NULL) || (sess->ssl_version != s->version) ||
+#ifdef OPENSSL_NO_TLSEXT
+ !sess->session_id_length ||
+#else
+ /*
+ * In the case of EAP-FAST, we can have a pre-shared
+ * "ticket" without a session ID.
+ */
+ (!sess->session_id_length && !sess->tlsext_tick) ||
+#endif
+ (sess->not_resumable)) {
if (!ssl_get_new_session(s, 0))
goto err;
}
} else
i = 1;
- if (i)
- ssl_fill_hello_random(s, 0, p, sizeof(s->s3->client_random));
+ if (i && ssl_fill_hello_random(s, 0, p,
+ sizeof(s->s3->client_random)) <= 0)
+ goto err;
/* Do the message type and length last */
d = p = ssl_handshake_start(s);
* client_version in client hello and not resetting it to
* the negotiated version.
*/
-#if 0
- *(p++) = s->version >> 8;
- *(p++) = s->version & 0xff;
- s->client_version = s->version;
-#else
*(p++) = s->client_version >> 8;
*(p++) = s->client_version & 0xff;
-#endif
/* Random stuff */
memcpy(p, s->s3->client_random, SSL3_RANDOM_SIZE);
#endif
l = p - d;
- ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l);
+ if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_HELLO, l)) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ SSLerr(SSL_F_SSL3_CLIENT_HELLO, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
s->state = SSL3_ST_CW_CLNT_HELLO_B;
}
/* SSL3_ST_CW_CLNT_HELLO_B */
return ssl_do_write(s);
err:
+ s->state = SSL_ST_ERR;
return (-1);
}
}
#ifndef OPENSSL_NO_TLSEXT
/*
- * check if we want to resume the session based on external pre-shared
- * secret
+ * Check if we can resume the session based on external pre-shared secret.
+ * EAP-FAST (RFC 4851) supports two types of session resumption.
+ * Resumption based on server-side state works with session IDs.
+ * Resumption based on pre-shared Protected Access Credentials (PACs)
+ * works by overriding the SessionTicket extension at the application
+ * layer, and does not send a session ID. (We do not know whether EAP-FAST
+ * servers would honour the session ID.) Therefore, the session ID alone
+ * is not a reliable indicator of session resumption, so we first check if
+ * we can resume, and later peek at the next handshake message to see if the
+ * server wants to resume.
*/
- if (s->version >= TLS1_VERSION && s->tls_session_secret_cb) {
+ if (s->version >= TLS1_VERSION && s->tls_session_secret_cb &&
+ s->session->tlsext_tick) {
SSL_CIPHER *pref_cipher = NULL;
s->session->master_key_length = sizeof(s->session->master_key);
if (s->tls_session_secret_cb(s, s->session->master_key,
s->tls_session_secret_cb_arg)) {
s->session->cipher = pref_cipher ?
pref_cipher : ssl_get_cipher_by_char(s, p + j);
- s->hit = 1;
+ } else {
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO, ERR_R_INTERNAL_ERROR);
+ al = SSL_AD_INTERNAL_ERROR;
+ goto f_err;
}
}
#endif /* OPENSSL_NO_TLSEXT */
- if (!s->hit && j != 0 && j == s->session->session_id_length
+ if (j != 0 && j == s->session->session_id_length
&& memcmp(p, s->session->session_id, j) == 0) {
if (s->sid_ctx_length != s->session->sid_ctx_length
|| memcmp(s->session->sid_ctx, s->sid_ctx, s->sid_ctx_length)) {
goto f_err;
}
s->hit = 1;
- }
- /* a miss or crap from the other end */
- if (!s->hit) {
+ } else {
/*
- * If we were trying for session-id reuse, make a new SSL_SESSION so
- * we don't stuff up other people
+ * If we were trying for session-id reuse but the server
+ * didn't echo the ID, make a new SSL_SESSION.
+ * In the case of EAP-FAST and PAC, we do not send a session ID,
+ * so the PAC-based session secret is always preserved. It'll be
+ * overwritten if the server refuses resumption.
*/
if (s->session->session_id_length > 0) {
if (!ssl_get_new_session(s, 0)) {
if (s->session->cipher)
s->session->cipher_id = s->session->cipher->id;
if (s->hit && (s->session->cipher_id != c->id)) {
-/* Workaround is now obsolete */
-#if 0
- if (!(s->options & SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG))
-#endif
- {
- al = SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
- SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
- goto f_err;
- }
+ al = SSL_AD_ILLEGAL_PARAMETER;
+ SSLerr(SSL_F_SSL3_GET_SERVER_HELLO,
+ SSL_R_OLD_SESSION_CIPHER_NOT_RETURNED);
+ goto f_err;
}
s->s3->tmp.new_cipher = c;
/*
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
err:
+ s->state = SSL_ST_ERR;
return (-1);
}
if (sc == NULL)
goto err;
- if (s->session->sess_cert)
- ssl_sess_cert_free(s->session->sess_cert);
+ ssl_sess_cert_free(s->session->sess_cert);
s->session->sess_cert = sc;
sc->cert_chain = sk;
* Why would the following ever happen? We just created sc a couple
* of lines ago.
*/
- if (sc->peer_pkeys[i].x509 != NULL)
- X509_free(sc->peer_pkeys[i].x509);
+ X509_free(sc->peer_pkeys[i].x509);
sc->peer_pkeys[i].x509 = x;
sc->peer_key = &(sc->peer_pkeys[i]);
- if (s->session->peer != NULL)
- X509_free(s->session->peer);
+ X509_free(s->session->peer);
CRYPTO_add(&x->references, 1, CRYPTO_LOCK_X509);
s->session->peer = x;
} else {
sc->peer_cert_type = i;
sc->peer_key = NULL;
- if (s->session->peer != NULL)
- X509_free(s->session->peer);
+ X509_free(s->session->peer);
s->session->peer = NULL;
}
s->session->verify_result = s->verify_result;
x = NULL;
ret = 1;
- if (0) {
+ goto done;
+
f_err:
- ssl3_send_alert(s, SSL3_AL_FATAL, al);
- }
+ ssl3_send_alert(s, SSL3_AL_FATAL, al);
err:
+ s->state = SSL_ST_ERR;
+ done:
EVP_PKEY_free(pkey);
X509_free(x);
sk_X509_pop_free(sk, X509_free);
#ifndef OPENSSL_NO_DH
DH *dh = NULL;
#endif
-#ifndef OPENSSL_NO_ECDH
+#ifndef OPENSSL_NO_EC
EC_KEY *ecdh = NULL;
BN_CTX *bn_ctx = NULL;
EC_POINT *srvr_ecpoint = NULL;
*/
if (alg_k & SSL_kPSK) {
s->session->sess_cert = ssl_sess_cert_new();
- if (s->ctx->psk_identity_hint)
- OPENSSL_free(s->ctx->psk_identity_hint);
+ OPENSSL_free(s->ctx->psk_identity_hint);
s->ctx->psk_identity_hint = NULL;
}
#endif
param = p = (unsigned char *)s->init_msg;
if (s->session->sess_cert != NULL) {
#ifndef OPENSSL_NO_RSA
- if (s->session->sess_cert->peer_rsa_tmp != NULL) {
- RSA_free(s->session->sess_cert->peer_rsa_tmp);
- s->session->sess_cert->peer_rsa_tmp = NULL;
- }
+ RSA_free(s->session->sess_cert->peer_rsa_tmp);
+ s->session->sess_cert->peer_rsa_tmp = NULL;
#endif
#ifndef OPENSSL_NO_DH
- if (s->session->sess_cert->peer_dh_tmp) {
- DH_free(s->session->sess_cert->peer_dh_tmp);
- s->session->sess_cert->peer_dh_tmp = NULL;
- }
+ DH_free(s->session->sess_cert->peer_dh_tmp);
+ s->session->sess_cert->peer_dh_tmp = NULL;
#endif
-#ifndef OPENSSL_NO_ECDH
- if (s->session->sess_cert->peer_ecdh_tmp) {
- EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp);
- s->session->sess_cert->peer_ecdh_tmp = NULL;
- }
+#ifndef OPENSSL_NO_EC
+ EC_KEY_free(s->session->sess_cert->peer_ecdh_tmp);
+ s->session->sess_cert->peer_ecdh_tmp = NULL;
#endif
} else {
s->session->sess_cert = ssl_sess_cert_new();
*/
memcpy(tmp_id_hint, p, i);
memset(tmp_id_hint + i, 0, PSK_MAX_IDENTITY_LEN + 1 - i);
- if (s->ctx->psk_identity_hint != NULL)
- OPENSSL_free(s->ctx->psk_identity_hint);
+ OPENSSL_free(s->ctx->psk_identity_hint);
s->ctx->psk_identity_hint = BUF_strdup(tmp_id_hint);
if (s->ctx->psk_identity_hint == NULL) {
al = SSL_AD_HANDSHAKE_FAILURE;
s->session->sess_cert->peer_dh_tmp = dh;
dh = NULL;
- } else if ((alg_k & SSL_kDHr) || (alg_k & SSL_kDHd)) {
- al = SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE,
- SSL_R_TRIED_TO_USE_UNSUPPORTED_CIPHER);
- goto f_err;
}
#endif /* !OPENSSL_NO_DH */
-#ifndef OPENSSL_NO_ECDH
+#ifndef OPENSSL_NO_EC
else if (alg_k & SSL_kECDHE) {
EC_GROUP *ngroup;
const EC_GROUP *group;
X509_get_pubkey(s->session->
sess_cert->peer_pkeys[SSL_PKEY_RSA_ENC].x509);
# endif
-# ifndef OPENSSL_NO_ECDSA
+# ifndef OPENSSL_NO_EC
else if (alg_a & SSL_aECDSA)
pkey =
X509_get_pubkey(s->session->
SSLerr(SSL_F_SSL3_GET_KEY_EXCHANGE, SSL_R_UNEXPECTED_MESSAGE);
goto f_err;
}
-#endif /* !OPENSSL_NO_ECDH */
+#endif /* !OPENSSL_NO_EC */
/* p points to the next byte, there are 'n' bytes left */
err:
EVP_PKEY_free(pkey);
#ifndef OPENSSL_NO_RSA
- if (rsa != NULL)
- RSA_free(rsa);
+ RSA_free(rsa);
#endif
#ifndef OPENSSL_NO_DH
- if (dh != NULL)
- DH_free(dh);
+ DH_free(dh);
#endif
-#ifndef OPENSSL_NO_ECDH
+#ifndef OPENSSL_NO_EC
BN_CTX_free(bn_ctx);
EC_POINT_free(srvr_ecpoint);
- if (ecdh != NULL)
- EC_KEY_free(ecdh);
+ EC_KEY_free(ecdh);
#endif
EVP_MD_CTX_cleanup(&md_ctx);
+ s->state = SSL_ST_ERR;
return (-1);
}
/* get the certificate types */
ctype_num = *(p++);
- if (s->cert->ctypes) {
- OPENSSL_free(s->cert->ctypes);
- s->cert->ctypes = NULL;
- }
+ OPENSSL_free(s->cert->ctypes);
+ s->cert->ctypes = NULL;
if (ctype_num > SSL3_CT_NUMBER) {
/* If we exceed static buffer copy all to cert structure */
s->cert->ctypes = OPENSSL_malloc(ctype_num);
/* get the CA RDNs */
n2s(p, llen);
-#if 0
- {
- FILE *out;
- out = fopen("/tmp/vsign.der", "w");
- fwrite(p, 1, llen, out);
- fclose(out);
- }
-#endif
if ((unsigned long)(p - d + llen) != n) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
for (nc = 0; nc < llen;) {
n2s(p, l);
if ((l + nc + 2) > llen) {
- if ((s->options & SSL_OP_NETSCAPE_CA_DN_BUG))
- goto cont; /* netscape bugs */
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, SSL_R_CA_DN_TOO_LONG);
goto err;
q = p;
if ((xn = d2i_X509_NAME(NULL, &q, l)) == NULL) {
- /* If netscape tolerance is on, ignore errors */
- if (s->options & SSL_OP_NETSCAPE_CA_DN_BUG)
- goto cont;
- else {
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
- SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, ERR_R_ASN1_LIB);
- goto err;
- }
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ SSLerr(SSL_F_SSL3_GET_CERTIFICATE_REQUEST, ERR_R_ASN1_LIB);
+ goto err;
}
if (q != (p + l)) {
nc += l + 2;
}
- if (0) {
- cont:
- ERR_clear_error();
- }
-
/* we should setup a certificate to return.... */
s->s3->tmp.cert_req = 1;
s->s3->tmp.ctype_num = ctype_num;
- if (s->s3->tmp.ca_names != NULL)
- sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free);
+ sk_X509_NAME_pop_free(s->s3->tmp.ca_names, X509_NAME_free);
s->s3->tmp.ca_names = ca_sk;
ca_sk = NULL;
ret = 1;
+ goto done;
err:
- if (ca_sk != NULL)
- sk_X509_NAME_pop_free(ca_sk, X509_NAME_free);
+ s->state = SSL_ST_ERR;
+ done:
+ sk_X509_NAME_pop_free(ca_sk, X509_NAME_free);
return (ret);
}
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
goto f_err;
}
- if (s->session->tlsext_tick) {
- OPENSSL_free(s->session->tlsext_tick);
- s->session->tlsext_ticklen = 0;
- }
+ OPENSSL_free(s->session->tlsext_tick);
+ s->session->tlsext_ticklen = 0;
s->session->tlsext_tick = OPENSSL_malloc(ticklen);
if (!s->session->tlsext_tick) {
SSLerr(SSL_F_SSL3_GET_NEW_SESSION_TICKET, ERR_R_MALLOC_FAILURE);
*/
EVP_Digest(p, ticklen,
s->session->session_id, &s->session->session_id_length,
-# ifndef OPENSSL_NO_SHA256
EVP_sha256(), NULL);
-# else
- EVP_sha1(), NULL);
-# endif
ret = 1;
return (ret);
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
err:
+ s->state = SSL_ST_ERR;
return (-1);
}
SSLerr(SSL_F_SSL3_GET_CERT_STATUS, SSL_R_LENGTH_MISMATCH);
goto f_err;
}
- if (s->tlsext_ocsp_resp)
- OPENSSL_free(s->tlsext_ocsp_resp);
+ OPENSSL_free(s->tlsext_ocsp_resp);
s->tlsext_ocsp_resp = BUF_memdup(p, resplen);
if (!s->tlsext_ocsp_resp) {
al = SSL_AD_INTERNAL_ERROR;
return 1;
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
+ s->state = SSL_ST_ERR;
return (-1);
}
#endif
/* should contain no data */
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
SSLerr(SSL_F_SSL3_GET_SERVER_DONE, SSL_R_LENGTH_MISMATCH);
+ s->state = SSL_ST_ERR;
return -1;
}
ret = 1;
#ifndef OPENSSL_NO_KRB5
KSSL_ERR kssl_err;
#endif /* OPENSSL_NO_KRB5 */
-#ifndef OPENSSL_NO_ECDH
+#ifndef OPENSSL_NO_EC
EC_KEY *clnt_ecdh = NULL;
const EC_POINT *srvr_ecpoint = NULL;
EVP_PKEY *srvr_pub_pkey = NULL;
int encoded_pt_len = 0;
BN_CTX *bn_ctx = NULL;
#endif
+ unsigned char *pms = NULL;
+ size_t pmslen = 0;
if (s->state == SSL3_ST_CW_KEY_EXCH_A) {
p = ssl_handshake_start(s);
#ifndef OPENSSL_NO_RSA
else if (alg_k & SSL_kRSA) {
RSA *rsa;
- unsigned char tmp_buf[SSL_MAX_MASTER_KEY_LENGTH];
+ pmslen = SSL_MAX_MASTER_KEY_LENGTH;
+ pms = OPENSSL_malloc(pmslen);
+ if (!pms)
+ goto memerr;
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, pmslen - 2) <= 0)
goto err;
- s->session->master_key_length = sizeof tmp_buf;
-
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(pmslen, pms, p, rsa, RSA_PKCS1_PADDING);
# ifdef PKCS1_CHECK
if (s->options & SSL_OP_PKCS1_CHECK_1)
p[1]++;
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);
}
#endif
#ifndef OPENSSL_NO_KRB5
n += 2;
}
- 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)
+ pmslen = SSL_MAX_MASTER_KEY_LENGTH;
+ pms = OPENSSL_malloc(pmslen);
+ if (!pms)
+ goto memerr;
+
+ pms[0] = s->client_version >> 8;
+ pms[1] = s->client_version & 0xff;
+ if (RAND_bytes(pms + 2, pmslen - 2) <= 0)
goto err;
/*-
* EVP_EncryptInit_ex(&ciph_ctx,NULL, key,iv);
*/
- memset(iv, 0, sizeof iv); /* per RFC 1510 */
+ memset(iv, 0, sizeof(iv)); /* per RFC 1510 */
EVP_EncryptInit_ex(&ciph_ctx, enc, NULL, kssl_ctx->key, iv);
- EVP_EncryptUpdate(&ciph_ctx, epms, &outl, tmp_buf,
- sizeof tmp_buf);
+ EVP_EncryptUpdate(&ciph_ctx, epms, &outl, pms, pmslen);
EVP_EncryptFinal_ex(&ciph_ctx, &(epms[outl]), &padl);
outl += padl;
if (outl > (int)sizeof epms) {
memcpy(p, epms, outl);
p += outl;
n += outl + 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);
OPENSSL_cleanse(epms, outl);
}
#endif
}
}
+ pmslen = DH_size(dh_clnt);
+ pms = OPENSSL_malloc(pmslen);
+ if (!pms)
+ goto memerr;
+
/*
* use the 'p' output buffer for the DH key, but make sure to
* clear it out afterwards
*/
- n = DH_compute_key(p, dh_srvr->pub_key, dh_clnt);
+ n = DH_compute_key(pms, dh_srvr->pub_key, dh_clnt);
if (scert->peer_dh_tmp == NULL)
DH_free(dh_srvr);
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);
+ pmslen = n;
if (s->s3->flags & TLS1_FLAGS_SKIP_CERT_VERIFY)
n = 0;
}
#endif
-#ifndef OPENSSL_NO_ECDH
+#ifndef OPENSSL_NO_EC
else if (alg_k & (SSL_kECDHE | SSL_kECDHr | SSL_kECDHe)) {
const EC_GROUP *srvr_group = NULL;
EC_KEY *tkey;
SSLerr(SSL_F_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) {
+ pmslen = (field_size + 7) / 8;
+ pms = OPENSSL_malloc(pmslen);
+ if (!pms)
+ goto memerr;
+ n = ECDH_compute_key(pms, pmslen, srvr_ecpoint, clnt_ecdh, NULL);
+ if (n <= 0 || pmslen != (size_t)n) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_ECDH_LIB);
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);
-
- memset(p, 0, n); /* clean up */
-
if (ecdh_clnt_cert) {
/* Send empty client key exch message */
n = 0;
/* Encoded point will be copied here */
p += 1;
/* copy the point */
- memcpy((unsigned char *)p, encodedPoint, n);
+ memcpy(p, encodedPoint, n);
/* increment n to account for length field */
n += 1;
}
/* Free allocated memory */
BN_CTX_free(bn_ctx);
- if (encodedPoint != NULL)
- OPENSSL_free(encodedPoint);
- if (clnt_ecdh != NULL)
- EC_KEY_free(clnt_ecdh);
+ OPENSSL_free(encodedPoint);
+ EC_KEY_free(clnt_ecdh);
EVP_PKEY_free(srvr_pub_pkey);
}
-#endif /* !OPENSSL_NO_ECDH */
+#endif /* !OPENSSL_NO_EC */
else if (alg_k & SSL_kGOST) {
/* GOST key exchange message creation */
EVP_PKEY_CTX *pkey_ctx;
size_t msglen;
unsigned int md_len;
int keytype;
- unsigned char premaster_secret[32], shared_ukm[32], tmp[256];
+ unsigned char shared_ukm[32], tmp[256];
EVP_MD_CTX *ukm_hash;
EVP_PKEY *pub_key;
+ pmslen = 32;
+ pms = OPENSSL_malloc(pmslen);
+ if (!pms)
+ goto memerr;
+
/*
* Get server sertificate PKEY and create ctx from it
*/
EVP_PKEY_encrypt_init(pkey_ctx);
/* Generate session key */
- RAND_bytes(premaster_secret, 32);
+ if (RAND_bytes(pms, pmslen) <= 0) {
+ EVP_PKEY_CTX_free(pkey_ctx);
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ };
/*
* If we have client certificate, use its secret as peer key
*/
*/
*(p++) = V_ASN1_SEQUENCE | V_ASN1_CONSTRUCTED;
msglen = 255;
- if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, premaster_secret, 32)
- < 0) {
+ if (EVP_PKEY_encrypt(pkey_ctx, tmp, &msglen, pms, pmslen) < 0) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
SSL_R_LIBRARY_BUG);
goto err;
s->s3->flags |= TLS1_FLAGS_SKIP_CERT_VERIFY;
}
EVP_PKEY_CTX_free(pkey_ctx);
- s->session->master_key_length =
- s->method->ssl3_enc->generate_master_secret(s,
- s->
- session->master_key,
- premaster_secret,
- 32);
EVP_PKEY_free(pub_key);
}
ERR_R_INTERNAL_ERROR);
goto err;
}
- if (s->session->srp_username != NULL)
- OPENSSL_free(s->session->srp_username);
+ OPENSSL_free(s->session->srp_username);
s->session->srp_username = BUF_strdup(s->srp_ctx.login);
if (s->session->srp_username == NULL) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
ERR_R_MALLOC_FAILURE);
goto err;
}
-
- if ((s->session->master_key_length =
- SRP_generate_client_master_secret(s,
- s->session->master_key)) <
- 0) {
- SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
- ERR_R_INTERNAL_ERROR);
- goto err;
- }
}
#endif
#ifndef OPENSSL_NO_PSK
char identity[PSK_MAX_IDENTITY_LEN + 2];
size_t identity_len;
unsigned char *t = NULL;
- unsigned char psk_or_pre_ms[PSK_MAX_PSK_LEN * 2 + 4];
- unsigned int pre_ms_len = 0, psk_len = 0;
+ unsigned int psk_len = 0;
int psk_err = 1;
n = 0;
}
memset(identity, 0, sizeof(identity));
+ /* Allocate maximum size buffer */
+ pmslen = PSK_MAX_PSK_LEN * 2 + 4;
+ pms = OPENSSL_malloc(pmslen);
+ if (!pms)
+ goto memerr;
+
psk_len = s->psk_client_callback(s, s->ctx->psk_identity_hint,
identity, sizeof(identity) - 1,
- psk_or_pre_ms,
- sizeof(psk_or_pre_ms));
+ pms, pmslen);
if (psk_len > PSK_MAX_PSK_LEN) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
ERR_R_INTERNAL_ERROR);
SSL_R_PSK_IDENTITY_NOT_FOUND);
goto psk_err;
}
+ /* Change pmslen to real length */
+ pmslen = 2 + psk_len + 2 + psk_len;
identity[PSK_MAX_IDENTITY_LEN + 1] = '\0';
identity_len = strlen(identity);
if (identity_len > PSK_MAX_IDENTITY_LEN) {
goto psk_err;
}
/* create PSK pre_master_secret */
- pre_ms_len = 2 + psk_len + 2 + psk_len;
- t = psk_or_pre_ms;
- memmove(psk_or_pre_ms + psk_len + 4, psk_or_pre_ms, psk_len);
+ t = pms;
+ memmove(pms + psk_len + 4, pms, psk_len);
s2n(psk_len, t);
memset(t, 0, psk_len);
t += psk_len;
s2n(psk_len, t);
- if (s->session->psk_identity_hint != NULL)
- OPENSSL_free(s->session->psk_identity_hint);
+ OPENSSL_free(s->session->psk_identity_hint);
s->session->psk_identity_hint =
BUF_strdup(s->ctx->psk_identity_hint);
if (s->ctx->psk_identity_hint != NULL
goto psk_err;
}
- if (s->session->psk_identity != NULL)
- OPENSSL_free(s->session->psk_identity);
+ OPENSSL_free(s->session->psk_identity);
s->session->psk_identity = BUF_strdup(identity);
if (s->session->psk_identity == NULL) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
goto psk_err;
}
- s->session->master_key_length =
- s->method->ssl3_enc->generate_master_secret(s,
- s->
- session->master_key,
- psk_or_pre_ms,
- pre_ms_len);
s2n(identity_len, p);
memcpy(p, identity, identity_len);
n = 2 + identity_len;
psk_err = 0;
psk_err:
OPENSSL_cleanse(identity, sizeof(identity));
- OPENSSL_cleanse(psk_or_pre_ms, sizeof(psk_or_pre_ms));
if (psk_err != 0) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
goto err;
goto err;
}
- ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n);
+ if (!ssl_set_handshake_header(s, SSL3_MT_CLIENT_KEY_EXCHANGE, n)) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+
s->state = SSL3_ST_CW_KEY_EXCH_B;
}
/* SSL3_ST_CW_KEY_EXCH_B */
- return ssl_do_write(s);
+ n = ssl_do_write(s);
+#ifndef OPENSSL_NO_SRP
+ /* Check for SRP */
+ if (s->s3->tmp.new_cipher->algorithm_mkey & SSL_kSRP) {
+ /*
+ * If everything written generate master key: no need to save PMS as
+ * SRP_generate_client_master_secret generates it internally.
+ */
+ if (n > 0) {
+ if ((s->session->master_key_length =
+ SRP_generate_client_master_secret(s,
+ s->session->master_key)) <
+ 0) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE,
+ ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+ } else
+#endif
+ /* If we haven't written everything save PMS */
+ if (n <= 0) {
+ s->cert->pms = pms;
+ s->cert->pmslen = pmslen;
+ } else {
+ /* If we don't have a PMS restore */
+ if (pms == NULL) {
+ pms = s->cert->pms;
+ pmslen = s->cert->pmslen;
+ }
+ if (pms == NULL) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
+ goto err;
+ }
+ s->session->master_key_length =
+ s->method->ssl3_enc->generate_master_secret(s,
+ s->
+ session->master_key,
+ pms, pmslen);
+ OPENSSL_clear_free(pms, pmslen);
+ s->cert->pms = NULL;
+ if (s->session->master_key_length < 0) {
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
+ }
+ return n;
+ memerr:
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_KEY_EXCHANGE, ERR_R_MALLOC_FAILURE);
err:
-#ifndef OPENSSL_NO_ECDH
+ OPENSSL_clear_free(pms, pmslen);
+ s->cert->pms = NULL;
+#ifndef OPENSSL_NO_EC
BN_CTX_free(bn_ctx);
- if (encodedPoint != NULL)
- OPENSSL_free(encodedPoint);
- if (clnt_ecdh != NULL)
- EC_KEY_free(clnt_ecdh);
+ OPENSSL_free(encodedPoint);
+ EC_KEY_free(clnt_ecdh);
EVP_PKEY_free(srvr_pub_pkey);
#endif
+ s->state = SSL_ST_ERR;
return (-1);
}
}
s2n(u, p);
n = u + 4;
- if (!ssl3_digest_cached_records(s))
+ /*
+ * For extended master secret we've already digested cached
+ * records.
+ */
+ if (s->session->flags & SSL_SESS_FLAG_EXTMS) {
+ BIO_free(s->s3->handshake_buffer);
+ s->s3->handshake_buffer = NULL;
+ s->s3->flags &= ~TLS1_FLAGS_KEEP_HANDSHAKE;
+ } else if (!ssl3_digest_cached_records(s))
goto err;
} else
#ifndef OPENSSL_NO_RSA
n = j + 2;
} else
#endif
-#ifndef OPENSSL_NO_ECDSA
+#ifndef OPENSSL_NO_EC
if (pkey->type == EVP_PKEY_EC) {
if (!ECDSA_sign(pkey->save_type,
&(data[MD5_DIGEST_LENGTH]),
SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
goto err;
}
- ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n);
+ if (!ssl_set_handshake_header(s, SSL3_MT_CERTIFICATE_VERIFY, n)) {
+ SSLerr(SSL_F_SSL3_SEND_CLIENT_VERIFY, ERR_R_INTERNAL_ERROR);
+ goto err;
+ }
s->state = SSL3_ST_CW_CERT_VRFY_B;
}
EVP_MD_CTX_cleanup(&mctx);
err:
EVP_MD_CTX_cleanup(&mctx);
EVP_PKEY_CTX_free(pctx);
+ s->state = SSL_ST_ERR;
return (-1);
}
}
if (i == 0) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ s->state = SSL_ST_ERR;
return 0;
}
s->rwstate = SSL_NOTHING;
SSL_R_BAD_DATA_RETURNED_BY_CALLBACK);
}
- if (x509 != NULL)
- X509_free(x509);
- if (pkey != NULL)
- EVP_PKEY_free(pkey);
+ X509_free(x509);
+ EVP_PKEY_free(pkey);
if (i && !ssl3_check_client_certificate(s))
i = 0;
if (i == 0) {
2) ? NULL : s->cert->key)) {
SSLerr(SSL_F_SSL3_SEND_CLIENT_CERTIFICATE, ERR_R_INTERNAL_ERROR);
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ s->state = SSL_ST_ERR;
return 0;
}
}
/* This is the passed certificate */
idx = sc->peer_cert_type;
-#ifndef OPENSSL_NO_ECDH
+#ifndef OPENSSL_NO_EC
if (idx == SSL_PKEY_ECC) {
if (ssl_check_srvr_ecc_cert_and_alg(sc->peer_pkeys[idx].x509, s) == 0) {
/* check failed */
return (0);
}
+#ifndef OPENSSL_NO_TLSEXT
/*
- * Check to see if handshake is full or resumed. Usually this is just a case
- * of checking to see if a cache hit has occurred. In the case of session
- * tickets we have to check the next message to be sure.
+ * Normally, we can tell if the server is resuming the session from
+ * the session ID. EAP-FAST (RFC 4851), however, relies on the next server
+ * message after the ServerHello to determine if the server is resuming.
+ * Therefore, we allow EAP-FAST to peek ahead.
+ * ssl3_check_finished returns 1 if we are resuming from an external
+ * pre-shared secret, we have a "ticket" and the next server handshake message
+ * is Finished; and 0 otherwise. It returns -1 upon an error.
*/
+static int ssl3_check_finished(SSL *s)
+{
+ int ok = 0;
+
+ if (s->version < TLS1_VERSION || !s->tls_session_secret_cb ||
+ !s->session->tlsext_tick)
+ return 0;
+
+ /* Need to permit this temporarily, in case the next message is Finished. */
+ s->s3->flags |= SSL3_FLAGS_CCS_OK;
+ /*
+ * This function is called when we might get a Certificate message instead,
+ * so permit appropriate message length.
+ * We ignore the return value as we're only interested in the message type
+ * and not its length.
+ */
+ s->method->ssl_get_message(s,
+ SSL3_ST_CR_CERT_A,
+ SSL3_ST_CR_CERT_B,
+ -1, s->max_cert_list, &ok);
+ s->s3->flags &= ~SSL3_FLAGS_CCS_OK;
+
+ if (!ok)
+ return -1;
+
+ s->s3->tmp.reuse_message = 1;
+
+ if (s->s3->tmp.message_type == SSL3_MT_FINISHED)
+ return 1;
+
+ /* If we're not done, then the CCS arrived early and we should bail. */
+ if (s->s3->change_cipher_spec) {
+ SSLerr(SSL_F_SSL3_CHECK_FINISHED, SSL_R_CCS_RECEIVED_EARLY);
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
+ return -1;
+ }
+
+ return 0;
+}
-#ifndef OPENSSL_NO_TLSEXT
# ifndef OPENSSL_NO_NEXTPROTONEG
int ssl3_send_next_proto(SSL *s)
{