break;
case TLS_ST_CR_CERT:
+ if (mt == SSL3_MT_CERTIFICATE_VERIFY) {
+ st->hand_state = TLS_ST_CR_CERT_VRFY;
+ return 1;
+ }
+ break;
+
+ case TLS_ST_CR_CERT_VRFY:
if (mt == SSL3_MT_FINISHED) {
st->hand_state = TLS_ST_CR_FINISHED;
return 1;
}
break;
+ case TLS_ST_OK:
+ if (mt == SSL3_MT_NEWSESSION_TICKET) {
+ st->hand_state = TLS_ST_CR_SESSION_TICKET;
+ return 1;
+ }
+ break;
}
/* No valid transition found */
return 1;
}
break;
+
+ case TLS_ST_OK:
+ if (mt == SSL3_MT_HELLO_REQUEST) {
+ st->hand_state = TLS_ST_CR_HELLO_REQ;
+ return 1;
+ }
+ break;
}
err:
st->hand_state = TLS_ST_CW_FINISHED;
return WRITE_TRAN_CONTINUE;
+ case TLS_ST_CR_SESSION_TICKET:
case TLS_ST_CW_FINISHED:
st->hand_state = TLS_ST_OK;
ossl_statem_set_in_init(s, 0);
return WRITE_TRAN_CONTINUE;
+
+ case TLS_ST_OK:
+ /* Just go straight to trying to read from the server */
+ return WRITE_TRAN_FINISHED;
}
}
return WRITE_TRAN_ERROR;
case TLS_ST_OK:
+ if (!s->renegotiate) {
+ /*
+ * We haven't requested a renegotiation ourselves so we must have
+ * received a message from the server. Better read it.
+ */
+ return WRITE_TRAN_FINISHED;
+ }
/* Renegotiation - fall through */
case TLS_ST_BEFORE:
st->hand_state = TLS_ST_CW_CLNT_HELLO;
ossl_statem_set_in_init(s, 0);
return WRITE_TRAN_CONTINUE;
}
+
+ case TLS_ST_CR_HELLO_REQ:
+ /*
+ * If we can renegotiate now then do so, otherwise wait for a more
+ * convenient time.
+ */
+ if (ssl3_renegotiate_check(s, 1)) {
+ if (!tls_setup_handshake(s)) {
+ ossl_statem_set_error(s);
+ return WRITE_TRAN_ERROR;
+ }
+ st->hand_state = TLS_ST_CW_CLNT_HELLO;
+ return WRITE_TRAN_CONTINUE;
+ }
+ st->hand_state = TLS_ST_OK;
+ ossl_statem_set_in_init(s, 0);
+ return WRITE_TRAN_CONTINUE;
}
}
break;
case TLS_ST_OK:
- return tls_finish_handshake(s, wst);
+ return tls_finish_handshake(s, wst, 1);
}
return WORK_FINISHED_CONTINUE;
/*
* Perform any work that needs to be done after sending a message from the
* client to the server.
+ case TLS_ST_SR_CERT_VRFY:
+ return SSL3_RT_MAX_PLAIN_LENGTH;
*/
WORK_STATE ossl_statem_client_post_work(SSL *s, WORK_STATE wst)
{
case TLS_ST_CR_CERT:
return s->max_cert_list;
+ case TLS_ST_CR_CERT_VRFY:
+ return SSL3_RT_MAX_PLAIN_LENGTH;
+
case TLS_ST_CR_CERT_STATUS:
return SSL3_RT_MAX_PLAIN_LENGTH;
case TLS_ST_CR_CERT:
return tls_process_server_certificate(s, pkt);
+ case TLS_ST_CR_CERT_VRFY:
+ return tls_process_cert_verify(s, pkt);
+
case TLS_ST_CR_CERT_STATUS:
return tls_process_cert_status(s, pkt);
case TLS_ST_CR_FINISHED:
return tls_process_finished(s, pkt);
+ case TLS_ST_CR_HELLO_REQ:
+ return tls_process_hello_req(s, pkt);
+
case TLS_ST_CR_ENCRYPTED_EXTENSIONS:
return tls_process_encrypted_extensions(s, pkt);
}
}
/* else use the pre-loaded session */
+ /* This is a real handshake so make sure we clean it up at the end */
+ s->statem.cleanuphand = 1;
+
p = s->s3->client_random;
/*
if (!tls_collect_extensions(s, &extensions, EXT_TLS1_3_CERTIFICATE,
&rawexts, &al)
|| !tls_parse_all_extensions(s, EXT_TLS1_3_CERTIFICATE,
- rawexts, x, chainidx, &al))
+ rawexts, x, chainidx, &al)) {
+ OPENSSL_free(rawexts);
goto f_err;
+ }
+ OPENSSL_free(rawexts);
}
if (!sk_X509_push(sk, x)) {
X509_up_ref(x);
s->session->peer = x;
s->session->verify_result = s->verify_result;
-
x = NULL;
+
+ /* Save the current hash state for when we receive the CertificateVerify */
+ if (SSL_IS_TLS13(s)
+ && !ssl_handshake_hash(s, s->cert_verify_hash,
+ sizeof(s->cert_verify_hash),
+ &s->cert_verify_hash_len)) {
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_SERVER_CERTIFICATE, ERR_R_INTERNAL_ERROR);
+ goto f_err;
+ }
+
ret = MSG_PROCESS_CONTINUE_READING;
goto done;
DH *dh = NULL;
BIGNUM *p = NULL, *g = NULL, *bnpub_key = NULL;
+ int check_bits = 0;
+
if (!PACKET_get_length_prefixed_2(pkt, &prime)
|| !PACKET_get_length_prefixed_2(pkt, &generator)
|| !PACKET_get_length_prefixed_2(pkt, &pub_key)) {
goto err;
}
- if (BN_is_zero(p) || BN_is_zero(g) || BN_is_zero(bnpub_key)) {
+ /* test non-zero pupkey */
+ if (BN_is_zero(bnpub_key)) {
*al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, SSL_R_BAD_DH_VALUE);
goto err;
}
p = g = NULL;
+ if (DH_check_params(dh, &check_bits) == 0 || check_bits != 0) {
+ *al = SSL_AD_DECODE_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, SSL_R_BAD_DH_VALUE);
+ goto err;
+ }
+
if (!DH_set0_key(dh, bnpub_key, NULL)) {
*al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_TLS_PROCESS_SKE_DHE, ERR_R_BN_LIB);
MSG_PROCESS_RETURN tls_process_key_exchange(SSL *s, PACKET *pkt)
{
- int al = -1;
+ int al = -1, ispss = 0;
long alg_k;
EVP_PKEY *pkey = NULL;
+ EVP_MD_CTX *md_ctx = NULL;
+ EVP_PKEY_CTX *pctx = NULL;
PACKET save_param_start, signature;
alg_k = s->s3->tmp.new_cipher->algorithm_mkey;
PACKET params;
int maxsig;
const EVP_MD *md = NULL;
- EVP_MD_CTX *md_ctx;
/*
* |pkt| now points to the beginning of the signature, so the difference
}
if (SSL_USE_SIGALGS(s)) {
- const unsigned char *sigalgs;
+ unsigned int sigalg;
int rv;
- if (!PACKET_get_bytes(pkt, &sigalgs, 2)) {
+
+ if (!PACKET_get_net_2(pkt, &sigalg)) {
al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_LENGTH_TOO_SHORT);
goto err;
}
- rv = tls12_check_peer_sigalg(&md, s, sigalgs, pkey);
+ rv = tls12_check_peer_sigalg(&md, s, sigalg, pkey);
if (rv == -1) {
al = SSL_AD_INTERNAL_ERROR;
goto err;
al = SSL_AD_DECODE_ERROR;
goto err;
}
+ ispss = SIGID_IS_PSS(sigalg);
#ifdef SSL_DEBUG
fprintf(stderr, "USING TLSv1.2 HASH %s\n", EVP_MD_name(md));
#endif
goto err;
}
- if (EVP_VerifyInit_ex(md_ctx, md, NULL) <= 0
- || EVP_VerifyUpdate(md_ctx, &(s->s3->client_random[0]),
- SSL3_RANDOM_SIZE) <= 0
- || EVP_VerifyUpdate(md_ctx, &(s->s3->server_random[0]),
- SSL3_RANDOM_SIZE) <= 0
- || EVP_VerifyUpdate(md_ctx, PACKET_data(¶ms),
- PACKET_remaining(¶ms)) <= 0) {
- EVP_MD_CTX_free(md_ctx);
+ if (EVP_DigestVerifyInit(md_ctx, &pctx, md, NULL, pkey) <= 0) {
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EVP_LIB);
+ goto err;
+ }
+ if (ispss) {
+ if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0
+ /* -1 here means set saltlen to the digest len */
+ || EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx, -1) <= 0) {
+ al = SSL_AD_INTERNAL_ERROR;
+ SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EVP_LIB);
+ goto err;
+ }
+ }
+ if (EVP_DigestVerifyUpdate(md_ctx, &(s->s3->client_random[0]),
+ SSL3_RANDOM_SIZE) <= 0
+ || EVP_DigestVerifyUpdate(md_ctx, &(s->s3->server_random[0]),
+ SSL3_RANDOM_SIZE) <= 0
+ || EVP_DigestVerifyUpdate(md_ctx, PACKET_data(¶ms),
+ PACKET_remaining(¶ms)) <= 0) {
al = SSL_AD_INTERNAL_ERROR;
SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, ERR_R_EVP_LIB);
goto err;
}
- /* TODO(size_t): Convert this call */
- if (EVP_VerifyFinal(md_ctx, PACKET_data(&signature),
- (unsigned int)PACKET_remaining(&signature),
- pkey) <= 0) {
+ if (EVP_DigestVerifyFinal(md_ctx, PACKET_data(&signature),
+ PACKET_remaining(&signature)) <= 0) {
/* bad signature */
- EVP_MD_CTX_free(md_ctx);
al = SSL_AD_DECRYPT_ERROR;
SSLerr(SSL_F_TLS_PROCESS_KEY_EXCHANGE, SSL_R_BAD_SIGNATURE);
goto err;
}
EVP_MD_CTX_free(md_ctx);
+ md_ctx = NULL;
} else {
/* aNULL, aSRP or PSK do not need public keys */
if (!(s->s3->tmp.new_cipher->algorithm_auth & (SSL_aNULL | SSL_aSRP))
if (al != -1)
ssl3_send_alert(s, SSL3_AL_FATAL, al);
ossl_statem_set_error(s);
+ EVP_MD_CTX_free(md_ctx);
return MSG_PROCESS_ERROR;
}
s->s3->tmp.ctype[i] = data[i];
if (SSL_USE_SIGALGS(s)) {
- if (!PACKET_get_net_2(pkt, &list_len)
- || !PACKET_get_bytes(pkt, &data, list_len)) {
+ PACKET sigalgs;
+
+ if (!PACKET_get_length_prefixed_2(pkt, &sigalgs)) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
SSL_R_LENGTH_MISMATCH);
s->s3->tmp.md[i] = NULL;
s->s3->tmp.valid_flags[i] = 0;
}
- if ((list_len & 1) || !tls1_save_sigalgs(s, data, list_len)) {
+ if (!tls1_save_sigalgs(s, &sigalgs)) {
ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
SSLerr(SSL_F_TLS_PROCESS_CERTIFICATE_REQUEST,
SSL_R_SIGNATURE_ALGORITHMS_ERROR);
{
int al;
unsigned int ticklen;
- unsigned long ticket_lifetime_hint;
+ unsigned long ticket_lifetime_hint, add_age;
unsigned int sess_len;
+ RAW_EXTENSION *exts = NULL;
if (!PACKET_get_net_4(pkt, &ticket_lifetime_hint)
+ || (SSL_IS_TLS13(s) && !PACKET_get_net_4(pkt, &add_age))
|| !PACKET_get_net_2(pkt, &ticklen)
- || PACKET_remaining(pkt) != ticklen) {
+ || (!SSL_IS_TLS13(s) && PACKET_remaining(pkt) != ticklen)
+ || (SSL_IS_TLS13(s) && (ticklen == 0
+ || PACKET_remaining(pkt) < ticklen))) {
al = SSL_AD_DECODE_ERROR;
SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, SSL_R_LENGTH_MISMATCH);
goto f_err;
}
- /* Server is allowed to change its mind and send an empty ticket. */
+ /*
+ * Server is allowed to change its mind (in <=TLSv1.2) and send an empty
+ * ticket. We already checked this TLSv1.3 case above, so it should never
+ * be 0 here in that instance
+ */
if (ticklen == 0)
return MSG_PROCESS_CONTINUE_READING;
+ /* TODO(TLS1.3): Is this a suitable test for TLS1.3? */
if (s->session->session_id_length > 0) {
int i = s->session_ctx->session_cache_mode;
SSL_SESSION *new_sess;
s->session->ext.tick_lifetime_hint = ticket_lifetime_hint;
s->session->ext.ticklen = ticklen;
+
+ if (SSL_IS_TLS13(s)) {
+ PACKET extpkt;
+
+ if (!PACKET_as_length_prefixed_2(pkt, &extpkt)
+ || !tls_collect_extensions(s, &extpkt,
+ EXT_TLS1_3_NEW_SESSION_TICKET,
+ &exts, &al)
+ || !tls_parse_all_extensions(s, EXT_TLS1_3_NEW_SESSION_TICKET,
+ exts, NULL, 0, &al)) {
+ SSLerr(SSL_F_TLS_PROCESS_NEW_SESSION_TICKET, SSL_R_BAD_EXTENSION);
+ goto f_err;
+ }
+ }
+
/*
* There are two ways to detect a resumed ticket session. One is to set
* an appropriate session ID and then the server must return a match in
goto err;
}
s->session->session_id_length = sess_len;
+
+ /* This is a standalone message in TLSv1.3, so there is no more to read */
+ if (SSL_IS_TLS13(s)) {
+ ssl_update_cache(s, SSL_SESS_CACHE_CLIENT);
+ return MSG_PROCESS_FINISHED_READING;
+ }
+
return MSG_PROCESS_CONTINUE_READING;
f_err:
ssl3_send_alert(s, SSL3_AL_FATAL, al);
return 1;
}
-
+
MSG_PROCESS_RETURN tls_process_cert_status(SSL *s, PACKET *pkt)
{
s->s3->tmp.pms = pms;
s->s3->tmp.pmslen = pmslen;
+ /* Log the premaster secret, if logging is enabled. */
+ if (!ssl_log_rsa_client_key_exchange(s, encdata, enclen, pms, pmslen))
+ goto err;
+
return 1;
err:
OPENSSL_clear_free(pms, pmslen);
}
#endif
+MSG_PROCESS_RETURN tls_process_hello_req(SSL *s, PACKET *pkt)
+{
+ if (PACKET_remaining(pkt) > 0) {
+ /* should contain no data */
+ SSLerr(SSL_F_TLS_PROCESS_HELLO_REQ, SSL_R_LENGTH_MISMATCH);
+ ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ ossl_statem_set_error(s);
+ return MSG_PROCESS_ERROR;
+ }
+
+ /*
+ * This is a historical discrepancy maintained for compatibility
+ * reasons. If a TLS client receives a HelloRequest it will attempt
+ * an abbreviated handshake. However if a DTLS client receives a
+ * HelloRequest it will do a full handshake.
+ */
+ if (SSL_IS_DTLS(s))
+ SSL_renegotiate(s);
+ else
+ SSL_renegotiate_abbreviated(s);
+
+ return MSG_PROCESS_FINISHED_READING;
+}
+
static MSG_PROCESS_RETURN tls_process_encrypted_extensions(SSL *s, PACKET *pkt)
{
int al = SSL_AD_INTERNAL_ERROR;