Decouple the handshake buffer and digest.
The handshake hash is initialized from the buffer as soon as the cipher
is known. When adding a message to the transcript, independently update
the buffer and rolling hash, whichever is active. This avoids the
complications around dont_free_handshake_buffer and EMS.
BUG=492371
Change-Id: I3b1065796a50fd1be5d42ead7210c2f253ef0aca
Reviewed-on: https://boringssl-review.googlesource.com/5615
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/s3_enc.c b/ssl/s3_enc.c
index 97555cd..af72549 100644
--- a/ssl/s3_enc.c
+++ b/ssl/s3_enc.c
@@ -235,49 +235,19 @@
s->s3->tmp.key_block_length = 0;
}
-int ssl3_init_finished_mac(SSL *s) {
- BIO_free(s->s3->handshake_buffer);
- ssl3_free_digest_list(s);
- s->s3->handshake_buffer = BIO_new(BIO_s_mem());
- if (s->s3->handshake_buffer == NULL) {
+int ssl3_init_handshake_buffer(SSL *ssl) {
+ ssl3_free_handshake_buffer(ssl);
+ ssl3_free_handshake_hash(ssl);
+ ssl->s3->handshake_buffer = BIO_new(BIO_s_mem());
+ if (ssl->s3->handshake_buffer == NULL) {
return 0;
}
- BIO_set_close(s->s3->handshake_buffer, BIO_CLOSE);
+ BIO_set_close(ssl->s3->handshake_buffer, BIO_CLOSE);
return 1;
}
-void ssl3_free_digest_list(SSL *s) {
- int i;
- if (!s->s3->handshake_dgst) {
- return;
- }
- for (i = 0; i < SSL_MAX_DIGEST; i++) {
- if (s->s3->handshake_dgst[i]) {
- EVP_MD_CTX_destroy(s->s3->handshake_dgst[i]);
- }
- }
- OPENSSL_free(s->s3->handshake_dgst);
- s->s3->handshake_dgst = NULL;
-}
-
-int ssl3_finish_mac(SSL *s, const uint8_t *buf, int len) {
- int i;
-
- if (s->s3->handshake_buffer) {
- return BIO_write(s->s3->handshake_buffer, (void *)buf, len) >= 0;
- }
-
- for (i = 0; i < SSL_MAX_DIGEST; i++) {
- if (s->s3->handshake_dgst[i] != NULL) {
- EVP_DigestUpdate(s->s3->handshake_dgst[i], buf, len);
- }
- }
- return 1;
-}
-
-int ssl3_digest_cached_records(
- SSL *s, enum should_free_handshake_buffer_t should_free_handshake_buffer) {
+int ssl3_init_handshake_hash(SSL *ssl) {
int i;
uint32_t mask;
const EVP_MD *md;
@@ -285,45 +255,81 @@
size_t hdatalen;
/* Allocate handshake_dgst array */
- ssl3_free_digest_list(s);
- s->s3->handshake_dgst = OPENSSL_malloc(SSL_MAX_DIGEST * sizeof(EVP_MD_CTX *));
- if (s->s3->handshake_dgst == NULL) {
+ ssl3_free_handshake_hash(ssl);
+ ssl->s3->handshake_dgst = OPENSSL_malloc(SSL_MAX_DIGEST *
+ sizeof(EVP_MD_CTX *));
+ if (ssl->s3->handshake_dgst == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
return 0;
}
- memset(s->s3->handshake_dgst, 0, SSL_MAX_DIGEST * sizeof(EVP_MD_CTX *));
- if (!BIO_mem_contents(s->s3->handshake_buffer, &hdata, &hdatalen)) {
+ memset(ssl->s3->handshake_dgst, 0, SSL_MAX_DIGEST * sizeof(EVP_MD_CTX *));
+ if (!BIO_mem_contents(ssl->s3->handshake_buffer, &hdata, &hdatalen)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_HANDSHAKE_LENGTH);
return 0;
}
/* Loop through bits of algorithm_prf field and create MD_CTX-es */
for (i = 0; ssl_get_handshake_digest(&mask, &md, i); i++) {
- if ((mask & ssl_get_algorithm_prf(s)) && md) {
- s->s3->handshake_dgst[i] = EVP_MD_CTX_create();
- if (s->s3->handshake_dgst[i] == NULL) {
+ if ((mask & ssl_get_algorithm_prf(ssl)) && md) {
+ ssl->s3->handshake_dgst[i] = EVP_MD_CTX_create();
+ if (ssl->s3->handshake_dgst[i] == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
return 0;
}
- if (!EVP_DigestInit_ex(s->s3->handshake_dgst[i], md, NULL)) {
- EVP_MD_CTX_destroy(s->s3->handshake_dgst[i]);
- s->s3->handshake_dgst[i] = NULL;
+ if (!EVP_DigestInit_ex(ssl->s3->handshake_dgst[i], md, NULL)) {
+ EVP_MD_CTX_destroy(ssl->s3->handshake_dgst[i]);
+ ssl->s3->handshake_dgst[i] = NULL;
OPENSSL_PUT_ERROR(SSL, ERR_LIB_EVP);
return 0;
}
- EVP_DigestUpdate(s->s3->handshake_dgst[i], hdata, hdatalen);
+ EVP_DigestUpdate(ssl->s3->handshake_dgst[i], hdata, hdatalen);
} else {
- s->s3->handshake_dgst[i] = NULL;
+ ssl->s3->handshake_dgst[i] = NULL;
}
}
- if (should_free_handshake_buffer == free_handshake_buffer) {
- /* Free handshake_buffer BIO */
- BIO_free(s->s3->handshake_buffer);
- s->s3->handshake_buffer = NULL;
+ return 1;
+}
+
+void ssl3_free_handshake_hash(SSL *ssl) {
+ int i;
+ if (!ssl->s3->handshake_dgst) {
+ return;
+ }
+ for (i = 0; i < SSL_MAX_DIGEST; i++) {
+ if (ssl->s3->handshake_dgst[i]) {
+ EVP_MD_CTX_destroy(ssl->s3->handshake_dgst[i]);
+ }
+ }
+ OPENSSL_free(ssl->s3->handshake_dgst);
+ ssl->s3->handshake_dgst = NULL;
+}
+
+void ssl3_free_handshake_buffer(SSL *ssl) {
+ BIO_free(ssl->s3->handshake_buffer);
+ ssl->s3->handshake_buffer = NULL;
+}
+
+int ssl3_update_handshake_hash(SSL *ssl, 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. */
+
+ /* TODO(davidben): Replace |handshake_buffer| with a simpler type that doesn't
+ * require a cast. */
+ if (ssl->s3->handshake_buffer != NULL &&
+ BIO_write(ssl->s3->handshake_buffer, in, (int)in_len) < 0) {
+ return 0;
}
+ if (ssl->s3->handshake_dgst != NULL) {
+ int i;
+ for (i = 0; i < SSL_MAX_DIGEST; i++) {
+ if (ssl->s3->handshake_dgst[i] != NULL) {
+ EVP_DigestUpdate(ssl->s3->handshake_dgst[i], in, in_len);
+ }
+ }
+ }
return 1;
}
@@ -357,11 +363,6 @@
uint8_t md_buf[EVP_MAX_MD_SIZE];
EVP_MD_CTX ctx, *d = NULL;
- if (s->s3->handshake_buffer &&
- !ssl3_digest_cached_records(s, free_handshake_buffer)) {
- return 0;
- }
-
/* Search for digest of specified type in the handshake_dgst array. */
for (i = 0; i < SSL_MAX_DIGEST; i++) {
if (s->s3->handshake_dgst[i] &&