Make constant-sized calls to Span::first/last/subspan compile-time sized. This uses the newly added first<N>, last<N> and subspan<S, N> methods. Also, changed subspan<0, N> to first<N> when it could be shown that the input span has at least N elements based on checks/asserts before it. This makes the return type compile-time sized even if the input span is not. NOT doing thsis however if: - The span is only used within the same function in a simple scope with no chance for errors compile-time checks would catch - The span is only passed to other functions or returned in cases where obviously the span has to be runtime sized (like if calling through a function pointer or returning as a return value) - The span is runtime-sized based on a runtime-sized function argument or other data source that can't feasibly be made statically sized Tested: IDA/Diaphora and ghidriff find no differences in generated code other than type identifiers with the extra template argument. Change-Id: I0eb52abd88f9f55a6651ddc333767e4e9345c03f Bug: 390229582 Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/82887 Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com>
diff --git a/ssl/extensions.cc b/ssl/extensions.cc index 1bce374..51e8e37 100644 --- a/ssl/extensions.cc +++ b/ssl/extensions.cc
@@ -2613,9 +2613,9 @@ if (ssl_has_CA_names(hs->config)) { CBB ca_contents; if (!CBB_add_u16(out_compressible, - TLSEXT_TYPE_certificate_authorities) || // - !CBB_add_u16_length_prefixed(out_compressible, &ca_contents) || // - !ssl_add_CA_names(hs, &ca_contents) || // + TLSEXT_TYPE_certificate_authorities) || // + !CBB_add_u16_length_prefixed(out_compressible, &ca_contents) || // + !ssl_add_CA_names(hs, &ca_contents) || // !CBB_flush(out_compressible)) { return false; } @@ -3221,7 +3221,7 @@ uint8_t prover_secret[spake2plus::kSecretSize]; if (!hs->pake_prover->ComputeConfirmation( prover_confirm, prover_secret, - pake_msg_span.subspan(0, spake2plus::kShareSize), + pake_msg_span.first<spake2plus::kShareSize>(), pake_msg_span.subspan(spake2plus::kShareSize))) { // Record a failure before releasing the answer to the client. hs->credential->ClaimPAKEAttempt(); @@ -4337,11 +4337,11 @@ assert(ticket.size() >= SSL_TICKET_KEY_NAME_LEN + EVP_MAX_IV_LENGTH); ScopedEVP_CIPHER_CTX cipher_ctx; ScopedHMAC_CTX hmac_ctx; - auto name = ticket.subspan(0, SSL_TICKET_KEY_NAME_LEN); + auto name = ticket.first<SSL_TICKET_KEY_NAME_LEN>(); // The actual IV is shorter, but the length is determined by the callback's // chosen cipher. Instead we pass in |EVP_MAX_IV_LENGTH| worth of IV to ensure // the callback has enough. - auto iv = ticket.subspan(SSL_TICKET_KEY_NAME_LEN, EVP_MAX_IV_LENGTH); + auto iv = ticket.subspan<SSL_TICKET_KEY_NAME_LEN, EVP_MAX_IV_LENGTH>(); int cb_ret = hs->ssl->session_ctx->ticket_key_cb( hs->ssl, const_cast<uint8_t *>(name.data()), const_cast<uint8_t *>(iv.data()), cipher_ctx.get(), hmac_ctx.get(), @@ -4370,7 +4370,7 @@ } const EVP_CIPHER *cipher = EVP_aes_128_cbc(); - auto name = ticket.subspan(0, SSL_TICKET_KEY_NAME_LEN); + auto name = ticket.first<SSL_TICKET_KEY_NAME_LEN>(); auto iv = ticket.subspan(SSL_TICKET_KEY_NAME_LEN, EVP_CIPHER_iv_length(cipher));
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc index 769dcfc..c96dedc 100644 --- a/ssl/handshake_client.cc +++ b/ssl/handshake_client.cc
@@ -687,7 +687,7 @@ sizeof(kJDK11DowngradeRandom) == sizeof(kTLS13DowngradeRandom), "downgrade signals have different size"); auto suffix = - Span(ssl->s3->server_random).last(sizeof(kTLS13DowngradeRandom)); + Span(ssl->s3->server_random).last<sizeof(kTLS13DowngradeRandom)>(); if (suffix == kTLS12DowngradeRandom || suffix == kTLS13DowngradeRandom || suffix == kJDK11DowngradeRandom) { OPENSSL_PUT_ERROR(SSL, SSL_R_TLS13_DOWNGRADE);
diff --git a/ssl/internal.h b/ssl/internal.h index e62202a..0bcc083 100644 --- a/ssl/internal.h +++ b/ssl/internal.h
@@ -1358,10 +1358,11 @@ // |transcript| with |msg|. The |ECH_CONFIRMATION_SIGNAL_LEN| bytes from // |offset| in |msg| are replaced with zeros before hashing. This function // returns true on success, and false on failure. -bool ssl_ech_accept_confirmation(const SSL_HANDSHAKE *hs, Span<uint8_t> out, - Span<const uint8_t> client_random, - const SSLTranscript &transcript, bool is_hrr, - Span<const uint8_t> msg, size_t offset); +bool ssl_ech_accept_confirmation( + const SSL_HANDSHAKE *hs, Span<uint8_t, ECH_CONFIRMATION_SIGNAL_LEN> out, + Span<const uint8_t, SSL3_RANDOM_SIZE> client_random, + const SSLTranscript &transcript, bool is_hrr, Span<const uint8_t> msg, + size_t offset); // ssl_is_valid_ech_public_name returns true if |public_name| is a valid ECH // public name and false otherwise. It is exported for testing.
diff --git a/ssl/ssl_transcript.cc b/ssl/ssl_transcript.cc index 6a445be..101da70 100644 --- a/ssl/ssl_transcript.cc +++ b/ssl/ssl_transcript.cc
@@ -168,8 +168,8 @@ // transcript format as TLS 1.3 is used. This means we write the 1-byte // msg_type, 3-byte length, then skip 2+3+3 bytes for the DTLS-specific // fields that get omitted. - if (!AddToBufferOrHash(in.subspan(0, 4)) || - !AddToBufferOrHash(in.subspan(12))) { + if (!AddToBufferOrHash(in.first<4>()) || + !AddToBufferOrHash(in.subspan<12>())) { return false; } return true;
diff --git a/ssl/tls13_enc.cc b/ssl/tls13_enc.cc index f94aea7..c5baa83 100644 --- a/ssl/tls13_enc.cc +++ b/ssl/tls13_enc.cc
@@ -284,7 +284,7 @@ return false; } uint32_t counter = CRYPTO_load_u32_le(sample.data()); - Span<const uint8_t> nonce = sample.subspan(4); + auto nonce = sample.subspan<4>(); OPENSSL_memset(out.data(), 0, out.size()); CRYPTO_chacha_20(out.data(), out.data(), out.size(), key_, nonce.data(), counter); @@ -558,8 +558,8 @@ if (truncated.size() < DTLS1_HM_HEADER_LENGTH) { return false; } - auto header = truncated.subspan(0, 4); - auto body = truncated.subspan(12); + auto header = truncated.first<4>(); + auto body = truncated.subspan<12>(); if (!transcript.CopyToHashContext(ctx.get(), digest) || !EVP_DigestUpdate(ctx.get(), header.data(), header.size()) || !EVP_DigestUpdate(ctx.get(), body.data(), body.size()) || @@ -644,10 +644,11 @@ ECH_CONFIRMATION_SIGNAL_LEN; } -bool ssl_ech_accept_confirmation(const SSL_HANDSHAKE *hs, Span<uint8_t> out, - Span<const uint8_t> client_random, - const SSLTranscript &transcript, bool is_hrr, - Span<const uint8_t> msg, size_t offset) { +bool ssl_ech_accept_confirmation( + const SSL_HANDSHAKE *hs, Span<uint8_t, ECH_CONFIRMATION_SIGNAL_LEN> out, + Span<const uint8_t, SSL3_RANDOM_SIZE> client_random, + const SSLTranscript &transcript, bool is_hrr, Span<const uint8_t> msg, + size_t offset) { // See draft-ietf-tls-esni-13, sections 7.2 and 7.2.1. static const uint8_t kZeros[EVP_MAX_MD_SIZE] = {0}; @@ -659,7 +660,9 @@ // We represent DTLS messages with the longer DTLS 1.2 header, but DTLS 1.3 // removes the extra fields from the transcript. - auto header = msg.subspan(0, SSL3_HM_HEADER_LENGTH); + // + // Size bound implied by ECH_CONFIRMATION_SIGNAL_LEN >= SSL3_HM_HEADER_LENGTH. + auto header = msg.first<SSL3_HM_HEADER_LENGTH>(); size_t full_header_len = SSL_is_dtls(hs->ssl) ? DTLS1_HM_HEADER_LENGTH : SSL3_HM_HEADER_LENGTH; auto before_zeros = msg.subspan(full_header_len, offset - full_header_len); @@ -685,7 +688,6 @@ return false; } - assert(out.size() == ECH_CONFIRMATION_SIGNAL_LEN); return hkdf_expand_label( out, transcript.Digest(), Span(secret, secret_len), is_hrr ? "hrr ech accept confirmation" : "ech accept confirmation",
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc index 3452ea3..eade4bd 100644 --- a/ssl/tls13_server.cc +++ b/ssl/tls13_server.cc
@@ -757,7 +757,7 @@ // Now that the message is encoded, fill in the whole value. size_t offset = hrr.size() - ECH_CONFIRMATION_SIGNAL_LEN; if (!ssl_ech_accept_confirmation( - hs, Span(hrr).last(ECH_CONFIRMATION_SIGNAL_LEN), + hs, Span(hrr).last<ECH_CONFIRMATION_SIGNAL_LEN>(), ssl->s3->client_random, hs->transcript, /*is_hrr=*/true, hrr, offset)) { return ssl_hs_error; @@ -947,7 +947,7 @@ if (hs->ech_is_inner) { // Fill in the ECH confirmation signal. const size_t offset = ssl_ech_confirmation_signal_hello_offset(ssl); - Span<uint8_t> random_suffix = random.last(ECH_CONFIRMATION_SIGNAL_LEN); + auto random_suffix = random.last<ECH_CONFIRMATION_SIGNAL_LEN>(); if (!ssl_ech_accept_confirmation(hs, random_suffix, ssl->s3->client_random, hs->transcript, /*is_hrr=*/false, server_hello, offset)) { @@ -955,8 +955,8 @@ } // Update |server_hello|. - Span<uint8_t> server_hello_out = - Span(server_hello).subspan(offset, ECH_CONFIRMATION_SIGNAL_LEN); + auto server_hello_out = + Span(server_hello).subspan(offset).first<ECH_CONFIRMATION_SIGNAL_LEN>(); OPENSSL_memcpy(server_hello_out.data(), random_suffix.data(), ECH_CONFIRMATION_SIGNAL_LEN); }
diff --git a/ssl/tls_record.cc b/ssl/tls_record.cc index 328a2da..ba0c4c1 100644 --- a/ssl/tls_record.cc +++ b/ssl/tls_record.cc
@@ -143,7 +143,7 @@ return ssl_open_record_partial; } - Span<const uint8_t> header = in.subspan(0, SSL3_RT_HEADER_LENGTH); + auto header = in.first(SSL3_RT_HEADER_LENGTH); ssl_do_msg_callback(ssl, 0 /* read */, SSL3_RT_HEADER, header); *out_consumed = in.size() - CBS_len(&cbs);
diff --git a/util/fipstools/acvp/modulewrapper/modulewrapper.cc b/util/fipstools/acvp/modulewrapper/modulewrapper.cc index f4bb4d7..762f3e9 100644 --- a/util/fipstools/acvp/modulewrapper/modulewrapper.cc +++ b/util/fipstools/acvp/modulewrapper/modulewrapper.cc
@@ -880,7 +880,7 @@ static bool Hash(const Span<const uint8_t> args[], ReplyCallback write_reply) { uint8_t digest[DigestLength]; OneShotHash(args[0].data(), args[0].size(), digest); - return write_reply({Span<const uint8_t>(digest)}); + return write_reply({MakeConstSpan(digest)}); } template <uint8_t *(*OneShotHash)(const uint8_t *, size_t, uint8_t *),