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 *),