Introduce bssl::Array<T> and use it in SSLKeyShare.
An Array<T> is an owning Span<T>. It's similar to absl::FixedArray<T>
but plays well with OPENSSL_malloc and doesn't implement inlining. With
OPENSSL_cleanse folded into OPENSSL_free, we could go nuts with
UniquePtr<uint8_t>, but having the pointer and length tied together is
nice for other reasons. Notably, Array<T> plays great with Span<T>.
Also switch the other parameter to a Span.
Bug: 132
Change-Id: I4cdcf810cf2838208c8ba9fcc6215c1e369dffb8
Reviewed-on: https://boringssl-review.googlesource.com/20667
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/handshake_client.cc b/ssl/handshake_client.cc
index 3916692..62e15e2 100644
--- a/ssl/handshake_client.cc
+++ b/ssl/handshake_client.cc
@@ -976,10 +976,13 @@
// Initialize ECDH and save the peer public key for later.
hs->key_share = SSLKeyShare::Create(group_id);
+ uint8_t *peer_key = nullptr;
+ size_t peer_key_len = 0;
if (!hs->key_share ||
- !CBS_stow(&point, &hs->peer_key, &hs->peer_key_len)) {
+ !CBS_stow(&point, &peer_key, &peer_key_len)) {
return ssl_hs_error;
}
+ hs->peer_key.Reset(peer_key, peer_key_len);
} else if (!(alg_k & SSL_kPSK)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_MESSAGE);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
@@ -1229,8 +1232,7 @@
return ssl_hs_error;
}
- uint8_t *pms = NULL;
- size_t pms_len = 0;
+ Array<uint8_t> pms;
uint32_t alg_k = hs->new_cipher->algorithm_mkey;
uint32_t alg_a = hs->new_cipher->algorithm_auth;
@@ -1240,7 +1242,7 @@
if (alg_a & SSL_aPSK) {
if (ssl->psk_client_callback == NULL) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_NO_CLIENT_CB);
- goto err;
+ return ssl_hs_error;
}
char identity[PSK_MAX_IDENTITY_LEN + 1];
@@ -1251,7 +1253,7 @@
if (psk_len == 0) {
OPENSSL_PUT_ERROR(SSL, SSL_R_PSK_IDENTITY_NOT_FOUND);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
- goto err;
+ return ssl_hs_error;
}
assert(psk_len <= PSK_MAX_PSK_LEN);
@@ -1259,7 +1261,7 @@
hs->new_session->psk_identity = BUF_strdup(identity);
if (hs->new_session->psk_identity == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
+ return ssl_hs_error;
}
// Write out psk_identity.
@@ -1268,29 +1270,26 @@
!CBB_add_bytes(&child, (const uint8_t *)identity,
OPENSSL_strnlen(identity, sizeof(identity))) ||
!CBB_flush(&body)) {
- goto err;
+ return ssl_hs_error;
}
}
- // Depending on the key exchange method, compute |pms| and |pms_len|.
+ // Depending on the key exchange method, compute |pms|.
if (alg_k & SSL_kRSA) {
- pms_len = SSL_MAX_MASTER_KEY_LENGTH;
- pms = (uint8_t *)OPENSSL_malloc(pms_len);
- if (pms == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
+ if (!pms.Init(SSL_MAX_MASTER_KEY_LENGTH)) {
+ return ssl_hs_error;
}
RSA *rsa = EVP_PKEY_get0_RSA(hs->peer_pubkey.get());
if (rsa == NULL) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- goto err;
+ return ssl_hs_error;
}
pms[0] = hs->client_version >> 8;
pms[1] = hs->client_version & 0xff;
if (!RAND_bytes(&pms[2], SSL_MAX_MASTER_KEY_LENGTH - 2)) {
- goto err;
+ return ssl_hs_error;
}
CBB child, *enc_pms = &body;
@@ -1298,56 +1297,50 @@
// In TLS, there is a length prefix.
if (ssl->version > SSL3_VERSION) {
if (!CBB_add_u16_length_prefixed(&body, &child)) {
- goto err;
+ return ssl_hs_error;
}
enc_pms = &child;
}
uint8_t *ptr;
if (!CBB_reserve(enc_pms, &ptr, RSA_size(rsa)) ||
- !RSA_encrypt(rsa, &enc_pms_len, ptr, RSA_size(rsa), pms, pms_len,
- RSA_PKCS1_PADDING) ||
+ !RSA_encrypt(rsa, &enc_pms_len, ptr, RSA_size(rsa), pms.data(),
+ pms.size(), RSA_PKCS1_PADDING) ||
!CBB_did_write(enc_pms, enc_pms_len) ||
!CBB_flush(&body)) {
- goto err;
+ return ssl_hs_error;
}
} else if (alg_k & SSL_kECDHE) {
// Generate a keypair and serialize the public half.
CBB child;
if (!CBB_add_u8_length_prefixed(&body, &child)) {
- goto err;
+ return ssl_hs_error;
}
// Compute the premaster.
uint8_t alert = SSL_AD_DECODE_ERROR;
- if (!hs->key_share->Accept(&child, &pms, &pms_len, &alert, hs->peer_key,
- hs->peer_key_len)) {
+ if (!hs->key_share->Accept(&child, &pms, &alert, hs->peer_key)) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
- goto err;
+ return ssl_hs_error;
}
if (!CBB_flush(&body)) {
- goto err;
+ return ssl_hs_error;
}
// The key exchange state may now be discarded.
hs->key_share.reset();
- OPENSSL_free(hs->peer_key);
- hs->peer_key = NULL;
- hs->peer_key_len = 0;
+ hs->peer_key.Reset();
} else if (alg_k & SSL_kPSK) {
// For plain PSK, other_secret is a block of 0s with the same length as
// the pre-shared key.
- pms_len = psk_len;
- pms = (uint8_t *)OPENSSL_malloc(pms_len);
- if (pms == NULL) {
- OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
+ if (!pms.Init(psk_len)) {
+ return ssl_hs_error;
}
- OPENSSL_memset(pms, 0, pms_len);
+ OPENSSL_memset(pms.data(), 0, pms.size());
} else {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_HANDSHAKE_FAILURE);
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
- goto err;
+ return ssl_hs_error;
}
// For a PSK cipher suite, other_secret is combined with the pre-shared
@@ -1358,40 +1351,33 @@
uint8_t *new_pms;
size_t new_pms_len;
- if (!CBB_init(pms_cbb.get(), 2 + psk_len + 2 + pms_len) ||
+ if (!CBB_init(pms_cbb.get(), 2 + psk_len + 2 + pms.size()) ||
!CBB_add_u16_length_prefixed(pms_cbb.get(), &child) ||
- !CBB_add_bytes(&child, pms, pms_len) ||
+ !CBB_add_bytes(&child, pms.data(), pms.size()) ||
!CBB_add_u16_length_prefixed(pms_cbb.get(), &child) ||
!CBB_add_bytes(&child, psk, psk_len) ||
!CBB_finish(pms_cbb.get(), &new_pms, &new_pms_len)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE);
- goto err;
+ return ssl_hs_error;
}
- OPENSSL_free(pms);
- pms = new_pms;
- pms_len = new_pms_len;
+ pms.Reset(new_pms, new_pms_len);
}
// The message must be added to the finished hash before calculating the
// master secret.
if (!ssl_add_message_cbb(ssl, cbb.get())) {
- goto err;
+ return ssl_hs_error;
}
hs->new_session->master_key_length = tls1_generate_master_secret(
- hs, hs->new_session->master_key, pms, pms_len);
+ hs, hs->new_session->master_key, pms.data(), pms.size());
if (hs->new_session->master_key_length == 0) {
- goto err;
+ return ssl_hs_error;
}
hs->new_session->extended_master_secret = hs->extended_master_secret;
- OPENSSL_free(pms);
hs->state = state_send_client_certificate_verify;
return ssl_hs_ok;
-
-err:
- OPENSSL_free(pms);
- return ssl_hs_error;
}
static enum ssl_hs_wait_t do_send_client_certificate_verify(SSL_HANDSHAKE *hs) {