#include <openssl/evp.h>
#include <openssl/x509.h>
+/* Fixed value used in the ServerHello random field to identify an HRR */
+const unsigned char hrrrandom[] = {
+ 0xcf, 0x21, 0xad, 0x74, 0xe5, 0x9a, 0x61, 0x11, 0xbe, 0x1d, 0x8c, 0x02,
+ 0x1e, 0x65, 0xb8, 0x91, 0xc2, 0xa2, 0x11, 0x16, 0x7a, 0xbb, 0x8c, 0x5e,
+ 0x07, 0x9e, 0x09, 0xe2, 0xc8, 0xa8, 0x33, 0x9c
+};
+
/*
* send s->init_buf in records of type 'type' (SSL3_RT_HANDSHAKE or
* SSL3_RT_CHANGE_CIPHER_SPEC)
const SIGALG_LOOKUP *lu = s->s3->tmp.sigalg;
if (lu == NULL || s->s3->tmp.cert == NULL) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
pkey = s->s3->tmp.cert->privatekey;
if (pkey == NULL || !tls1_lookup_md(lu, &md)) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
mctx = EVP_MD_CTX_new();
if (mctx == NULL) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_MALLOC_FAILURE);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+ ERR_R_MALLOC_FAILURE);
goto err;
}
}
if (SSL_USE_SIGALGS(s) && !WPACKET_put_bytes_u16(pkt, lu->sigalg)) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
siglen = EVP_PKEY_size(pkey);
sig = OPENSSL_malloc(siglen);
if (sig == NULL) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_MALLOC_FAILURE);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+ ERR_R_MALLOC_FAILURE);
goto err;
}
if (EVP_DigestSignInit(mctx, &pctx, md, NULL, pkey) <= 0) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_EVP_LIB);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+ ERR_R_EVP_LIB);
goto err;
}
if (EVP_PKEY_CTX_set_rsa_padding(pctx, RSA_PKCS1_PSS_PADDING) <= 0
|| EVP_PKEY_CTX_set_rsa_pss_saltlen(pctx,
RSA_PSS_SALTLEN_DIGEST) <= 0) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_EVP_LIB);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+ ERR_R_EVP_LIB);
goto err;
}
}
s->session->master_key)
|| EVP_DigestSignFinal(mctx, sig, &siglen) <= 0) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_EVP_LIB);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+ ERR_R_EVP_LIB);
goto err;
}
} else if (EVP_DigestSign(mctx, sig, &siglen, hdata, hdatalen) <= 0) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_EVP_LIB);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+ ERR_R_EVP_LIB);
goto err;
}
#endif
if (!WPACKET_sub_memcpy_u16(pkt, sig, siglen)) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CERT_VERIFY, ERR_R_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_CERT_VERIFY,
+ ERR_R_INTERNAL_ERROR);
goto err;
}
/* Digest cached records and discard handshake buffer */
- if (!ssl3_digest_cached_records(s, 0))
+ if (!ssl3_digest_cached_records(s, 0)) {
+ /* SSLfatal() already called */
goto err;
+ }
OPENSSL_free(sig);
EVP_MD_CTX_free(mctx);
err:
OPENSSL_free(sig);
EVP_MD_CTX_free(mctx);
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
return 0;
}
&& !s->server
&& s->s3->tmp.cert_req == 0
&& (!s->method->ssl3_enc->change_cipher_state(s,
- SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_CLIENT_WRITE))) {
- SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, SSL_R_CANNOT_CHANGE_CIPHER);
- /*
- * This is a fatal error, which leaves
- * enc_write_ctx in an inconsistent state
- * and thus ssl3_send_alert may crash.
- */
+ SSL3_CC_HANDSHAKE | SSL3_CHANGE_CIPHER_CLIENT_WRITE))) {;
+ /* SSLfatal() already called */
return 0;
}
sender, slen,
s->s3->tmp.finish_md);
if (finish_md_len == 0) {
- SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR);
- goto err;
+ /* SSLfatal() already called */
+ return 0;
}
s->s3->tmp.finish_md_len = finish_md_len;
if (!WPACKET_memcpy(pkt, s->s3->tmp.finish_md, finish_md_len)) {
- SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR);
- goto err;
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_FINISHED,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
}
/*
if (!SSL_IS_TLS13(s) && !ssl_log_secret(s, MASTER_SECRET_LABEL,
s->session->master_key,
s->session->master_key_length)) {
- SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR);
- goto err;
+ /* SSLfatal() already called */
+ return 0;
}
/*
* Copy the finished so we can use it for renegotiation checks
*/
if (!ossl_assert(finish_md_len <= EVP_MAX_MD_SIZE)) {
- SSLerr(SSL_F_TLS_CONSTRUCT_FINISHED, ERR_R_INTERNAL_ERROR);
- goto err;
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_FINISHED,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
}
if (!s->server) {
memcpy(s->s3->previous_client_finished, s->s3->tmp.finish_md,
}
return 1;
- err:
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return 0;
}
int tls_construct_key_update(SSL *s, WPACKET *pkt)
{
if (!WPACKET_put_bytes_u8(pkt, s->key_update)) {
- SSLerr(SSL_F_TLS_CONSTRUCT_KEY_UPDATE, ERR_R_INTERNAL_ERROR);
- goto err;
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR, SSL_F_TLS_CONSTRUCT_KEY_UPDATE,
+ ERR_R_INTERNAL_ERROR);
+ return 0;
}
s->key_update = SSL_KEY_UPDATE_NONE;
return 1;
-
- err:
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- return 0;
}
MSG_PROCESS_RETURN tls_process_key_update(SSL *s, PACKET *pkt)
int tls_construct_change_cipher_spec(SSL *s, WPACKET *pkt)
{
if (!WPACKET_put_bytes_u8(pkt, SSL3_MT_CCS)) {
- SSLerr(SSL_F_TLS_CONSTRUCT_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ SSLfatal(s, SSL_AD_INTERNAL_ERROR,
+ SSL_F_TLS_CONSTRUCT_CHANGE_CIPHER_SPEC, ERR_R_INTERNAL_ERROR);
return 0;
}
* in NBIO events. If |clearbufs| is set then init_buf and the wbio buffer is
* freed up as well.
*/
-WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs)
+WORK_STATE tls_finish_handshake(SSL *s, WORK_STATE wst, int clearbufs, int stop)
{
int discard;
void (*cb) (const SSL *ssl, int type, int val) = NULL;
}
}
- /*
- * If we've not cleared the buffers its because we've got more work to do,
- * so continue.
- */
- if (!clearbufs)
+ if (!stop)
return WORK_FINISHED_CONTINUE;
ossl_statem_set_in_init(s, 0);
int tls_get_message_header(SSL *s, int *mt)
{
/* s->init_num < SSL3_HM_HEADER_LENGTH */
- int skip_message, i, recvd_type, al;
+ int skip_message, i, recvd_type;
unsigned char *p;
size_t l, readbytes;
* in the middle of a handshake message.
*/
if (s->init_num != 0 || readbytes != 1 || p[0] != SSL3_MT_CCS) {
- al = SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER,
- SSL_R_BAD_CHANGE_CIPHER_SPEC);
- goto f_err;
+ SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+ SSL_F_TLS_GET_MESSAGE_HEADER,
+ SSL_R_BAD_CHANGE_CIPHER_SPEC);
+ return 0;
+ }
+ if (s->statem.hand_state == TLS_ST_BEFORE
+ && (s->s3->flags & TLS1_FLAGS_STATELESS) != 0) {
+ /*
+ * We are stateless and we received a CCS. Probably this is
+ * from a client between the first and second ClientHellos.
+ * We should ignore this, but return an error because we do
+ * not return success until we see the second ClientHello
+ * with a valid cookie.
+ */
+ return 0;
}
s->s3->tmp.message_type = *mt = SSL3_MT_CHANGE_CIPHER_SPEC;
s->init_num = readbytes - 1;
s->s3->tmp.message_size = readbytes;
return 1;
} else if (recvd_type != SSL3_RT_HANDSHAKE) {
- al = SSL_AD_UNEXPECTED_MESSAGE;
- SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, SSL_R_CCS_RECEIVED_EARLY);
- goto f_err;
+ SSLfatal(s, SSL_AD_UNEXPECTED_MESSAGE,
+ SSL_F_TLS_GET_MESSAGE_HEADER,
+ SSL_R_CCS_RECEIVED_EARLY);
+ return 0;
}
s->init_num += readbytes;
}
n2l3(p, l);
/* BUF_MEM_grow takes an 'int' parameter */
if (l > (INT_MAX - SSL3_HM_HEADER_LENGTH)) {
- al = SSL_AD_ILLEGAL_PARAMETER;
- SSLerr(SSL_F_TLS_GET_MESSAGE_HEADER, SSL_R_EXCESSIVE_MESSAGE_SIZE);
- goto f_err;
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER, SSL_F_TLS_GET_MESSAGE_HEADER,
+ SSL_R_EXCESSIVE_MESSAGE_SIZE);
+ return 0;
}
s->s3->tmp.message_size = l;
}
return 1;
- f_err:
- ssl3_send_alert(s, SSL3_AL_FATAL, al);
- return 0;
}
int tls_get_message_body(SSL *s, size_t *len)
if (RECORD_LAYER_is_sslv2_record(&s->rlayer)) {
if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
s->init_num)) {
- SSLerr(SSL_F_TLS_GET_MESSAGE_BODY, ERR_R_EVP_LIB);
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
+ /* SSLfatal() already called */
*len = 0;
return 0;
}
* We defer feeding in the HRR until later. We'll do it as part of
* processing the message
*/
- if (s->s3->tmp.message_type != SSL3_MT_HELLO_RETRY_REQUEST
- && !ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
- s->init_num + SSL3_HM_HEADER_LENGTH)) {
- SSLerr(SSL_F_TLS_GET_MESSAGE_BODY, ERR_R_EVP_LIB);
- ssl3_send_alert(s, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
- *len = 0;
- return 0;
+#define SERVER_HELLO_RANDOM_OFFSET (SSL3_HM_HEADER_LENGTH + 2)
+ if (s->s3->tmp.message_type != SSL3_MT_SERVER_HELLO
+ || s->init_num < SERVER_HELLO_RANDOM_OFFSET + SSL3_RANDOM_SIZE
+ || memcmp(hrrrandom,
+ s->init_buf->data + SERVER_HELLO_RANDOM_OFFSET,
+ SSL3_RANDOM_SIZE) != 0) {
+ if (!ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+ s->init_num + SSL3_HM_HEADER_LENGTH)) {
+ /* SSLfatal() already called */
+ *len = 0;
+ return 0;
+ }
}
if (s->msg_callback)
s->msg_callback(0, s->version, SSL3_RT_HANDSHAKE, s->init_buf->data,
suppversions = &hello->pre_proc_exts[TLSEXT_IDX_supported_versions];
+ /* If we did an HRR then supported versions is mandatory */
+ if (!suppversions->present && s->hello_retry_request != SSL_HRR_NONE)
+ return SSL_R_UNSUPPORTED_PROTOCOL;
+
if (suppversions->present && !SSL_IS_DTLS(s)) {
unsigned int candidate_vers = 0;
unsigned int best_vers = 0;
}
if (best_vers > 0) {
- if (SSL_IS_TLS13(s)) {
+ if (s->hello_retry_request != SSL_HRR_NONE) {
/*
- * We get here if this is after a HelloRetryRequest. In this
- * case we just check that we still negotiated TLSv1.3
+ * This is after a HelloRetryRequest so we better check that we
+ * negotiated TLSv1.3
*/
if (best_vers != TLS1_3_VERSION)
return SSL_R_UNSUPPORTED_PROTOCOL;
*
* @s: client SSL handle.
* @version: The proposed version from the server's HELLO.
- * @checkdgrd: Whether to check the downgrade sentinels in the server_random
- * @al: Where to store any alert value that may be generated
+ * @extensions: The extensions received
*
- * Returns 0 on success or an SSL error reason number on failure.
+ * Returns 1 on success or 0 on error.
*/
-int ssl_choose_client_version(SSL *s, int version, int checkdgrd, int *al)
+int ssl_choose_client_version(SSL *s, int version, RAW_EXTENSION *extensions)
{
const version_info *vent;
const version_info *table;
int highver = 0;
+ int origv;
+
+ origv = s->version;
+ s->version = version;
- /* TODO(TLS1.3): Remove this before release */
- if (version == TLS1_3_VERSION_DRAFT)
- version = TLS1_3_VERSION;
+ /* This will overwrite s->version if the extension is present */
+ if (!tls_parse_extension(s, TLSEXT_IDX_supported_versions,
+ SSL_EXT_TLS1_2_SERVER_HELLO
+ | SSL_EXT_TLS1_3_SERVER_HELLO, extensions,
+ NULL, 0)) {
+ s->version = origv;
+ return 0;
+ }
- if (s->hello_retry_request && version != TLS1_3_VERSION) {
- *al = SSL_AD_PROTOCOL_VERSION;
- return SSL_R_WRONG_SSL_VERSION;
+ if (s->hello_retry_request != SSL_HRR_NONE
+ && s->version != TLS1_3_VERSION) {
+ s->version = origv;
+ SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_F_SSL_CHOOSE_CLIENT_VERSION,
+ SSL_R_WRONG_SSL_VERSION);
+ return 0;
}
switch (s->method->version) {
default:
- if (version != s->version) {
- *al = SSL_AD_PROTOCOL_VERSION;
- return SSL_R_WRONG_SSL_VERSION;
+ if (s->version != s->method->version) {
+ s->version = origv;
+ SSLfatal(s, SSL_AD_PROTOCOL_VERSION,
+ SSL_F_SSL_CHOOSE_CLIENT_VERSION,
+ SSL_R_WRONG_SSL_VERSION);
+ return 0;
}
/*
* If this SSL handle is not from a version flexible method we don't
* versions they don't want. If not, then easy to fix, just return
* ssl_method_error(s, s->method)
*/
- return 0;
+ return 1;
case TLS_ANY_VERSION:
table = tls_version_table;
break;
if (vent->cmeth == NULL)
continue;
- if (highver != 0 && version != vent->version)
+ if (highver != 0 && s->version != vent->version)
continue;
method = vent->cmeth();
err = ssl_method_error(s, method);
if (err != 0) {
- if (version == vent->version) {
- *al = SSL_AD_PROTOCOL_VERSION;
- return err;
+ if (s->version == vent->version) {
+ s->version = origv;
+ SSLfatal(s, SSL_AD_PROTOCOL_VERSION,
+ SSL_F_SSL_CHOOSE_CLIENT_VERSION, err);
+ return 0;
}
continue;
if (highver == 0)
highver = vent->version;
- if (version != vent->version)
+ if (s->version != vent->version)
continue;
#ifndef OPENSSL_NO_TLS13DOWNGRADE
/* Check for downgrades */
- if (checkdgrd) {
- if (version == TLS1_2_VERSION && highver > version) {
- if (memcmp(tls12downgrade,
- s->s3->server_random + SSL3_RANDOM_SIZE
- - sizeof(tls12downgrade),
- sizeof(tls12downgrade)) == 0) {
- *al = SSL_AD_ILLEGAL_PARAMETER;
- return SSL_R_INAPPROPRIATE_FALLBACK;
- }
- } else if (!SSL_IS_DTLS(s)
- && version < TLS1_2_VERSION
- && highver > version) {
- if (memcmp(tls11downgrade,
- s->s3->server_random + SSL3_RANDOM_SIZE
- - sizeof(tls11downgrade),
- sizeof(tls11downgrade)) == 0) {
- *al = SSL_AD_ILLEGAL_PARAMETER;
- return SSL_R_INAPPROPRIATE_FALLBACK;
- }
+ if (s->version == TLS1_2_VERSION && highver > s->version) {
+ if (memcmp(tls12downgrade,
+ s->s3->server_random + SSL3_RANDOM_SIZE
+ - sizeof(tls12downgrade),
+ sizeof(tls12downgrade)) == 0) {
+ s->version = origv;
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+ SSL_F_SSL_CHOOSE_CLIENT_VERSION,
+ SSL_R_INAPPROPRIATE_FALLBACK);
+ return 0;
+ }
+ } else if (!SSL_IS_DTLS(s)
+ && s->version < TLS1_2_VERSION
+ && highver > s->version) {
+ if (memcmp(tls11downgrade,
+ s->s3->server_random + SSL3_RANDOM_SIZE
+ - sizeof(tls11downgrade),
+ sizeof(tls11downgrade)) == 0) {
+ s->version = origv;
+ SSLfatal(s, SSL_AD_ILLEGAL_PARAMETER,
+ SSL_F_SSL_CHOOSE_CLIENT_VERSION,
+ SSL_R_INAPPROPRIATE_FALLBACK);
+ return 0;
}
}
#endif
s->method = method;
- s->version = version;
- return 0;
+ return 1;
}
- *al = SSL_AD_PROTOCOL_VERSION;
- return SSL_R_UNSUPPORTED_PROTOCOL;
+ s->version = origv;
+ SSLfatal(s, SSL_AD_PROTOCOL_VERSION, SSL_F_SSL_CHOOSE_CLIENT_VERSION,
+ SSL_R_UNSUPPORTED_PROTOCOL);
+ return 0;
}
/*
#endif
/* Replace ClientHello1 in the transcript hash with a synthetic message */
-int create_synthetic_message_hash(SSL *s)
+int create_synthetic_message_hash(SSL *s, const unsigned char *hashval,
+ size_t hashlen, const unsigned char *hrr,
+ size_t hrrlen)
{
- unsigned char hashval[EVP_MAX_MD_SIZE];
- size_t hashlen = 0;
+ unsigned char hashvaltmp[EVP_MAX_MD_SIZE];
unsigned char msghdr[SSL3_HM_HEADER_LENGTH];
memset(msghdr, 0, sizeof(msghdr));
- /* Get the hash of the initial ClientHello */
- if (!ssl3_digest_cached_records(s, 0)
- || !ssl_handshake_hash(s, hashval, sizeof(hashval), &hashlen)) {
- /* SSLfatal() already called */
- return 0;
+ if (hashval == NULL) {
+ hashval = hashvaltmp;
+ hashlen = 0;
+ /* Get the hash of the initial ClientHello */
+ if (!ssl3_digest_cached_records(s, 0)
+ || !ssl_handshake_hash(s, hashvaltmp, sizeof(hashvaltmp),
+ &hashlen)) {
+ /* SSLfatal() already called */
+ return 0;
+ }
}
/* Reinitialise the transcript hash */
return 0;
}
+ /*
+ * Now re-inject the HRR and current message if appropriate (we just deleted
+ * it when we reinitialised the transcript hash above). Only necessary after
+ * receiving a ClientHello2 with a cookie.
+ */
+ if (hrr != NULL
+ && (!ssl3_finish_mac(s, hrr, hrrlen)
+ || !ssl3_finish_mac(s, (unsigned char *)s->init_buf->data,
+ s->s3->tmp.message_size
+ + SSL3_HM_HEADER_LENGTH))) {
+ /* SSLfatal() already called */
+ return 0;
+ }
+
return 1;
}