Moving transcript and PRF functions to SSL_TRANSCRIPT.
Change-Id: I98903df561bbf8c5739f892d2ad5e89ac0eb8e6f
Reviewed-on: https://boringssl-review.googlesource.com/13369
Reviewed-by: Steven Valdez <svaldez@google.com>
Reviewed-by: David Benjamin <davidben@google.com>
Commit-Queue: David Benjamin <davidben@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/CMakeLists.txt b/ssl/CMakeLists.txt
index 9b45d6e..5b5ea97 100644
--- a/ssl/CMakeLists.txt
+++ b/ssl/CMakeLists.txt
@@ -14,7 +14,6 @@
handshake_client.c
handshake_server.c
s3_both.c
- s3_enc.c
s3_lib.c
s3_pkt.c
ssl_aead_ctx.c
@@ -29,6 +28,7 @@
ssl_privkey_cc.cc
ssl_session.c
ssl_stat.c
+ ssl_transcript.c
ssl_x509.c
t1_enc.c
t1_lib.c
diff --git a/ssl/d1_both.c b/ssl/d1_both.c
index 48a5c54..b864e42 100644
--- a/ssl/d1_both.c
+++ b/ssl/d1_both.c
@@ -549,7 +549,14 @@
}
if (!is_ccs) {
- ssl3_update_handshake_hash(ssl, data, len);
+ /* TODO(svaldez): Move this up a layer to fix abstraction for SSL_TRANSCRIPT
+ * on hs. */
+ if (ssl->s3->hs != NULL &&
+ !SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, data, len)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ OPENSSL_free(data);
+ return 0;
+ }
ssl->d1->handshake_write_seq++;
}
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index ad0f06a..66c0142 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -399,7 +399,7 @@
* record the handshake hashes at this point in the session so that
* any resumption of this session with ChannelID can sign those
* hashes. */
- ret = tls1_record_handshake_hashes_for_channel_id(ssl);
+ ret = tls1_record_handshake_hashes_for_channel_id(hs);
if (ret <= 0) {
goto end;
}
@@ -732,7 +732,7 @@
/* Now that the length prefixes have been computed, fill in the placeholder
* PSK binder. */
if (hs->needs_psk_binder &&
- !tls13_write_psk_binder(ssl, msg, len)) {
+ !tls13_write_psk_binder(hs, msg, len)) {
OPENSSL_free(msg);
goto err;
}
@@ -748,7 +748,7 @@
SSL *const ssl = hs->ssl;
/* The handshake buffer is reset on every ClientHello. Notably, in DTLS, we
* may send multiple ClientHellos if we receive HelloVerifyRequest. */
- if (!ssl3_init_handshake_buffer(ssl)) {
+ if (!SSL_TRANSCRIPT_init(&hs->transcript)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return -1;
}
@@ -819,9 +819,6 @@
return 1;
}
- /* The handshake transcript is reset on HelloVerifyRequst, so do not bother
- * hashing it. */
-
CBS_init(&hello_verify_request, ssl->init_msg, ssl->init_num);
if (!CBS_get_u16(&hello_verify_request, &server_version) ||
!CBS_get_u8_length_prefixed(&hello_verify_request, &cookie) ||
@@ -897,8 +894,6 @@
assert(ssl->s3->have_version == ssl->s3->initial_handshake_complete);
if (!ssl->s3->have_version) {
ssl->version = server_wire_version;
- ssl->s3->enc_method = ssl3_get_enc_method(server_version);
- assert(ssl->s3->enc_method != NULL);
/* At this point, the connection's version is known and ssl->version is
* fixed. Begin enforcing the record-layer version. */
ssl->s3->have_version = 1;
@@ -999,8 +994,9 @@
/* Now that the cipher is known, initialize the handshake hash and hash the
* ServerHello. */
- if (!ssl3_init_handshake_hash(ssl) ||
- !ssl_hash_current_message(ssl)) {
+ if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(ssl),
+ c->algorithm_prf) ||
+ !ssl_hash_current_message(hs)) {
goto f_err;
}
@@ -1009,7 +1005,7 @@
* buffer may be released. */
if (ssl->session != NULL ||
!ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) {
- ssl3_free_handshake_buffer(ssl);
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
}
/* Only the NULL compression algorithm is supported. */
@@ -1061,7 +1057,7 @@
}
if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
- !ssl_hash_current_message(ssl)) {
+ !ssl_hash_current_message(hs)) {
return -1;
}
@@ -1115,7 +1111,7 @@
return 1;
}
- if (!ssl_hash_current_message(ssl)) {
+ if (!ssl_hash_current_message(hs)) {
return -1;
}
@@ -1177,7 +1173,7 @@
return 1;
}
- if (!ssl_hash_current_message(ssl)) {
+ if (!ssl_hash_current_message(hs)) {
return -1;
}
@@ -1403,12 +1399,12 @@
ssl->s3->tmp.reuse_message = 1;
/* If we get here we don't need the handshake buffer as we won't be doing
* client auth. */
- ssl3_free_handshake_buffer(ssl);
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
return 1;
}
if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_REQUEST) ||
- !ssl_hash_current_message(ssl)) {
+ !ssl_hash_current_message(hs)) {
return -1;
}
@@ -1467,7 +1463,7 @@
}
if (!ssl_check_message_type(ssl, SSL3_MT_SERVER_HELLO_DONE) ||
- !ssl_hash_current_message(ssl)) {
+ !ssl_hash_current_message(hs)) {
return -1;
}
@@ -1499,7 +1495,7 @@
if (!ssl_has_certificate(ssl)) {
/* Without a client certificate, the handshake buffer may be released. */
- ssl3_free_handshake_buffer(ssl);
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
/* In SSL 3.0, the Certificate message is replaced with a warning alert. */
if (ssl->version == SSL3_VERSION) {
@@ -1680,9 +1676,8 @@
goto err;
}
- ssl->s3->new_session->master_key_length =
- tls1_generate_master_secret(ssl, ssl->s3->new_session->master_key, pms,
- pms_len);
+ ssl->s3->new_session->master_key_length = tls1_generate_master_secret(
+ hs, ssl->s3->new_session->master_key, pms, pms_len);
if (ssl->s3->new_session->master_key_length == 0) {
goto err;
}
@@ -1743,11 +1738,11 @@
goto err;
}
- const EVP_MD *md;
uint8_t digest[EVP_MAX_MD_SIZE];
size_t digest_len;
- if (!ssl3_cert_verify_hash(ssl, &md, digest, &digest_len,
- signature_algorithm)) {
+ if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(
+ &hs->transcript, digest, &digest_len, ssl->s3->new_session,
+ signature_algorithm)) {
goto err;
}
@@ -1756,7 +1751,6 @@
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(ssl->cert->privatekey, NULL);
if (pctx == NULL ||
!EVP_PKEY_sign_init(pctx) ||
- !EVP_PKEY_CTX_set_signature_md(pctx, md) ||
!EVP_PKEY_sign(pctx, ptr, &sig_len, digest, digest_len)) {
EVP_PKEY_CTX_free(pctx);
sign_result = ssl_private_key_failure;
@@ -1766,12 +1760,12 @@
} else {
sign_result = ssl_private_key_sign(
ssl, ptr, &sig_len, max_sig_len, signature_algorithm,
- (const uint8_t *)ssl->s3->handshake_buffer->data,
- ssl->s3->handshake_buffer->length);
+ (const uint8_t *)hs->transcript.buffer->data,
+ hs->transcript.buffer->length);
}
/* The handshake buffer is no longer necessary. */
- ssl3_free_handshake_buffer(ssl);
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
} else {
assert(hs->state == SSL3_ST_CW_CERT_VRFY_B);
sign_result = ssl_private_key_complete(ssl, ptr, &sig_len, max_sig_len);
@@ -1834,7 +1828,7 @@
CBB cbb, body;
if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
- !tls1_write_channel_id(ssl, &body) ||
+ !tls1_write_channel_id(hs, &body) ||
!ssl_add_message_cbb(ssl, &cbb)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
CBB_cleanup(&cbb);
@@ -1852,7 +1846,7 @@
}
if (!ssl_check_message_type(ssl, SSL3_MT_NEW_SESSION_TICKET) ||
- !ssl_hash_current_message(ssl)) {
+ !ssl_hash_current_message(hs)) {
return -1;
}
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c
index 6ebfce4..5e921b6 100644
--- a/ssl/handshake_server.c
+++ b/ssl/handshake_server.c
@@ -218,13 +218,6 @@
case SSL_ST_ACCEPT:
ssl_do_info_callback(ssl, SSL_CB_HANDSHAKE_START, 1);
-
- if (!ssl3_init_handshake_buffer(ssl)) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- ret = -1;
- goto end;
- }
-
hs->state = SSL3_ST_SR_CLNT_HELLO_A;
break;
@@ -421,7 +414,7 @@
* hashes in |ssl->s3->new_session| in case we need them to verify a
* ChannelID signature on a resumption of this session in the future. */
if (ssl->session == NULL && ssl->s3->tlsext_channel_id_valid) {
- ret = tls1_record_handshake_hashes_for_channel_id(ssl);
+ ret = tls1_record_handshake_hashes_for_channel_id(hs);
if (ret <= 0) {
goto end;
}
@@ -654,8 +647,6 @@
hs->client_version = client_hello->version;
ssl->version = ssl->method->version_to_wire(version);
- ssl->s3->enc_method = ssl3_get_enc_method(version);
- assert(ssl->s3->enc_method != NULL);
/* At this point, the connection's version is known and |ssl->version| is
* fixed. Begin enforcing the record-layer version. */
@@ -1053,14 +1044,15 @@
/* Now that all parameters are known, initialize the handshake hash and hash
* the ClientHello. */
- if (!ssl3_init_handshake_hash(ssl) ||
- !ssl_hash_current_message(ssl)) {
+ if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(ssl),
+ ssl->s3->tmp.new_cipher->algorithm_prf) ||
+ !ssl_hash_current_message(hs)) {
goto f_err;
}
/* Release the handshake buffer if client authentication isn't required. */
if (!hs->cert_request) {
- ssl3_free_handshake_buffer(ssl);
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
}
ret = 1;
@@ -1457,7 +1449,7 @@
return -1;
}
- if (!ssl_hash_current_message(ssl)) {
+ if (!ssl_hash_current_message(hs)) {
return -1;
}
@@ -1488,7 +1480,7 @@
if (sk_CRYPTO_BUFFER_num(ssl->s3->new_session->certs) == 0) {
/* No client certificate so the handshake buffer may be discarded. */
- ssl3_free_handshake_buffer(ssl);
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
/* In SSL 3.0, sending no certificate is signaled by omitting the
* Certificate message. */
@@ -1543,7 +1535,7 @@
}
if (!ssl_check_message_type(ssl, SSL3_MT_CLIENT_KEY_EXCHANGE) ||
- !ssl_hash_current_message(ssl)) {
+ !ssl_hash_current_message(hs)) {
return -1;
}
}
@@ -1771,9 +1763,9 @@
}
/* Compute the master secret */
- ssl->s3->new_session->master_key_length = tls1_generate_master_secret(
- ssl, ssl->s3->new_session->master_key, premaster_secret,
- premaster_secret_len);
+ ssl->s3->new_session->master_key_length =
+ tls1_generate_master_secret(hs, ssl->s3->new_session->master_key,
+ premaster_secret, premaster_secret_len);
if (ssl->s3->new_session->master_key_length == 0) {
goto err;
}
@@ -1805,7 +1797,7 @@
* CertificateVerify is required if and only if there's a client certificate.
* */
if (hs->peer_pubkey == NULL) {
- ssl3_free_handshake_buffer(ssl);
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
return 1;
}
@@ -1854,26 +1846,25 @@
/* The SSL3 construction for CertificateVerify does not decompose into a
* single final digest and signature, and must be special-cased. */
if (ssl3_protocol_version(ssl) == SSL3_VERSION) {
- const EVP_MD *md;
uint8_t digest[EVP_MAX_MD_SIZE];
size_t digest_len;
- if (!ssl3_cert_verify_hash(ssl, &md, digest, &digest_len,
- signature_algorithm)) {
+ if (!SSL_TRANSCRIPT_ssl3_cert_verify_hash(&hs->transcript, digest,
+ &digest_len, ssl->s3->new_session,
+ signature_algorithm)) {
goto err;
}
EVP_PKEY_CTX *pctx = EVP_PKEY_CTX_new(hs->peer_pubkey, NULL);
sig_ok = pctx != NULL &&
EVP_PKEY_verify_init(pctx) &&
- EVP_PKEY_CTX_set_signature_md(pctx, md) &&
EVP_PKEY_verify(pctx, CBS_data(&signature), CBS_len(&signature),
digest, digest_len);
EVP_PKEY_CTX_free(pctx);
} else {
sig_ok = ssl_public_key_verify(
ssl, CBS_data(&signature), CBS_len(&signature), signature_algorithm,
- hs->peer_pubkey, (const uint8_t *)ssl->s3->handshake_buffer->data,
- ssl->s3->handshake_buffer->length);
+ hs->peer_pubkey, (const uint8_t *)hs->transcript.buffer->data,
+ hs->transcript.buffer->length);
}
#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
@@ -1888,8 +1879,8 @@
/* The handshake buffer is no longer necessary, and we may hash the current
* message.*/
- ssl3_free_handshake_buffer(ssl);
- if (!ssl_hash_current_message(ssl)) {
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
+ if (!ssl_hash_current_message(hs)) {
goto err;
}
@@ -1911,7 +1902,7 @@
}
if (!ssl_check_message_type(ssl, SSL3_MT_NEXT_PROTO) ||
- !ssl_hash_current_message(ssl)) {
+ !ssl_hash_current_message(hs)) {
return -1;
}
@@ -1942,8 +1933,8 @@
}
if (!ssl_check_message_type(ssl, SSL3_MT_CHANNEL_ID) ||
- !tls1_verify_channel_id(ssl) ||
- !ssl_hash_current_message(ssl)) {
+ !tls1_verify_channel_id(hs) ||
+ !ssl_hash_current_message(hs)) {
return -1;
}
return 1;
diff --git a/ssl/internal.h b/ssl/internal.h
index 18ef26a..06bdd04 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -220,10 +220,9 @@
const SSL_CIPHER *cipher, uint16_t version);
/* ssl_get_handshake_digest returns the |EVP_MD| corresponding to
- * |algorithm_prf|. It returns SHA-1 for |SSL_HANDSHAKE_DEFAULT|. The caller is
- * responsible for maintaining the additional MD5 digest and switching to
- * SHA-256 in TLS 1.2. */
-const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf);
+ * |algorithm_prf| and the |version|. */
+const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf,
+ uint16_t version);
/* ssl_create_cipher_list evaluates |rule_str| according to the ciphers in
* |ssl_method|. It sets |*out_cipher_list| to a newly-allocated
@@ -260,6 +259,87 @@
size_t ssl_cipher_get_record_split_len(const SSL_CIPHER *cipher);
+/* Transcript layer. */
+
+/* SSL_TRANSCRIPT maintains the handshake transcript as a combination of a
+ * buffer and running hash. */
+typedef struct ssl_transcript_st {
+ /* buffer, if non-NULL, contains the handshake transcript. */
+ BUF_MEM *buffer;
+ /* hash, if initialized with an |EVP_MD|, maintains the handshake hash. For
+ * TLS 1.1 and below, it is the SHA-1 half. */
+ EVP_MD_CTX hash;
+ /* md5, if initialized with an |EVP_MD|, maintains the MD5 half of the
+ * handshake hash for TLS 1.1 and below. */
+ EVP_MD_CTX md5;
+} SSL_TRANSCRIPT;
+
+/* SSL_TRANSCRIPT_init initializes the handshake transcript. If called on an
+ * existing transcript, it resets the transcript and hash. It returns one on
+ * success and zero on failure. */
+int SSL_TRANSCRIPT_init(SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_init_hash initializes the handshake hash based on the PRF and
+ * contents of the handshake transcript. Subsequent calls to
+ * |SSL_TRANSCRIPT_update| will update the rolling hash. It returns one on
+ * success and zero on failure. It is an error to call this function after the
+ * handshake buffer is released. */
+int SSL_TRANSCRIPT_init_hash(SSL_TRANSCRIPT *transcript, uint16_t version,
+ int algorithm_prf);
+
+/* SSL_TRANSCRIPT_cleanup cleans up the hash and transcript. */
+void SSL_TRANSCRIPT_cleanup(SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_free_buffer releases the handshake buffer. Subsequent calls to
+ * |SSL_TRANSCRIPT_update| will not update the handshake buffer. */
+void SSL_TRANSCRIPT_free_buffer(SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_digest_len returns the length of the PRF hash. */
+size_t SSL_TRANSCRIPT_digest_len(const SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_md returns the PRF hash. For TLS 1.1 and below, this is
+ * |EVP_md5_sha1|. */
+const EVP_MD *SSL_TRANSCRIPT_md(const SSL_TRANSCRIPT *transcript);
+
+/* SSL_TRANSCRIPT_update adds |in| to the handshake buffer and handshake hash,
+ * whichever is enabled. It returns one on success and zero on failure. */
+int SSL_TRANSCRIPT_update(SSL_TRANSCRIPT *transcript, const uint8_t *in,
+ size_t in_len);
+
+/* SSL_TRANSCRIPT_get_hash writes the handshake hash to |out| which must have
+ * room for at least |SSL_TRANSCRIPT_digest_len| bytes. On success, it returns
+ * one and sets |*out_len| to the number of bytes written. Otherwise, it returns
+ * zero. */
+int SSL_TRANSCRIPT_get_hash(const SSL_TRANSCRIPT *transcript, uint8_t *out,
+ size_t *out_len);
+
+/* SSL_TRANSCRIPT_ssl3_cert_verify_hash writes the SSL 3.0 CertificateVerify
+ * hash into the bytes pointed to by |out| and writes the number of bytes to
+ * |*out_len|. |out| must have room for |EVP_MAX_MD_SIZE| bytes. It returns one
+ * on success and zero on failure. */
+int SSL_TRANSCRIPT_ssl3_cert_verify_hash(SSL_TRANSCRIPT *transcript,
+ uint8_t *out, size_t *out_len,
+ const SSL_SESSION *session,
+ int signature_algorithm);
+
+/* SSL_TRANSCRIPT_finish_mac computes the MAC for the Finished message into the
+ * bytes pointed by |out| and writes the number of bytes to |*out_len|. |out|
+ * must have room for |EVP_MAX_MD_SIZE| bytes. It returns one on success and
+ * zero on failure. */
+int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out,
+ size_t *out_len, const SSL_SESSION *session,
+ int from_server, uint16_t version);
+
+/* tls1_prf computes the PRF function for |ssl|. It writes |out_len| bytes to
+ * |out|, using |secret| as the secret and |label| as the label. |seed1| and
+ * |seed2| are concatenated to form the seed parameter. It returns one on
+ * success and zero on failure. */
+int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len,
+ const uint8_t *secret, size_t secret_len, const char *label,
+ size_t label_len, const uint8_t *seed1, size_t seed1_len,
+ const uint8_t *seed2, size_t seed2_len);
+
+
/* Encryption layer. */
/* SSL_AEAD_CTX contains information about an AEAD that is being used to encrypt
@@ -525,35 +605,6 @@
int custom_ext_add_serverhello(SSL_HANDSHAKE *hs, CBB *extensions);
-/* Handshake hash.
- *
- * The TLS handshake maintains a transcript of all handshake messages. At
- * various points in the protocol, this is either a handshake buffer, a rolling
- * hash (selected by cipher suite) or both. */
-
-/* ssl3_init_handshake_buffer initializes the handshake buffer and resets the
- * handshake hash. It returns one success and zero on failure. */
-int ssl3_init_handshake_buffer(SSL *ssl);
-
-/* ssl3_init_handshake_hash initializes the handshake hash based on the pending
- * cipher and the contents of the handshake buffer. Subsequent calls to
- * |ssl3_update_handshake_hash| will update the rolling hash. It returns one on
- * success and zero on failure. It is an error to call this function after the
- * handshake buffer is released. */
-int ssl3_init_handshake_hash(SSL *ssl);
-
-/* ssl3_free_handshake_buffer releases the handshake buffer. Subsequent calls
- * to |ssl3_update_handshake_hash| will not update the handshake buffer. */
-void ssl3_free_handshake_buffer(SSL *ssl);
-
-/* ssl3_free_handshake_hash releases the handshake hash. */
-void ssl3_free_handshake_hash(SSL *ssl);
-
-/* ssl3_update_handshake_hash adds |in| to the handshake buffer and handshake
- * hash, whichever is enabled. It returns one on success and zero on failure. */
-int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len);
-
-
/* ECDH groups. */
typedef struct ssl_ecdh_ctx_st SSL_ECDH_CTX;
@@ -827,12 +878,6 @@
int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in,
size_t len);
-/* tls13_get_context_hash writes Hash(Handshake Context) to |out| which must
- * have room for at least |EVP_MAX_MD_SIZE| bytes. On success, it returns one
- * and sets |*out_len| to the number of bytes written. Otherwise, it returns
- * zero. */
-int tls13_get_context_hash(SSL *ssl, uint8_t *out, size_t *out_len);
-
/* tls13_set_traffic_key sets the read or write traffic keys to
* |traffic_secret|. It returns one on success and zero on error. */
int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
@@ -872,12 +917,13 @@
/* tls13_write_psk_binder calculates the PSK binder value and replaces the last
* bytes of |msg| with the resulting value. It returns 1 on success, and 0 on
* failure. */
-int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len);
+int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len);
/* tls13_verify_psk_binder verifies that the handshake transcript, truncated
* up to the binders has a valid signature using the value of |session|'s
* resumption secret. It returns 1 on success, and 0 on failure. */
-int tls13_verify_psk_binder(SSL *ssl, SSL_SESSION *session, CBS *binders);
+int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
+ CBS *binders);
/* Handshake functions. */
@@ -951,6 +997,9 @@
/* ecdh_ctx is the current ECDH instance. */
SSL_ECDH_CTX ecdh_ctx;
+ /* transcript is the current handshake transcript. */
+ SSL_TRANSCRIPT transcript;
+
/* cookie is the value of the cookie received from the server, if any. */
uint8_t *cookie;
size_t cookie_len;
@@ -1132,7 +1181,7 @@
* containing the result. The caller must free it with |OPENSSL_free| to release
* it. This function returns one on success and zero on failure. */
int tls13_get_cert_verify_signature_input(
- SSL *ssl, uint8_t **out, size_t *out_len,
+ SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len,
enum ssl_cert_verify_context_t cert_verify_context);
/* ssl_negotiate_alpn negotiates the ALPN extension, if applicable. It returns
@@ -1390,20 +1439,6 @@
* crypto/x509. */
extern const struct ssl_x509_method_st ssl_crypto_x509_method;
-/* 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. */
-typedef struct ssl3_enc_method {
- /* prf computes the PRF function for |ssl|. It writes |out_len| bytes to
- * |out|, using |secret| as the secret and |label| as the label. |seed1| and
- * |seed2| are concatenated to form the seed parameter. It returns one on
- * success and zero on failure. */
- int (*prf)(const SSL *ssl, uint8_t *out, size_t out_len,
- const uint8_t *secret, size_t secret_len, const char *label,
- size_t label_len, const uint8_t *seed1, size_t seed1_len,
- const uint8_t *seed2, size_t seed2_len);
- int (*final_finish_mac)(SSL *ssl, int from_server, uint8_t *out);
-} SSL3_ENC_METHOD;
-
typedef struct ssl3_record_st {
/* type is the record type. */
uint8_t type;
@@ -1453,15 +1488,6 @@
int wpend_ret; /* number of bytes submitted */
const uint8_t *wpend_buf;
- /* handshake_buffer, if non-NULL, contains the handshake transcript. */
- BUF_MEM *handshake_buffer;
- /* handshake_hash, if initialized with an |EVP_MD|, maintains the handshake
- * hash. For TLS 1.1 and below, it is the SHA-1 half. */
- EVP_MD_CTX handshake_hash;
- /* handshake_md5, if initialized with an |EVP_MD|, maintains the MD5 half of
- * the handshake hash for TLS 1.1 and below. */
- EVP_MD_CTX handshake_md5;
-
/* recv_shutdown is the shutdown state for the receive half of the
* connection. */
enum ssl_shutdown_t recv_shutdown;
@@ -1538,10 +1564,6 @@
/* aead_write_ctx is the current write cipher state. */
SSL_AEAD_CTX *aead_write_ctx;
- /* enc_method is the method table corresponding to the current protocol
- * version. */
- const SSL3_ENC_METHOD *enc_method;
-
/* hs is the handshake state for the current handshake or NULL if there isn't
* one. */
SSL_HANDSHAKE *hs;
@@ -1865,9 +1887,6 @@
CRYPTO_BUFFER *ocsp_response;
};
-extern const SSL3_ENC_METHOD TLSv1_enc_data;
-extern const SSL3_ENC_METHOD SSLv3_enc_data;
-
/* From draft-ietf-tls-tls13-18, used in determining PSK modes. */
#define SSL_PSK_KE 0x0
#define SSL_PSK_DHE_KE 0x1
@@ -1904,6 +1923,11 @@
* zero otherwise. */
int ssl_session_is_resumable(const SSL *ssl, const SSL_SESSION *session);
+/* SSL_SESSION_get_digest returns the digest used in |session|. If the digest is
+ * invalid, it returns NULL. */
+const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session,
+ const SSL *ssl);
+
void ssl_set_session(SSL *ssl, SSL_SESSION *session);
enum ssl_session_result_t {
@@ -1963,13 +1987,6 @@
void ssl3_get_current_message(const SSL *ssl, CBS *out);
void ssl3_release_current_message(SSL *ssl, int free_buffer);
-/* ssl3_cert_verify_hash writes the SSL 3.0 CertificateVerify hash into the
- * bytes pointed to by |out| and writes the number of bytes to |*out_len|. |out|
- * must have room for |EVP_MAX_MD_SIZE| bytes. It sets |*out_md| to the hash
- * function used. It returns one on success and zero on failure. */
-int ssl3_cert_verify_hash(SSL *ssl, const EVP_MD **out_md, uint8_t *out,
- size_t *out_len, uint16_t signature_algorithm);
-
int ssl3_send_finished(SSL_HANDSHAKE *hs);
int ssl3_dispatch_alert(SSL *ssl);
int ssl3_read_app_data(SSL *ssl, int *out_got_handshake, uint8_t *buf, int len,
@@ -2006,7 +2023,7 @@
/* ssl_hash_current_message incorporates the current handshake message into the
* handshake hash. It returns one on success and zero on allocation failure. */
-int ssl_hash_current_message(SSL *ssl);
+int ssl_hash_current_message(SSL_HANDSHAKE *hs);
/* dtls1_get_record reads a new input record. On success, it places it in
* |ssl->s3->rrec| and returns one. Otherwise it returns <= 0 on error or if
@@ -2050,9 +2067,8 @@
int dtls1_dispatch_alert(SSL *ssl);
int tls1_change_cipher_state(SSL_HANDSHAKE *hs, int which);
-int tls1_handshake_digest(SSL *ssl, uint8_t *out, size_t out_len);
-int tls1_generate_master_secret(SSL *ssl, uint8_t *out, const uint8_t *premaster,
- size_t premaster_len);
+int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out,
+ const uint8_t *premaster, size_t premaster_len);
/* tls1_get_grouplist sets |*out_group_ids| and |*out_group_ids_len| to the
* locally-configured group preference list. */
@@ -2108,19 +2124,19 @@
/* tls1_verify_channel_id processes the current message as a Channel ID message,
* and verifies the signature. If the key is valid, it saves the Channel ID and
* returns one. Otherwise, it returns zero. */
-int tls1_verify_channel_id(SSL *ssl);
+int tls1_verify_channel_id(SSL_HANDSHAKE *hs);
/* tls1_write_channel_id generates a Channel ID message and puts the output in
* |cbb|. |ssl->tlsext_channel_id_private| must already be set before calling.
* This function returns one on success and zero on error. */
-int tls1_write_channel_id(SSL *ssl, CBB *cbb);
+int tls1_write_channel_id(SSL_HANDSHAKE *hs, CBB *cbb);
/* tls1_channel_id_hash computes the hash to be signed by Channel ID and writes
* it to |out|, which must contain at least |EVP_MAX_MD_SIZE| bytes. It returns
* one on success and zero on failure. */
-int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len);
+int tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len);
-int tls1_record_handshake_hashes_for_channel_id(SSL *ssl);
+int tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs);
/* ssl_do_channel_id_callback checks runs |ssl->ctx->channel_id_cb| if
* necessary. It returns one on success and zero on fatal error. Note that, on
@@ -2132,10 +2148,6 @@
* otherwise. */
int ssl3_can_false_start(const SSL *ssl);
-/* ssl3_get_enc_method returns the SSL3_ENC_METHOD corresponding to
- * |version|. */
-const SSL3_ENC_METHOD *ssl3_get_enc_method(uint16_t version);
-
/* ssl_get_version_range sets |*out_min_version| and |*out_max_version| to the
* minimum and maximum enabled protocol versions, respectively. */
int ssl_get_version_range(const SSL *ssl, uint16_t *out_min_version,
@@ -2145,8 +2157,6 @@
* call this function before the version is determined. */
uint16_t ssl3_protocol_version(const SSL *ssl);
-uint32_t ssl_get_algorithm_prf(const SSL *ssl);
-
void ssl_get_current_time(const SSL *ssl, struct timeval *out_clock);
/* ssl_reset_error_state resets state for |SSL_get_error|. */
diff --git a/ssl/s3_both.c b/ssl/s3_both.c
index 8d2657f..324e9f9 100644
--- a/ssl/s3_both.c
+++ b/ssl/s3_both.c
@@ -141,6 +141,10 @@
hs->ssl = ssl;
hs->wait = ssl_hs_ok;
hs->state = SSL_ST_INIT;
+ if (!SSL_TRANSCRIPT_init(&hs->transcript)) {
+ ssl_handshake_free(hs);
+ return NULL;
+ }
return hs;
}
@@ -159,6 +163,7 @@
OPENSSL_cleanse(hs->server_traffic_secret_0,
sizeof(hs->server_traffic_secret_0));
SSL_ECDH_CTX_cleanup(&hs->ecdh_ctx);
+ SSL_TRANSCRIPT_cleanup(&hs->transcript);
OPENSSL_free(hs->cookie);
OPENSSL_free(hs->key_share_bytes);
OPENSSL_free(hs->public_key);
@@ -264,7 +269,12 @@
} while (added < len);
ssl_do_msg_callback(ssl, 1 /* write */, SSL3_RT_HANDSHAKE, msg, len);
- ssl3_update_handshake_hash(ssl, msg, len);
+ /* TODO(svaldez): Move this up a layer to fix abstraction for SSL_TRANSCRIPT
+ * on hs. */
+ if (ssl->s3->hs != NULL &&
+ !SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript, msg, len)) {
+ goto err;
+ }
ret = 1;
err:
@@ -353,17 +363,20 @@
int ssl3_send_finished(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+ const SSL_SESSION *session = SSL_get_session(ssl);
+
uint8_t finished[EVP_MAX_MD_SIZE];
- size_t finished_len =
- ssl->s3->enc_method->final_finish_mac(ssl, ssl->server, finished);
- if (finished_len == 0) {
+ size_t finished_len;
+ if (!SSL_TRANSCRIPT_finish_mac(&hs->transcript, finished, &finished_len,
+ session, ssl->server,
+ ssl3_protocol_version(ssl))) {
return 0;
}
/* Log the master secret, if logging is enabled. */
if (!ssl_log_secret(ssl, "CLIENT_RANDOM",
- SSL_get_session(ssl)->master_key,
- SSL_get_session(ssl)->master_key_length)) {
+ session->master_key,
+ session->master_key_length)) {
return 0;
}
@@ -409,10 +422,11 @@
/* Snapshot the finished hash before incorporating the new message. */
uint8_t finished[EVP_MAX_MD_SIZE];
- size_t finished_len =
- ssl->s3->enc_method->final_finish_mac(ssl, !ssl->server, finished);
- if (finished_len == 0 ||
- !ssl_hash_current_message(ssl)) {
+ size_t finished_len;
+ if (!SSL_TRANSCRIPT_finish_mac(&hs->transcript, finished, &finished_len,
+ SSL_get_session(ssl), !ssl->server,
+ ssl3_protocol_version(ssl)) ||
+ !ssl_hash_current_message(hs)) {
return -1;
}
@@ -561,9 +575,11 @@
CBS_init(&v2_client_hello, ssl_read_buffer(ssl) + 2, msg_length);
/* The V2ClientHello without the length is incorporated into the handshake
- * hash. */
- if (!ssl3_update_handshake_hash(ssl, CBS_data(&v2_client_hello),
- CBS_len(&v2_client_hello))) {
+ * hash. This is only ever called at the start of the handshake, so hs is
+ * guaranteed to be non-NULL. */
+ if (!SSL_TRANSCRIPT_update(&ssl->s3->hs->transcript,
+ CBS_data(&v2_client_hello),
+ CBS_len(&v2_client_hello))) {
return -1;
}
@@ -734,15 +750,15 @@
CBS_init(out, (uint8_t *)ssl->init_buf->data, ssl->init_buf->length);
}
-int ssl_hash_current_message(SSL *ssl) {
+int ssl_hash_current_message(SSL_HANDSHAKE *hs) {
/* V2ClientHellos are hashed implicitly. */
- if (ssl->s3->is_v2_hello) {
+ if (hs->ssl->s3->is_v2_hello) {
return 1;
}
CBS cbs;
- ssl->method->get_current_message(ssl, &cbs);
- return ssl3_update_handshake_hash(ssl, CBS_data(&cbs), CBS_len(&cbs));
+ hs->ssl->method->get_current_message(hs->ssl, &cbs);
+ return SSL_TRANSCRIPT_update(&hs->transcript, CBS_data(&cbs), CBS_len(&cbs));
}
void ssl3_release_current_message(SSL *ssl, int free_buffer) {
diff --git a/ssl/s3_lib.c b/ssl/s3_lib.c
index 3f44629..1c723cd 100644
--- a/ssl/s3_lib.c
+++ b/ssl/s3_lib.c
@@ -178,9 +178,6 @@
return 0;
}
- EVP_MD_CTX_init(&s3->handshake_hash);
- EVP_MD_CTX_init(&s3->handshake_md5);
-
ssl->s3 = s3;
/* Set the version to the highest supported version.
@@ -202,8 +199,6 @@
SSL_SESSION_free(ssl->s3->new_session);
SSL_SESSION_free(ssl->s3->established_session);
- ssl3_free_handshake_buffer(ssl);
- ssl3_free_handshake_hash(ssl);
ssl_handshake_free(ssl->s3->hs);
OPENSSL_free(ssl->s3->next_proto_negotiated);
OPENSSL_free(ssl->s3->alpn_selected);
@@ -224,14 +219,3 @@
return ssl->ctx->cipher_list;
}
-
-/* If we are using default SHA1+MD5 algorithms switch to new SHA256 PRF and
- * handshake macs if required. */
-uint32_t ssl_get_algorithm_prf(const SSL *ssl) {
- uint32_t algorithm_prf = ssl->s3->tmp.new_cipher->algorithm_prf;
- if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT &&
- ssl3_protocol_version(ssl) >= TLS1_2_VERSION) {
- return SSL_HANDSHAKE_MAC_SHA256;
- }
- return algorithm_prf;
-}
diff --git a/ssl/ssl_cipher.c b/ssl/ssl_cipher.c
index 480304f..8f1ad73 100644
--- a/ssl/ssl_cipher.c
+++ b/ssl/ssl_cipher.c
@@ -787,10 +787,11 @@
return 1;
}
-const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf) {
+const EVP_MD *ssl_get_handshake_digest(uint32_t algorithm_prf,
+ uint16_t version) {
switch (algorithm_prf) {
case SSL_HANDSHAKE_MAC_DEFAULT:
- return EVP_sha1();
+ return version >= TLS1_2_VERSION ? EVP_sha256() : EVP_md5_sha1();
case SSL_HANDSHAKE_MAC_SHA256:
return EVP_sha256();
case SSL_HANDSHAKE_MAC_SHA384:
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 7fc7233..c946b77 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -2383,22 +2383,6 @@
cipher->algorithm_mac == SSL_AEAD;
}
-const SSL3_ENC_METHOD *ssl3_get_enc_method(uint16_t version) {
- switch (version) {
- case SSL3_VERSION:
- return &SSLv3_enc_data;
-
- case TLS1_VERSION:
- case TLS1_1_VERSION:
- case TLS1_2_VERSION:
- case TLS1_3_VERSION:
- return &TLSv1_enc_data;
-
- default:
- return NULL;
- }
-}
-
const struct {
uint16_t version;
uint32_t flag;
diff --git a/ssl/ssl_session.c b/ssl/ssl_session.c
index 9221e92..908d5dc 100644
--- a/ssl/ssl_session.c
+++ b/ssl/ssl_session.c
@@ -494,6 +494,16 @@
return CRYPTO_get_ex_data(&session->ex_data, idx);
}
+const EVP_MD *SSL_SESSION_get_digest(const SSL_SESSION *session,
+ const SSL *ssl) {
+ uint16_t version;
+ if (!ssl->method->version_from_wire(&version, session->ssl_version)) {
+ return NULL;
+ }
+
+ return ssl_get_handshake_digest(session->cipher->algorithm_prf, version);
+}
+
int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server) {
SSL *const ssl = hs->ssl;
if (ssl->mode & SSL_MODE_NO_SESSION_CREATION) {
diff --git a/ssl/s3_enc.c b/ssl/ssl_transcript.c
similarity index 64%
rename from ssl/s3_enc.c
rename to ssl/ssl_transcript.c
index bf82e08..9cc3777 100644
--- a/ssl/s3_enc.c
+++ b/ssl/ssl_transcript.c
@@ -138,84 +138,22 @@
#include <assert.h>
#include <string.h>
+#include <openssl/buf.h>
+#include <openssl/digest.h>
#include <openssl/err.h>
-#include <openssl/evp.h>
#include <openssl/mem.h>
#include <openssl/md5.h>
#include <openssl/nid.h>
+#include <openssl/sha.h>
#include "../crypto/internal.h"
#include "internal.h"
-static int ssl3_prf(const SSL *ssl, uint8_t *out, size_t out_len,
- const uint8_t *secret, size_t secret_len, const char *label,
- size_t label_len, const uint8_t *seed1, size_t seed1_len,
- const uint8_t *seed2, size_t seed2_len) {
- EVP_MD_CTX md5;
- EVP_MD_CTX sha1;
- uint8_t buf[16], smd[SHA_DIGEST_LENGTH];
- uint8_t c = 'A';
- size_t i, j, k;
-
- k = 0;
- EVP_MD_CTX_init(&md5);
- EVP_MD_CTX_init(&sha1);
- for (i = 0; i < out_len; i += MD5_DIGEST_LENGTH) {
- k++;
- if (k > sizeof(buf)) {
- /* bug: 'buf' is too small for this ciphersuite */
- OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- return 0;
- }
-
- for (j = 0; j < k; j++) {
- buf[j] = c;
- }
- c++;
- if (!EVP_DigestInit_ex(&sha1, EVP_sha1(), NULL)) {
- OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
- return 0;
- }
- EVP_DigestUpdate(&sha1, buf, k);
- EVP_DigestUpdate(&sha1, secret, secret_len);
- /* |label| is ignored for SSLv3. */
- if (seed1_len) {
- EVP_DigestUpdate(&sha1, seed1, seed1_len);
- }
- if (seed2_len) {
- EVP_DigestUpdate(&sha1, seed2, seed2_len);
- }
- EVP_DigestFinal_ex(&sha1, smd, NULL);
-
- if (!EVP_DigestInit_ex(&md5, EVP_md5(), NULL)) {
- OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
- return 0;
- }
- EVP_DigestUpdate(&md5, secret, secret_len);
- EVP_DigestUpdate(&md5, smd, SHA_DIGEST_LENGTH);
- if (i + MD5_DIGEST_LENGTH > out_len) {
- EVP_DigestFinal_ex(&md5, smd, NULL);
- OPENSSL_memcpy(out, smd, out_len - i);
- } else {
- EVP_DigestFinal_ex(&md5, out, NULL);
- }
-
- out += MD5_DIGEST_LENGTH;
- }
-
- OPENSSL_cleanse(smd, SHA_DIGEST_LENGTH);
- EVP_MD_CTX_cleanup(&md5);
- EVP_MD_CTX_cleanup(&sha1);
-
- return 1;
-}
-
-int ssl3_init_handshake_buffer(SSL *ssl) {
- ssl3_free_handshake_buffer(ssl);
- ssl3_free_handshake_hash(ssl);
- ssl->s3->handshake_buffer = BUF_MEM_new();
- return ssl->s3->handshake_buffer != NULL;
+int SSL_TRANSCRIPT_init(SSL_TRANSCRIPT *transcript) {
+ SSL_TRANSCRIPT_cleanup(transcript);
+ transcript->buffer = BUF_MEM_new();
+ return transcript->buffer != NULL;
}
/* init_digest_with_data calls |EVP_DigestInit_ex| on |ctx| with |md| and then
@@ -229,78 +167,113 @@
return 1;
}
-int ssl3_init_handshake_hash(SSL *ssl) {
- ssl3_free_handshake_hash(ssl);
+int SSL_TRANSCRIPT_init_hash(SSL_TRANSCRIPT *transcript, uint16_t version,
+ int algorithm_prf) {
+ const EVP_MD *md = ssl_get_handshake_digest(algorithm_prf, version);
- uint32_t algorithm_prf = ssl_get_algorithm_prf(ssl);
- if (!init_digest_with_data(&ssl->s3->handshake_hash,
- ssl_get_handshake_digest(algorithm_prf),
- ssl->s3->handshake_buffer)) {
- return 0;
+ /* To support SSL 3.0's Finished and CertificateVerify constructions,
+ * EVP_md5_sha1() is split into MD5 and SHA-1 halves. When SSL 3.0 is removed,
+ * we can simplify this. */
+ if (md == EVP_md5_sha1()) {
+ if (!init_digest_with_data(&transcript->md5, EVP_md5(),
+ transcript->buffer)) {
+ return 0;
+ }
+ md = EVP_sha1();
}
- if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT &&
- !init_digest_with_data(&ssl->s3->handshake_md5, EVP_md5(),
- ssl->s3->handshake_buffer)) {
+ if (!init_digest_with_data(&transcript->hash, md, transcript->buffer)) {
return 0;
}
return 1;
}
-void ssl3_free_handshake_hash(SSL *ssl) {
- EVP_MD_CTX_cleanup(&ssl->s3->handshake_hash);
- EVP_MD_CTX_cleanup(&ssl->s3->handshake_md5);
+void SSL_TRANSCRIPT_cleanup(SSL_TRANSCRIPT *transcript) {
+ SSL_TRANSCRIPT_free_buffer(transcript);
+ EVP_MD_CTX_cleanup(&transcript->hash);
+ EVP_MD_CTX_cleanup(&transcript->md5);
}
-void ssl3_free_handshake_buffer(SSL *ssl) {
- BUF_MEM_free(ssl->s3->handshake_buffer);
- ssl->s3->handshake_buffer = NULL;
+void SSL_TRANSCRIPT_free_buffer(SSL_TRANSCRIPT *transcript) {
+ BUF_MEM_free(transcript->buffer);
+ transcript->buffer = NULL;
}
-int ssl3_update_handshake_hash(SSL *ssl, const uint8_t *in, size_t in_len) {
+size_t SSL_TRANSCRIPT_digest_len(const SSL_TRANSCRIPT *transcript) {
+ return EVP_MD_size(SSL_TRANSCRIPT_md(transcript));
+}
+
+const EVP_MD *SSL_TRANSCRIPT_md(const SSL_TRANSCRIPT *transcript) {
+ if (EVP_MD_CTX_md(&transcript->md5) != NULL) {
+ return EVP_md5_sha1();
+ }
+ return EVP_MD_CTX_md(&transcript->hash);
+}
+
+int SSL_TRANSCRIPT_update(SSL_TRANSCRIPT *transcript, const uint8_t *in,
+ size_t in_len) {
/* Depending on the state of the handshake, either the handshake buffer may be
* active, the rolling hash, or both. */
-
- if (ssl->s3->handshake_buffer != NULL) {
- size_t new_len = ssl->s3->handshake_buffer->length + in_len;
+ if (transcript->buffer != NULL) {
+ size_t new_len = transcript->buffer->length + in_len;
if (new_len < in_len) {
OPENSSL_PUT_ERROR(SSL, ERR_R_OVERFLOW);
return 0;
}
- if (!BUF_MEM_grow(ssl->s3->handshake_buffer, new_len)) {
+ if (!BUF_MEM_grow(transcript->buffer, new_len)) {
return 0;
}
- OPENSSL_memcpy(ssl->s3->handshake_buffer->data + new_len - in_len, in,
- in_len);
+ OPENSSL_memcpy(transcript->buffer->data + new_len - in_len, in, in_len);
}
- if (EVP_MD_CTX_md(&ssl->s3->handshake_hash) != NULL) {
- EVP_DigestUpdate(&ssl->s3->handshake_hash, in, in_len);
+ if (EVP_MD_CTX_md(&transcript->hash) != NULL) {
+ EVP_DigestUpdate(&transcript->hash, in, in_len);
}
- if (EVP_MD_CTX_md(&ssl->s3->handshake_md5) != NULL) {
- EVP_DigestUpdate(&ssl->s3->handshake_md5, in, in_len);
+ if (EVP_MD_CTX_md(&transcript->md5) != NULL) {
+ EVP_DigestUpdate(&transcript->md5, in, in_len);
}
+
return 1;
}
-static int ssl3_handshake_mac(SSL *ssl, int md_nid, const char *sender,
- size_t sender_len, uint8_t *p) {
- unsigned int ret;
+int SSL_TRANSCRIPT_get_hash(const SSL_TRANSCRIPT *transcript, uint8_t *out,
+ size_t *out_len) {
+ int ret = 0;
+ EVP_MD_CTX ctx;
+ EVP_MD_CTX_init(&ctx);
+ unsigned md5_len = 0;
+ if (EVP_MD_CTX_md(&transcript->md5) != NULL) {
+ if (!EVP_MD_CTX_copy_ex(&ctx, &transcript->md5) ||
+ !EVP_DigestFinal_ex(&ctx, out, &md5_len)) {
+ goto err;
+ }
+ }
+
+ unsigned len;
+ if (!EVP_MD_CTX_copy_ex(&ctx, &transcript->hash) ||
+ !EVP_DigestFinal_ex(&ctx, out + md5_len, &len)) {
+ goto err;
+ }
+
+ *out_len = md5_len + len;
+ ret = 1;
+
+err:
+ EVP_MD_CTX_cleanup(&ctx);
+ return ret;
+}
+
+static int ssl3_handshake_mac(SSL_TRANSCRIPT *transcript,
+ const SSL_SESSION *session,
+ const EVP_MD_CTX *ctx_template,
+ const char *sender, size_t sender_len,
+ uint8_t *p, size_t *out_len) {
+ unsigned int len;
size_t npad, n;
unsigned int i;
uint8_t md_buf[EVP_MAX_MD_SIZE];
EVP_MD_CTX ctx;
- const EVP_MD_CTX *ctx_template;
-
- if (md_nid == NID_md5) {
- ctx_template = &ssl->s3->handshake_md5;
- } else if (md_nid == EVP_MD_CTX_type(&ssl->s3->handshake_hash)) {
- ctx_template = &ssl->s3->handshake_hash;
- } else {
- OPENSSL_PUT_ERROR(SSL, SSL_R_NO_REQUIRED_DIGEST);
- return 0;
- }
EVP_MD_CTX_init(&ctx);
if (!EVP_MD_CTX_copy_ex(&ctx, ctx_template)) {
@@ -325,11 +298,6 @@
n = EVP_MD_CTX_size(&ctx);
- SSL_SESSION *session = ssl->session;
- if (ssl->s3->new_session != NULL) {
- session = ssl->s3->new_session;
- }
-
npad = (48 / n) * n;
if (sender != NULL) {
EVP_DigestUpdate(&ctx, sender, sender_len);
@@ -346,61 +314,92 @@
EVP_DigestUpdate(&ctx, session->master_key, session->master_key_length);
EVP_DigestUpdate(&ctx, kPad2, npad);
EVP_DigestUpdate(&ctx, md_buf, i);
- EVP_DigestFinal_ex(&ctx, p, &ret);
+ EVP_DigestFinal_ex(&ctx, p, &len);
EVP_MD_CTX_cleanup(&ctx);
- return ret;
+ *out_len = len;
+ return 1;
}
-static int ssl3_final_finish_mac(SSL *ssl, int from_server, uint8_t *out) {
- const char *sender = from_server ? SSL3_MD_SERVER_FINISHED_CONST
- : SSL3_MD_CLIENT_FINISHED_CONST;
- const size_t sender_len = 4;
- int ret, sha1len;
- ret = ssl3_handshake_mac(ssl, NID_md5, sender, sender_len, out);
- if (ret == 0) {
- return 0;
- }
-
- out += ret;
-
- sha1len = ssl3_handshake_mac(ssl, NID_sha1, sender, sender_len, out);
- if (sha1len == 0) {
- return 0;
- }
-
- ret += sha1len;
- return ret;
-}
-
-int ssl3_cert_verify_hash(SSL *ssl, const EVP_MD **out_md, uint8_t *out,
- size_t *out_len, uint16_t signature_algorithm) {
- assert(ssl3_protocol_version(ssl) == SSL3_VERSION);
-
- if (signature_algorithm == SSL_SIGN_RSA_PKCS1_MD5_SHA1) {
- if (ssl3_handshake_mac(ssl, NID_md5, NULL, 0, out) == 0 ||
- ssl3_handshake_mac(ssl, NID_sha1, NULL, 0,
- out + MD5_DIGEST_LENGTH) == 0) {
- return 0;
- }
- *out_md = EVP_md5_sha1();
- *out_len = MD5_DIGEST_LENGTH + SHA_DIGEST_LENGTH;
- } else if (signature_algorithm == SSL_SIGN_ECDSA_SHA1) {
- if (ssl3_handshake_mac(ssl, NID_sha1, NULL, 0, out) == 0) {
- return 0;
- }
- *out_md = EVP_sha1();
- *out_len = SHA_DIGEST_LENGTH;
- } else {
+int SSL_TRANSCRIPT_ssl3_cert_verify_hash(SSL_TRANSCRIPT *transcript,
+ uint8_t *out, size_t *out_len,
+ const SSL_SESSION *session,
+ int signature_algorithm) {
+ if (SSL_TRANSCRIPT_md(transcript) != EVP_md5_sha1()) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
- return 1;
+ if (signature_algorithm == SSL_SIGN_RSA_PKCS1_MD5_SHA1) {
+ size_t md5_len, len;
+ if (!ssl3_handshake_mac(transcript, session, &transcript->md5, NULL, 0, out,
+ &md5_len) ||
+ !ssl3_handshake_mac(transcript, session, &transcript->hash, NULL, 0,
+ out + md5_len, &len)) {
+ return 0;
+ }
+ *out_len = md5_len + len;
+ return 1;
+ }
+
+ if (signature_algorithm == SSL_SIGN_ECDSA_SHA1) {
+ return ssl3_handshake_mac(transcript, session, &transcript->hash, NULL, 0,
+ out, out_len);
+ }
+
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
}
-const SSL3_ENC_METHOD SSLv3_enc_data = {
- ssl3_prf,
- ssl3_final_finish_mac,
-};
+int SSL_TRANSCRIPT_finish_mac(SSL_TRANSCRIPT *transcript, uint8_t *out,
+ size_t *out_len, const SSL_SESSION *session,
+ int from_server, uint16_t version) {
+ if (version == SSL3_VERSION) {
+ if (SSL_TRANSCRIPT_md(transcript) != EVP_md5_sha1()) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ const char *sender = from_server ? SSL3_MD_SERVER_FINISHED_CONST
+ : SSL3_MD_CLIENT_FINISHED_CONST;
+ const size_t sender_len = 4;
+ size_t md5_len, len;
+ if (!ssl3_handshake_mac(transcript, session, &transcript->md5, sender,
+ sender_len, out, &md5_len) ||
+ !ssl3_handshake_mac(transcript, session, &transcript->hash, sender,
+ sender_len, out + md5_len, &len)) {
+ return 0;
+ }
+
+ *out_len = md5_len + len;
+ return 1;
+ }
+
+ /* At this point, the handshake should have released the handshake buffer on
+ * its own. */
+ assert(transcript->buffer == NULL);
+
+ const char *label = TLS_MD_CLIENT_FINISH_CONST;
+ size_t label_len = TLS_MD_SERVER_FINISH_CONST_SIZE;
+ if (from_server) {
+ label = TLS_MD_SERVER_FINISH_CONST;
+ label_len = TLS_MD_SERVER_FINISH_CONST_SIZE;
+ }
+
+ uint8_t digests[EVP_MAX_MD_SIZE];
+ size_t digests_len;
+ if (!SSL_TRANSCRIPT_get_hash(transcript, digests, &digests_len)) {
+ return 0;
+ }
+
+ static const size_t kFinishedLen = 12;
+ if (!tls1_prf(SSL_TRANSCRIPT_md(transcript), out, kFinishedLen,
+ session->master_key, session->master_key_length, label,
+ label_len, digests, digests_len, NULL, 0)) {
+ return 0;
+ }
+
+ *out_len = kFinishedLen;
+ return 1;
+}
diff --git a/ssl/t1_enc.c b/ssl/t1_enc.c
index 5e5c348..d01992e 100644
--- a/ssl/t1_enc.c
+++ b/ssl/t1_enc.c
@@ -224,18 +224,17 @@
return ret;
}
-static int tls1_prf(const SSL *ssl, uint8_t *out, size_t out_len,
- const uint8_t *secret, size_t secret_len, const char *label,
- size_t label_len, const uint8_t *seed1, size_t seed1_len,
- const uint8_t *seed2, size_t seed2_len) {
+int tls1_prf(const EVP_MD *digest, uint8_t *out, size_t out_len,
+ const uint8_t *secret, size_t secret_len, const char *label,
+ size_t label_len, const uint8_t *seed1, size_t seed1_len,
+ const uint8_t *seed2, size_t seed2_len) {
if (out_len == 0) {
return 1;
}
OPENSSL_memset(out, 0, out_len);
- uint32_t algorithm_prf = ssl_get_algorithm_prf(ssl);
- if (algorithm_prf == SSL_HANDSHAKE_MAC_DEFAULT) {
+ if (digest == EVP_md5_sha1()) {
/* If using the MD5/SHA1 PRF, |secret| is partitioned between SHA-1 and
* MD5, MD5 first. */
size_t secret_half = secret_len - (secret_len / 2);
@@ -248,17 +247,82 @@
/* Note that, if |secret_len| is odd, the two halves share a byte. */
secret = secret + (secret_len - secret_half);
secret_len = secret_half;
+
+ digest = EVP_sha1();
}
- if (!tls1_P_hash(out, out_len, ssl_get_handshake_digest(algorithm_prf),
- secret, secret_len, (const uint8_t *)label, label_len,
- seed1, seed1_len, seed2, seed2_len)) {
+ if (!tls1_P_hash(out, out_len, digest, secret, secret_len,
+ (const uint8_t *)label, label_len, seed1, seed1_len, seed2,
+ seed2_len)) {
return 0;
}
return 1;
}
+static int ssl3_prf(uint8_t *out, size_t out_len, const uint8_t *secret,
+ size_t secret_len, const char *label, size_t label_len,
+ const uint8_t *seed1, size_t seed1_len,
+ const uint8_t *seed2, size_t seed2_len) {
+ EVP_MD_CTX md5;
+ EVP_MD_CTX sha1;
+ uint8_t buf[16], smd[SHA_DIGEST_LENGTH];
+ uint8_t c = 'A';
+ size_t i, j, k;
+
+ k = 0;
+ EVP_MD_CTX_init(&md5);
+ EVP_MD_CTX_init(&sha1);
+ for (i = 0; i < out_len; i += MD5_DIGEST_LENGTH) {
+ k++;
+ if (k > sizeof(buf)) {
+ /* bug: 'buf' is too small for this ciphersuite */
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
+ for (j = 0; j < k; j++) {
+ buf[j] = c;
+ }
+ c++;
+ if (!EVP_DigestInit_ex(&sha1, EVP_sha1(), NULL)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
+ return 0;
+ }
+ EVP_DigestUpdate(&sha1, buf, k);
+ EVP_DigestUpdate(&sha1, secret, secret_len);
+ /* |label| is ignored for SSLv3. */
+ if (seed1_len) {
+ EVP_DigestUpdate(&sha1, seed1, seed1_len);
+ }
+ if (seed2_len) {
+ EVP_DigestUpdate(&sha1, seed2, seed2_len);
+ }
+ EVP_DigestFinal_ex(&sha1, smd, NULL);
+
+ if (!EVP_DigestInit_ex(&md5, EVP_md5(), NULL)) {
+ OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
+ return 0;
+ }
+ EVP_DigestUpdate(&md5, secret, secret_len);
+ EVP_DigestUpdate(&md5, smd, SHA_DIGEST_LENGTH);
+ if (i + MD5_DIGEST_LENGTH > out_len) {
+ EVP_DigestFinal_ex(&md5, smd, NULL);
+ OPENSSL_memcpy(out, smd, out_len - i);
+ } else {
+ EVP_DigestFinal_ex(&md5, out, NULL);
+ }
+
+ out += MD5_DIGEST_LENGTH;
+ }
+
+ OPENSSL_cleanse(smd, SHA_DIGEST_LENGTH);
+ EVP_MD_CTX_cleanup(&md5);
+ EVP_MD_CTX_cleanup(&sha1);
+
+ return 1;
+}
+
static int tls1_setup_key_block(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
if (hs->key_block_len != 0) {
@@ -385,112 +449,58 @@
}
int SSL_generate_key_block(const SSL *ssl, uint8_t *out, size_t out_len) {
- return ssl->s3->enc_method->prf(
- ssl, out, out_len, SSL_get_session(ssl)->master_key,
- SSL_get_session(ssl)->master_key_length, TLS_MD_KEY_EXPANSION_CONST,
- TLS_MD_KEY_EXPANSION_CONST_SIZE, ssl->s3->server_random, SSL3_RANDOM_SIZE,
- ssl->s3->client_random, SSL3_RANDOM_SIZE);
-}
-
-static int append_digest(const EVP_MD_CTX *ctx, uint8_t *out, size_t *out_len,
- size_t max_out) {
- int ret = 0;
- EVP_MD_CTX ctx_copy;
- EVP_MD_CTX_init(&ctx_copy);
-
- if (EVP_MD_CTX_size(ctx) > max_out) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_BUFFER_TOO_SMALL);
- goto err;
- }
- unsigned len;
- if (!EVP_MD_CTX_copy_ex(&ctx_copy, ctx) ||
- !EVP_DigestFinal_ex(&ctx_copy, out, &len)) {
- goto err;
- }
- assert(len == EVP_MD_CTX_size(ctx));
-
- *out_len = len;
- ret = 1;
-
-err:
- EVP_MD_CTX_cleanup(&ctx_copy);
- return ret;
-}
-
-/* tls1_handshake_digest calculates the current handshake hash and writes it to
- * |out|, which has space for |out_len| bytes. It returns the number of bytes
- * written or -1 in the event of an error. This function works on a copy of the
- * underlying digests so can be called multiple times and prior to the final
- * update etc. */
-int tls1_handshake_digest(SSL *ssl, uint8_t *out, size_t out_len) {
- size_t md5_len = 0;
- if (EVP_MD_CTX_md(&ssl->s3->handshake_md5) != NULL &&
- !append_digest(&ssl->s3->handshake_md5, out, &md5_len, out_len)) {
- return -1;
+ if (ssl3_protocol_version(ssl) == SSL3_VERSION) {
+ return ssl3_prf(out, out_len, SSL_get_session(ssl)->master_key,
+ SSL_get_session(ssl)->master_key_length,
+ TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE,
+ ssl->s3->server_random, SSL3_RANDOM_SIZE,
+ ssl->s3->client_random, SSL3_RANDOM_SIZE);
}
- size_t len;
- if (!append_digest(&ssl->s3->handshake_hash, out + md5_len, &len,
- out_len - md5_len)) {
- return -1;
- }
-
- return (int)(md5_len + len);
-}
-
-static int tls1_final_finish_mac(SSL *ssl, int from_server, uint8_t *out) {
- /* At this point, the handshake should have released the handshake buffer on
- * its own. */
- assert(ssl->s3->handshake_buffer == NULL);
-
- const char *label = TLS_MD_CLIENT_FINISH_CONST;
- size_t label_len = TLS_MD_SERVER_FINISH_CONST_SIZE;
- if (from_server) {
- label = TLS_MD_SERVER_FINISH_CONST;
- label_len = TLS_MD_SERVER_FINISH_CONST_SIZE;
- }
-
- uint8_t buf[EVP_MAX_MD_SIZE];
- int digests_len = tls1_handshake_digest(ssl, buf, sizeof(buf));
- if (digests_len < 0) {
+ const EVP_MD *digest = ssl_get_handshake_digest(
+ SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
+ if (digest == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
-
- static const size_t kFinishedLen = 12;
- if (!ssl->s3->enc_method->prf(ssl, out, kFinishedLen,
- SSL_get_session(ssl)->master_key,
- SSL_get_session(ssl)->master_key_length, label,
- label_len, buf, digests_len, NULL, 0)) {
- return 0;
- }
-
- return (int)kFinishedLen;
+ return tls1_prf(digest, out, out_len, SSL_get_session(ssl)->master_key,
+ SSL_get_session(ssl)->master_key_length,
+ TLS_MD_KEY_EXPANSION_CONST, TLS_MD_KEY_EXPANSION_CONST_SIZE,
+ ssl->s3->server_random, SSL3_RANDOM_SIZE,
+ ssl->s3->client_random, SSL3_RANDOM_SIZE);
}
-int tls1_generate_master_secret(SSL *ssl, uint8_t *out,
+int tls1_generate_master_secret(SSL_HANDSHAKE *hs, uint8_t *out,
const uint8_t *premaster,
size_t premaster_len) {
+ const SSL *ssl = hs->ssl;
if (ssl->s3->tmp.extended_master_secret) {
uint8_t digests[EVP_MAX_MD_SIZE];
- int digests_len = tls1_handshake_digest(ssl, digests, sizeof(digests));
- if (digests_len == -1) {
- return 0;
- }
-
- if (!ssl->s3->enc_method->prf(ssl, out, SSL3_MASTER_SECRET_SIZE, premaster,
- premaster_len,
- TLS_MD_EXTENDED_MASTER_SECRET_CONST,
- TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE,
- digests, digests_len, NULL, 0)) {
+ size_t digests_len;
+ if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, digests, &digests_len) ||
+ !tls1_prf(SSL_TRANSCRIPT_md(&hs->transcript), out,
+ SSL3_MASTER_SECRET_SIZE, premaster, premaster_len,
+ TLS_MD_EXTENDED_MASTER_SECRET_CONST,
+ TLS_MD_EXTENDED_MASTER_SECRET_CONST_SIZE, digests,
+ digests_len, NULL, 0)) {
return 0;
}
} else {
- if (!ssl->s3->enc_method->prf(ssl, out, SSL3_MASTER_SECRET_SIZE, premaster,
- premaster_len, TLS_MD_MASTER_SECRET_CONST,
- TLS_MD_MASTER_SECRET_CONST_SIZE,
- ssl->s3->client_random, SSL3_RANDOM_SIZE,
- ssl->s3->server_random, SSL3_RANDOM_SIZE)) {
- return 0;
+ if (ssl3_protocol_version(ssl) == SSL3_VERSION) {
+ if (!ssl3_prf(out, SSL3_MASTER_SECRET_SIZE, premaster, premaster_len,
+ TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE,
+ ssl->s3->client_random, SSL3_RANDOM_SIZE,
+ ssl->s3->server_random, SSL3_RANDOM_SIZE)) {
+ return 0;
+ }
+ } else {
+ if (!tls1_prf(SSL_TRANSCRIPT_md(&hs->transcript), out,
+ SSL3_MASTER_SECRET_SIZE, premaster, premaster_len,
+ TLS_MD_MASTER_SECRET_CONST, TLS_MD_MASTER_SECRET_CONST_SIZE,
+ ssl->s3->client_random, SSL3_RANDOM_SIZE,
+ ssl->s3->server_random, SSL3_RANDOM_SIZE)) {
+ return 0;
+ }
}
}
@@ -538,16 +548,15 @@
OPENSSL_memcpy(seed + 2 * SSL3_RANDOM_SIZE + 2, context, context_len);
}
- int ret =
- ssl->s3->enc_method->prf(ssl, out, out_len,
- SSL_get_session(ssl)->master_key,
- SSL_get_session(ssl)->master_key_length, label,
- label_len, seed, seed_len, NULL, 0);
+ const EVP_MD *digest = ssl_get_handshake_digest(
+ SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
+ if (digest == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+ int ret = tls1_prf(digest, out, out_len, SSL_get_session(ssl)->master_key,
+ SSL_get_session(ssl)->master_key_length, label, label_len,
+ seed, seed_len, NULL, 0);
OPENSSL_free(seed);
return ret;
}
-
-const SSL3_ENC_METHOD TLSv1_enc_data = {
- tls1_prf,
- tls1_final_finish_mac,
-};
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index cf46742..b3ba546 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1883,8 +1883,12 @@
return 0;
}
- const EVP_MD *digest =
- ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf);
+ const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl);
+ if (digest == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
size_t binder_len = EVP_MD_size(digest);
return 15 + ssl->session->tlsext_ticklen + binder_len;
}
@@ -1912,8 +1916,13 @@
/* Fill in a placeholder zero binder of the appropriate length. It will be
* computed and filled in later after length prefixes are computed. */
uint8_t zero_binder[EVP_MAX_MD_SIZE] = {0};
- const EVP_MD *digest =
- ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf);
+
+ const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl);
+ if (digest == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
+
size_t binder_len = EVP_MD_size(digest);
CBB contents, identity, ticket, binders, binder;
@@ -3325,7 +3334,8 @@
return 0;
}
-int tls1_verify_channel_id(SSL *ssl) {
+int tls1_verify_channel_id(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
int ret = 0;
uint16_t extension_type;
CBS extension, channel_id;
@@ -3384,7 +3394,7 @@
uint8_t digest[EVP_MAX_MD_SIZE];
size_t digest_len;
- if (!tls1_channel_id_hash(ssl, digest, &digest_len)) {
+ if (!tls1_channel_id_hash(hs, digest, &digest_len)) {
goto err;
}
@@ -3413,10 +3423,11 @@
return ret;
}
-int tls1_write_channel_id(SSL *ssl, CBB *cbb) {
+int tls1_write_channel_id(SSL_HANDSHAKE *hs, CBB *cbb) {
+ SSL *const ssl = hs->ssl;
uint8_t digest[EVP_MAX_MD_SIZE];
size_t digest_len;
- if (!tls1_channel_id_hash(ssl, digest, &digest_len)) {
+ if (!tls1_channel_id_hash(hs, digest, &digest_len)) {
return 0;
}
@@ -3462,11 +3473,12 @@
return ret;
}
-int tls1_channel_id_hash(SSL *ssl, uint8_t *out, size_t *out_len) {
+int tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len) {
+ SSL *const ssl = hs->ssl;
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION) {
uint8_t *msg;
size_t msg_len;
- if (!tls13_get_cert_verify_signature_input(ssl, &msg, &msg_len,
+ if (!tls13_get_cert_verify_signature_input(hs, &msg, &msg_len,
ssl_cert_verify_channel_id)) {
return 0;
}
@@ -3493,13 +3505,12 @@
ssl->session->original_handshake_hash_len);
}
- uint8_t handshake_hash[EVP_MAX_MD_SIZE];
- int handshake_hash_len = tls1_handshake_digest(ssl, handshake_hash,
- sizeof(handshake_hash));
- if (handshake_hash_len < 0) {
+ uint8_t hs_hash[EVP_MAX_MD_SIZE];
+ size_t hs_hash_len;
+ if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, hs_hash, &hs_hash_len)) {
return 0;
}
- SHA256_Update(&ctx, handshake_hash, (size_t)handshake_hash_len);
+ SHA256_Update(&ctx, hs_hash, (size_t)hs_hash_len);
SHA256_Final(out, &ctx);
*out_len = SHA256_DIGEST_LENGTH;
return 1;
@@ -3508,8 +3519,8 @@
/* tls1_record_handshake_hashes_for_channel_id records the current handshake
* hashes in |ssl->s3->new_session| so that Channel ID resumptions can sign that
* data. */
-int tls1_record_handshake_hashes_for_channel_id(SSL *ssl) {
- int digest_len;
+int tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs) {
+ SSL *const ssl = hs->ssl;
/* This function should never be called for a resumed session because the
* handshake hashes that we wish to record are for the original, full
* handshake. */
@@ -3517,15 +3528,18 @@
return -1;
}
- digest_len =
- tls1_handshake_digest(
- ssl, ssl->s3->new_session->original_handshake_hash,
- sizeof(ssl->s3->new_session->original_handshake_hash));
- if (digest_len < 0) {
+ OPENSSL_COMPILE_ASSERT(
+ sizeof(ssl->s3->new_session->original_handshake_hash) == EVP_MAX_MD_SIZE,
+ original_handshake_hash_is_too_small);
+
+ size_t digest_len;
+ if (!SSL_TRANSCRIPT_get_hash(&hs->transcript,
+ ssl->s3->new_session->original_handshake_hash,
+ &digest_len)) {
return -1;
}
- assert(sizeof(ssl->s3->new_session->original_handshake_hash) < 256);
+ OPENSSL_COMPILE_ASSERT(EVP_MAX_MD_SIZE <= 0xff, max_md_size_is_too_large);
ssl->s3->new_session->original_handshake_hash_len = (uint8_t)digest_len;
return 1;
diff --git a/ssl/tls13_both.c b/ssl/tls13_both.c
index 9e9da44..134dfd2 100644
--- a/ssl/tls13_both.c
+++ b/ssl/tls13_both.c
@@ -102,7 +102,7 @@
}
int tls13_get_cert_verify_signature_input(
- SSL *ssl, uint8_t **out, size_t *out_len,
+ SSL_HANDSHAKE *hs, uint8_t **out, size_t *out_len,
enum ssl_cert_verify_context_t cert_verify_context) {
CBB cbb;
if (!CBB_init(&cbb, 64 + 33 + 1 + 2 * EVP_MAX_MD_SIZE)) {
@@ -140,7 +140,8 @@
uint8_t context_hash[EVP_MAX_MD_SIZE];
size_t context_hash_len;
- if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len) ||
+ if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash,
+ &context_hash_len) ||
!CBB_add_bytes(&cbb, context_hash, context_hash_len) ||
!CBB_finish(&cbb, out, out_len)) {
goto err;
@@ -372,7 +373,7 @@
ssl->s3->new_session->peer_signature_algorithm = signature_algorithm;
if (!tls13_get_cert_verify_signature_input(
- ssl, &msg, &msg_len,
+ hs, &msg, &msg_len,
ssl->server ? ssl_cert_verify_client : ssl_cert_verify_server)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
goto err;
@@ -536,7 +537,7 @@
enum ssl_private_key_result_t sign_result;
if (is_first_run) {
if (!tls13_get_cert_verify_signature_input(
- ssl, &msg, &msg_len,
+ hs, &msg, &msg_len,
ssl->server ? ssl_cert_verify_server : ssl_cert_verify_client)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_INTERNAL_ERROR);
goto err;
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c
index fc94d2f..a85f6b3 100644
--- a/ssl/tls13_client.c
+++ b/ssl/tls13_client.c
@@ -135,7 +135,7 @@
hs->retry_group = group_id;
}
- if (!ssl_hash_current_message(ssl)) {
+ if (!ssl_hash_current_message(hs)) {
return ssl_hs_error;
}
@@ -271,8 +271,6 @@
ssl->s3->tmp.new_cipher = cipher;
/* The PRF hash is now known. Set up the key schedule. */
- size_t hash_len =
- EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)));
if (!tls13_init_key_schedule(hs)) {
return ssl_hs_error;
}
@@ -283,7 +281,7 @@
ssl->s3->new_session->master_key_length)) {
return ssl_hs_error;
}
- } else if (!tls13_advance_key_schedule(hs, kZeroes, hash_len)) {
+ } else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) {
return ssl_hs_error;
}
@@ -327,7 +325,7 @@
ssl->s3->short_header = 1;
}
- if (!ssl_hash_current_message(ssl) ||
+ if (!ssl_hash_current_message(hs) ||
!tls13_derive_handshake_secrets(hs) ||
!tls13_set_traffic_key(ssl, evp_aead_open, hs->server_handshake_secret,
hs->hash_len) ||
@@ -358,7 +356,7 @@
return ssl_hs_error;
}
- if (!ssl_hash_current_message(ssl)) {
+ if (!ssl_hash_current_message(hs)) {
return ssl_hs_error;
}
@@ -414,7 +412,7 @@
sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free);
hs->ca_names = ca_sk;
- if (!ssl_hash_current_message(ssl)) {
+ if (!ssl_hash_current_message(hs)) {
return ssl_hs_error;
}
@@ -426,7 +424,7 @@
SSL *const ssl = hs->ssl;
if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
!tls13_process_certificate(hs, 0 /* certificate required */) ||
- !ssl_hash_current_message(ssl)) {
+ !ssl_hash_current_message(hs)) {
return ssl_hs_error;
}
@@ -439,7 +437,7 @@
SSL *const ssl = hs->ssl;
if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
!tls13_process_certificate_verify(hs) ||
- !ssl_hash_current_message(ssl)) {
+ !ssl_hash_current_message(hs)) {
return ssl_hs_error;
}
@@ -451,7 +449,7 @@
SSL *const ssl = hs->ssl;
if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) ||
!tls13_process_finished(hs) ||
- !ssl_hash_current_message(ssl) ||
+ !ssl_hash_current_message(hs) ||
/* Update the secret to the master secret and derive traffic keys. */
!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len) ||
!tls13_derive_application_secrets(hs)) {
@@ -536,7 +534,7 @@
CBB cbb, body;
if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_CHANNEL_ID) ||
- !tls1_write_channel_id(ssl, &body) ||
+ !tls1_write_channel_id(hs, &body) ||
!ssl_add_message_cbb(ssl, &cbb)) {
CBB_cleanup(&cbb);
return ssl_hs_error;
diff --git a/ssl/tls13_enc.c b/ssl/tls13_enc.c
index ea9dce8..4d140e3 100644
--- a/ssl/tls13_enc.c
+++ b/ssl/tls13_enc.c
@@ -29,28 +29,25 @@
int tls13_init_key_schedule(SSL_HANDSHAKE *hs) {
- SSL *const ssl = hs->ssl;
- const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
+ if (!SSL_TRANSCRIPT_init_hash(&hs->transcript, ssl3_protocol_version(hs->ssl),
+ hs->ssl->s3->tmp.new_cipher->algorithm_prf)) {
+ return 0;
+ }
- hs->hash_len = EVP_MD_size(digest);
+
+ hs->hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript);
/* Initialize the secret to the zero key. */
OPENSSL_memset(hs->secret, 0, hs->hash_len);
- /* Initialize the rolling hashes and release the handshake buffer. */
- if (!ssl3_init_handshake_hash(ssl)) {
- return 0;
- }
- ssl3_free_handshake_buffer(ssl);
+ SSL_TRANSCRIPT_free_buffer(&hs->transcript);
return 1;
}
int tls13_advance_key_schedule(SSL_HANDSHAKE *hs, const uint8_t *in,
size_t len) {
- const EVP_MD *digest =
- ssl_get_handshake_digest(ssl_get_algorithm_prf(hs->ssl));
-
- return HKDF_extract(hs->secret, &hs->hash_len, digest, in, len, hs->secret,
+ return HKDF_extract(hs->secret, &hs->hash_len,
+ SSL_TRANSCRIPT_md(&hs->transcript), in, len, hs->secret,
hs->hash_len);
}
@@ -83,35 +80,21 @@
return ret;
}
-int tls13_get_context_hash(SSL *ssl, uint8_t *out, size_t *out_len) {
- EVP_MD_CTX ctx;
- EVP_MD_CTX_init(&ctx);
- unsigned handshake_len = 0;
- int ok = EVP_MD_CTX_copy_ex(&ctx, &ssl->s3->handshake_hash) &&
- EVP_DigestFinal_ex(&ctx, out, &handshake_len);
- EVP_MD_CTX_cleanup(&ctx);
- if (ok) {
- *out_len = handshake_len;
- }
- return ok;
-}
-
/* derive_secret derives a secret of length |len| and writes the result in |out|
* with the given label and the current base secret and most recently-saved
* handshake context. It returns one on success and zero on error. */
static int derive_secret(SSL_HANDSHAKE *hs, uint8_t *out, size_t len,
const uint8_t *label, size_t label_len) {
- SSL *const ssl = hs->ssl;
- const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
-
uint8_t context_hash[EVP_MAX_MD_SIZE];
size_t context_hash_len;
- if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len)) {
+ if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash,
+ &context_hash_len)) {
return 0;
}
- return hkdf_expand_label(out, digest, hs->secret, hs->hash_len, label,
- label_len, context_hash, context_hash_len, len);
+ return hkdf_expand_label(out, SSL_TRANSCRIPT_md(&hs->transcript), hs->secret,
+ hs->hash_len, label, label_len, context_hash,
+ context_hash_len, len);
}
int tls13_set_traffic_key(SSL *ssl, enum evp_aead_direction_t direction,
@@ -124,7 +107,6 @@
/* Look up cipher suite properties. */
const EVP_AEAD *aead;
- const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
size_t discard;
if (!ssl_cipher_get_evp_aead(&aead, &discard, &discard,
SSL_get_session(ssl)->cipher,
@@ -132,6 +114,9 @@
return 0;
}
+ const EVP_MD *digest = ssl_get_handshake_digest(
+ SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
+
/* Derive the key. */
size_t key_len = EVP_AEAD_key_length(aead);
uint8_t key[EVP_AEAD_MAX_KEY_LENGTH];
@@ -226,7 +211,8 @@
"application traffic secret";
int tls13_rotate_traffic_key(SSL *ssl, enum evp_aead_direction_t direction) {
- const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
+ const EVP_MD *digest = ssl_get_handshake_digest(
+ SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
uint8_t *secret;
size_t secret_len;
@@ -287,7 +273,6 @@
int tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len,
int is_server) {
SSL *const ssl = hs->ssl;
- const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
const uint8_t *traffic_secret;
if (is_server == ssl->server) {
@@ -298,9 +283,11 @@
uint8_t context_hash[EVP_MAX_MD_SIZE];
size_t context_hash_len;
- if (!tls13_get_context_hash(ssl, context_hash, &context_hash_len) ||
- !tls13_verify_data(digest, out, out_len, traffic_secret, hs->hash_len,
- context_hash, context_hash_len)) {
+ if (!SSL_TRANSCRIPT_get_hash(&hs->transcript, context_hash,
+ &context_hash_len) ||
+ !tls13_verify_data(SSL_TRANSCRIPT_md(&hs->transcript), out, out_len,
+ traffic_secret, hs->hash_len, context_hash,
+ context_hash_len)) {
return 0;
}
return 1;
@@ -310,7 +297,8 @@
const char *label, size_t label_len,
const uint8_t *context, size_t context_len,
int use_context) {
- const EVP_MD *digest = ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl));
+ const EVP_MD *digest = ssl_get_handshake_digest(
+ SSL_get_session(ssl)->cipher->algorithm_prf, ssl3_protocol_version(ssl));
const uint8_t *hash = NULL;
size_t hash_len = 0;
@@ -325,8 +313,8 @@
static const char kTLS13LabelPSKBinder[] = "resumption psk binder key";
-static int tls13_psk_binder(SSL *ssl, uint8_t *out, const EVP_MD *digest,
- uint8_t *psk, size_t psk_len, uint8_t *context,
+static int tls13_psk_binder(uint8_t *out, const EVP_MD *digest, uint8_t *psk,
+ size_t psk_len, uint8_t *context,
size_t context_len, size_t hash_len) {
uint8_t binder_context[EVP_MAX_MD_SIZE];
unsigned binder_context_len;
@@ -355,9 +343,13 @@
return 1;
}
-int tls13_write_psk_binder(SSL *ssl, uint8_t *msg, size_t len) {
- const EVP_MD *digest =
- ssl_get_handshake_digest(ssl->session->cipher->algorithm_prf);
+int tls13_write_psk_binder(SSL_HANDSHAKE *hs, uint8_t *msg, size_t len) {
+ SSL *const ssl = hs->ssl;
+ const EVP_MD *digest = SSL_SESSION_get_digest(ssl->session, ssl);
+ if (digest == NULL) {
+ OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
+ return 0;
+ }
size_t hash_len = EVP_MD_size(digest);
if (len < hash_len + 3) {
@@ -370,8 +362,8 @@
uint8_t context[EVP_MAX_MD_SIZE];
unsigned context_len;
if (!EVP_DigestInit_ex(&ctx, digest, NULL) ||
- !EVP_DigestUpdate(&ctx, ssl->s3->handshake_buffer->data,
- ssl->s3->handshake_buffer->length) ||
+ !EVP_DigestUpdate(&ctx, hs->transcript.buffer->data,
+ hs->transcript.buffer->length) ||
!EVP_DigestUpdate(&ctx, msg, len - hash_len - 3) ||
!EVP_DigestFinal_ex(&ctx, context, &context_len)) {
EVP_MD_CTX_cleanup(&ctx);
@@ -381,9 +373,9 @@
EVP_MD_CTX_cleanup(&ctx);
uint8_t verify_data[EVP_MAX_MD_SIZE] = {0};
- if (!tls13_psk_binder(ssl, verify_data, digest, ssl->session->master_key,
- ssl->session->master_key_length, context,
- context_len, hash_len)) {
+ if (!tls13_psk_binder(verify_data, digest, ssl->session->master_key,
+ ssl->session->master_key_length, context, context_len,
+ hash_len)) {
return 0;
}
@@ -391,16 +383,14 @@
return 1;
}
-int tls13_verify_psk_binder(SSL *ssl, SSL_SESSION *session,
+int tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session,
CBS *binders) {
- const EVP_MD *digest =
- ssl_get_handshake_digest(session->cipher->algorithm_prf);
- size_t hash_len = EVP_MD_size(digest);
+ size_t hash_len = SSL_TRANSCRIPT_digest_len(&hs->transcript);
/* Get the full ClientHello, including message header. It must be large enough
* to exclude the binders. */
CBS message;
- ssl->method->get_current_message(ssl, &message);
+ hs->ssl->method->get_current_message(hs->ssl, &message);
if (CBS_len(&message) < CBS_len(binders) + 2) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
@@ -411,23 +401,25 @@
uint8_t context[EVP_MAX_MD_SIZE];
unsigned context_len;
if (!EVP_Digest(CBS_data(&message), CBS_len(&message) - CBS_len(binders) - 2,
- context, &context_len, digest, NULL)) {
+ context, &context_len, SSL_TRANSCRIPT_md(&hs->transcript),
+ NULL)) {
return 0;
}
uint8_t verify_data[EVP_MAX_MD_SIZE] = {0};
CBS binder;
- if (!tls13_psk_binder(ssl, verify_data, digest, session->master_key,
- session->master_key_length, context, context_len,
- hash_len) ||
+ if (!tls13_psk_binder(verify_data, SSL_TRANSCRIPT_md(&hs->transcript),
+ session->master_key, session->master_key_length,
+ context, context_len, hash_len) ||
/* We only consider the first PSK, so compare against the first binder. */
!CBS_get_u8_length_prefixed(binders, &binder)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
return 0;
}
- int binder_ok = CBS_len(&binder) == hash_len &&
- CRYPTO_memcmp(CBS_data(&binder), verify_data, hash_len) == 0;
+ int binder_ok =
+ CBS_len(&binder) == hash_len &&
+ CRYPTO_memcmp(CBS_data(&binder), verify_data, hash_len) == 0;
#if defined(BORINGSSL_UNSAFE_FUZZER_MODE)
binder_ok = 1;
#endif
diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c
index e9ba86f..3ef0c15 100644
--- a/ssl/tls13_server.c
+++ b/ssl/tls13_server.c
@@ -157,6 +157,14 @@
return ssl_hs_error;
}
+ /* The PRF hash is now known. Set up the key schedule and hash the
+ * ClientHello. */
+ if (!tls13_init_key_schedule(hs) ||
+ !ssl_hash_current_message(hs)) {
+ return ssl_hs_error;
+ }
+
+
/* Decode the ticket if we agree on a PSK key exchange mode. */
uint8_t alert = SSL_AD_DECODE_ERROR;
SSL_SESSION *session = NULL;
@@ -207,7 +215,7 @@
}
} else {
/* Check the PSK binder. */
- if (!tls13_verify_psk_binder(ssl, session, &binders)) {
+ if (!tls13_verify_psk_binder(hs, session, &binders)) {
SSL_SESSION_free(session);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECRYPT_ERROR);
return ssl_hs_error;
@@ -243,22 +251,13 @@
return ssl_hs_error;
}
- /* The PRF hash is now known. Set up the key schedule and hash the
- * ClientHello. */
- size_t hash_len =
- EVP_MD_size(ssl_get_handshake_digest(ssl_get_algorithm_prf(ssl)));
- if (!tls13_init_key_schedule(hs) ||
- !ssl_hash_current_message(ssl)) {
- return ssl_hs_error;
- }
-
/* Incorporate the PSK into the running secret. */
if (ssl->s3->session_reused) {
if (!tls13_advance_key_schedule(hs, ssl->s3->new_session->master_key,
ssl->s3->new_session->master_key_length)) {
return ssl_hs_error;
}
- } else if (!tls13_advance_key_schedule(hs, kZeroes, hash_len)) {
+ } else if (!tls13_advance_key_schedule(hs, kZeroes, hs->hash_len)) {
return ssl_hs_error;
}
@@ -323,7 +322,7 @@
return ssl_hs_error;
}
- if (!ssl_hash_current_message(ssl)) {
+ if (!ssl_hash_current_message(hs)) {
return ssl_hs_error;
}
@@ -485,7 +484,7 @@
if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE) ||
!tls13_process_certificate(hs, allow_anonymous) ||
- !ssl_hash_current_message(ssl)) {
+ !ssl_hash_current_message(hs)) {
return ssl_hs_error;
}
@@ -504,7 +503,7 @@
if (!ssl_check_message_type(ssl, SSL3_MT_CERTIFICATE_VERIFY) ||
!tls13_process_certificate_verify(hs) ||
- !ssl_hash_current_message(ssl)) {
+ !ssl_hash_current_message(hs)) {
return ssl_hs_error;
}
@@ -513,15 +512,14 @@
}
static enum ssl_hs_wait_t do_process_channel_id(SSL_HANDSHAKE *hs) {
- SSL *const ssl = hs->ssl;
- if (!ssl->s3->tlsext_channel_id_valid) {
+ if (!hs->ssl->s3->tlsext_channel_id_valid) {
hs->tls13_state = state_process_client_finished;
return ssl_hs_ok;
}
- if (!ssl_check_message_type(ssl, SSL3_MT_CHANNEL_ID) ||
- !tls1_verify_channel_id(ssl) ||
- !ssl_hash_current_message(ssl)) {
+ if (!ssl_check_message_type(hs->ssl, SSL3_MT_CHANNEL_ID) ||
+ !tls1_verify_channel_id(hs) ||
+ !ssl_hash_current_message(hs)) {
return ssl_hs_error;
}
@@ -533,7 +531,7 @@
SSL *const ssl = hs->ssl;
if (!ssl_check_message_type(ssl, SSL3_MT_FINISHED) ||
!tls13_process_finished(hs) ||
- !ssl_hash_current_message(ssl) ||
+ !ssl_hash_current_message(hs) ||
/* evp_aead_seal keys have already been switched. */
!tls13_set_traffic_key(ssl, evp_aead_open, hs->client_traffic_secret_0,
hs->hash_len) ||