diff options
author | Pete Bentley <prb@google.com> | 2021-07-23 17:57:12 +0100 |
---|---|---|
committer | Pete Bentley <prb@google.com> | 2021-07-23 17:57:20 +0100 |
commit | 00a7c4040a2a6f6242d962a19cb9963f7f420818 (patch) | |
tree | 92137424b51b87f2224120b0f7c9875384fb0f91 /src/ssl/internal.h | |
parent | 62b47fae9dba725737229b6d3421558d771f0bdd (diff) | |
download | boringssl-00a7c4040a2a6f6242d962a19cb9963f7f420818.tar.gz |
external/boringssl: Sync to 7a817f48bafee508b2d23ad278f892ee1cb32b91.
Re-lands https://r.android.com/1774909
This includes the following changes:
https://boringssl.googlesource.com/boringssl/+log/ae2bb641735447496bed334c495e4868b981fe32..7a817f48bafee508b2d23ad278f892ee1cb32b91
* Add 'generate-ech' command to bssl tool
* Don't enable atomics in NO_THREADS configurations.
* Check strtoul return for overflow error in GetUnsigned()
* Add convenience functions to malloc EVP_HPKE_CTX and EVP_HPKE_KEY.
* Document that SSL_PRIVATE_KEY_METHOD should configure signing prefs.
* Always have CRYPTO_sysrand_for_seed.
* hrss: use less stack space.
* Make X509_EXTENSION opaque.
Update-Note: Use X509_EXTENSION_get_* instead.
* Make X509_CRL opaque.
Update-Note: Use accessors instead.
* Switch another malloc to bssl::Array.
* Add a pointer alignment helper function.
* Remove unused field in X509_NAME_ENTRY.
Update-Note: Removed unused field in struct.
* Fix sign bit in BN_div if numerator and quotient alias.
* Handle the server case in SSL_get0_ech_name_override.
* Remove -2 return value from X509*_get_*_by_NID.
Update-Note: The return value convention of some functions was
simplified. This is not expected to affect any callers.
* Remove X509at_get0_data_by_OBJ.
Update-Note: X509at_get0_data_by_OBJ is removed. We found no callers of
this function.
* Document a batch of extension-related functions in x509.h.
* conf: fix getting keys from the default section.
* conf: don't crash when parsing.
* Add some OpenSSL compatibility aliases.
* Make ASN1_OBJECT opaque.
Update-Note: ASN1_OBJECT is now opaque. Callers should use accessors.
* Rename asn1_locl.h to internal.h.
* Update hpke_test.go.
* Decorate x509v3_a2i_ipadd declaration as its definition.
* SHA-256 is used on AArch64, even if NO_ASM.
* swtb is another AArch64 magic tweak.
* Implement ClientHelloOuter handshakes.
* runner: Add a convenience function for base64 flags.
* Reduce bouncing on the cache lock in ssl_update_cache.
Update-Note: This reshuffles some locks around the session cache.
(Hopefully for the better.)
* Only clear not_resumable after the handshake.
* runner: Test that clients actually use renewed tickets.
* runner: Clean up test logic.
* runner: Fix process exit timeout.
* Remove old ASN.1 SET macros.
* Document some ASN1_INTEGER and ASN1_ENUMERATED functions.
* Document ASN1_STRING_to_UTF8.
* Const-correct ASN1_item_verify a bit more.
* Compute ASN.1 BIT STRING sizes more consistently.
* Remove lh_FOO_doall.
* Prefix internal LHASH functions.
* Unexport almost all of LHASH.
Update-Note: BoringSSL no longer provides a general-purpose hash table
to callers. Use the language's standard library, or another
implementation.
* Rename t1_lib.cc to extensions.cc.
* Prefix and unexport a2i_ipadd.
* Fix a -Wdeprecated-copy warning.
* Validate ECH public names.
* Fold X509_VERIFY_PARAM_ID into X509_VERIFY_PARAM.
* Make X509_VERIFY_PARAM opaque.
Update-Note: Use setters instead of configuring X509_VERIFY_PARAM
directly.
* Move crypto/x509/vpm_int.h into internal.h.
* Reformat x509_vfy.h and convert comments.
* Reland "Add util/fetch_ech_config_list.go"
* Revert "Add util/fetch_ech_config_list.go"
* Add util/fetch_ech_config_list.go
* More reliably report handshake errors through SSL_write.
* Add an option to permute ClientHello extension order.
* runner: Check the test name against the protocol being tested.
* Remove outdated comment in primality testing.
* Add most of an ECH client implementation.
* Add a basic API to make ECHConfigs.
* Make ECH server APIs take EVP_HPKE_KEY.
* Rename SSL_ECH_SERVER_CONFIG_LIST to SSL_ECH_KEYS.
* runner: Self-check tests more accurately and earlier.
* Don't pad the second ClientHello.
* Fix ext_pre_shared_key_clienthello_length calculation.
* Tidy up the PSK binder logic.
* Move the TLS vs DTLS header length adjustment into ssl_add_clienthello_tlsext.
* Shift some complexity out of ssl_add_clienthello_tlsext.
* Add a note about extension callback names.
* Add move support to EVP_MD_CTX.
* Replace hs->needs_psk_binder with an output parameter.
* Make add_clienthello callbacks const.
* Fix documentation typo.
* Compute the ECH GREASE payload outside of the callbacks.
* Pick up the GREASE ECH config ID from grease_seed.
* Initialize grease_seed on construction.
* Remove the extension init hook.
* Move key_share computation out of ClientHello callbacks.
* Release some temporaries outside of ClientHello callbacks.
* Move the early_data_{offered,reason} logic out of extension callbacks.
* Implement a handshake hint for certificate compression.
* runner: Implement ECH server for testing.
* runner: Parse the status_request extension more strictly.
* runner: Make echIsInner a boolean.
* runner: Revise ECHConfig type in preparation for client implementation
* Fix ECH-Server-RepeatedConfigID test.
* Add SSL_ech_accepted API and ech_is_required alerts.
* Reject the ECH extension in TLS 1.2 ServerHello.
* Move ECH-related APIs to encrypted_client_hello.cc.
* Const-correct message creation hooks.
* Remove the Channel ID callback.
Update-Note: SSL_CTX_set_channel_id_cb is removed.
SSL_set_tls_channel_id_enabled no longer enables Channel ID as a client,
only as a server.
* Manage Channel ID handshake state better.
Update-Note: SSL_get_tls_channel_id will no longer return all zeros
during the handshake or on the client. I did not find any callers
relying on this.
* DTLS-SRTP is only defined for DTLS.
* Remove impossible ssl->s3 null check.
* fix #415: Perl scripts fail when building from a path with spaces
* Cite an RFC over 9000 (draft-ietf-quic-tls is now RFC 9001).
Update-Note: QUIC APIs now default to the standard code point rather
than the draft one. QUICHE has already been calling
SSL_set_quic_use_legacy_codepoint, so this should not affect them. Once
callers implementing the draft versions cycle out, we can then drop
SSL_set_quic_use_legacy_codepoint altogether. I've also bumped
BORINGSSL_API_VERSION in case we end up needing an ifdef.
* Add compatibility impl for EVP_PKEY_get0
* Make md32_common.h single-included and use an unsized helper for SHA-256.
* Pull HASH_TRANSFORM out of md32_common.h.
* Ensure name not null in EVP_get_cipherbyname
* Fix array-parameter warnings
* Don't copy client's session ID into server's session.
* Test ECH server with unique and repeated config IDs.
* Refresh SSL corpora after adding ECH fuzzer mode.
* Implement fuzzer mode for ECH server.
* Don't try to write empty early data in the tool.
* GREASE is now RFC 8701.
* runner: Reject all zero client and server randoms.
* Const-correct SSL_get_srtp_profiles.
Update-Note: The change to the return type isn't quite compatible, but I
only found one caller of this function, which has since been fixed. (If
we need to return a non-const value for compatibility, we can do that
and document that the caller should not mutate the output.)
* Update the ECH GREASE size selection.
* fuzz/minimise_corpora.sh: Add shebang and chmod +x
* Add a missing case to SSL_error_description.
* Remove draft tokbind implementation.
Update-Note: Token binding APIs are removed.
* Make X509_REQ and X509_REQ_INFO opaque.
Update-Note: Callers that reach into X509_REQ and X509_REQ_INFO must use
accessors instead.
* Check hs->early_session, not ssl->session, for the early data limit.
* Fix some includes.
* Be clearer which signing inputs are digests.
* Validate RSA public keys more consistently.
Update-Note: See above.
* Add APIs to manually fill in signatures for CRLs.
* Check for resumption identifiers in SSL_SESSION_is_resumable.
* Don't use SHA256(ticket) as the signaling session ID for tickets.
* Simplify renego + resumption handling.
* Move session ID assignment out of ssl_get_new_session.
* Fix the ech_accept comment.
* Export the HPKE implementation.
* Refer to EVP_HPKE_CTX by a consistent name.
* Shift the KEM dependency in HPKE up a step.
* Update ACVP URLs.
* Add SSL_can_release_private_key.
* Make X509_SIG and X509_CERT_AUX opaque.
Update-Note: Direct access of these structs should be replaced by
accessors.
* acvp: move hash iterations into modulewrapper.
* Switch HPKE to a three-parameter output buffer.
* Introduce EVP_HPKE_{AEAD,KDF} types.
* Don't mark up the first word in a collective comment.
* Revise the deterministic for_test variant of HPKE's SetupBaseS.
* Fix a memory leak with d2i_ASN1_OBJECT object reuse.
* Remove HPKE PSK mode.
* Remove HKDF-SHA384 and HKDF-SHA512 from HPKE.
* Correctly order PKCS#7 certificates and CRLs.
Update-Note: It is no longer the case that constructing a PKCS#7 file
and parsing them back out will keep the certificates and CRLs in the
same order.
* Implement ECH draft 10 and update HPKE to draft 08.
* Document expected use of BTI and PAC macros.
* Remove non-deterministic bits from ECDSA ACVP test.
* Reference the newer ChaCha20-Poly1305 RFC.
* Use passive entropy collection everywhere.
* Rename X509V*_VERSION constants.
Update-Note: This renames some BoringSSL-specific constants that we
recently added. It doesn't look like anyone's used them yet.
* Const-correct ASN1_OBJECT_create.
* Clarify OBJ_get0_data and OBJ_get_length.
* avcp: SHA-1 for ECDSA _verification_ is still supported by NIST.
* A couple of Aarch64 FIPS delocate fixes.
* Use a placeholder for unknown errors in ERR_*_error_string.
* Include assembly optimizations in Bazel builds on Linux-aarch64.
* Remove some BoringSSL-only X509_CINF functions.
Update-Note: X509_get_cert_info, X509_CINF_set_modified, and
X509_CINF_get_signature are removed. I believe all callers have been
updated. Callers should use i2d_re_X509_tbs, i2d_X509_tbs, and
X509_get0_tbs_sigalg instead.
* Document and test X509_ATTRIBUTE creation functions.
* Revert handshaker fd numbers and make StartProcess more flexible.
* Remove support for malformed X509_ATTRIBUTEs.
Update-Note: Given OpenSSL hasn't accepted these for five years, it's
unlikely anything depends on it. If something breaks, we can revert this
and revisit. No one calls X509_ATTRIBUTE_set1_data on a non-empty
X509_ATTRIBUTE, so the behavior change there should be safe.
* Make X509_ATTRIBUTE opaque.
Update-Note: Direct accesses of X509_ATTRIBUTE should be replaced with
one of the accessors. I couldn't find any direct accesses, so hopefully
this is fine.
* acvptool: Fix typo hard-coding the HTTP method.
* Document a few more x509.h functions.
* Make X509_PUBKEY opaque.
Update-Note: Direct accesses of X509_PUBKEY should be replaced with one
of the accessors. I believe all callers have been fixed at this point.
* Always encode booleans as DER.
Update-Note: Callers setting ASN1_BOOLEANs to a positive value other
than 0xff will now encode 0xff. This probably fixes a bug, but if anyone
was attaching significance to incorrectly-encoded booleans, that will
break.
* Fix issuerUID and subjectUID parsing in the key usage checker.
* Add experimental handshake hints API.
* Make our Python scripts Python-3-compatible.
* Export ssl_client_hello_init for fuzzers.
* acvp: support GMAC as an algorithm.
* Record a fuzzing corpus for the ClientHelloInner decoder.
* Use a consistent plural for 'corpus'.
* Add util/bot/libFuzzer to .gitignore.
* acvp: support KAS-ECC-SSC staticUnified mode.
* Check for invalid ALPN inputs in SSL_(CTX_)set_alpn_protos.
Update-Note: SSL_CTX_set_alpn_protos and SSL_set_alpn_protos will now
reject invalud inputs. Previously, they would accept them, but silently
send an invalid ALPN extension which the server would almost certainly
error on.
* Don't duplicate ServerHello construction code.
* Rearrange key share and early data logic.
* Only skip early data with HRR when offered.
* Add ECH server config API to ssl_ctx_api fuzzer
* Fix ppc64le build.
* Simplify the Lucky13 mitigation.
* Add ECH server (draft-ietf-tls-esni-09).
* runner: Remove unused field
* runner: Construct finishedHash earlier.
* Simplify tls_cbc.c slightly.
* Remove remnants of CBC SHA2 cipher suites.
* runner: Test different V2ClientHello challenge lengths.
* runner: Ensure helloBytes is always the same as hello.marshal().
* runner: Fix ECH confirmation calculation with PSKs in tests.
* runner: Fix HPKE parameter order.
* runner: UpdateForHelloRetryRequest cannot fail.
* runner: Don't use the buffer in TLS 1.3.
* runner: Don't maintain two copies of the same transcript hash.
* runner: Remove remnants of SSL 3.0.
* runner: Fix writeClientHash and writeRecord ordering.
* runner: Remove CheckTLS13DowngradeRandom.
* runner: Remove remnants of the separate HelloRetryRequest message.
* runner: Store a cipherSuite in ClientSessionState.
* runner: Move writeHash to the finishedHash struct.
* Fix the spelling of HPKE AEAD constants.
* Don't reset server callback expectations on new handshake.
* Fix MockQuicTransport::Flush error handling.
* Fold ripemd/internal.h into ripemd.c.
* Move load/store helpers to crypto/internal.h.
* Make words in crypto/fipsmodule/modes actually words.
* Handle EINTR more in handshaker.cc.
* Add a few missing SSL_R_BIO_NOT_SET cases.
* Fix some unreachable code in the QUIC handshaker driver.
* Rearrange SSLKeyShare::Serialize.
* Fix ssl/internal.h sectioning.
* Remove some now unnecessary test exclusions from split handshakes.
* Remove tls13-split-handshakes flag.
* Define HANDSHAKER_SUPPORTED in once place.
* Tidy up handshaker tester.
* modulewrapper: add option to print build information.
* FIPS counters for AES-CTR.
* Enforce that pre_shared_key must come with psk_key_exchange_modes.
* Zero out FIPS counters.
* Remove is_resume field on TestState.
* Remove OPENSSL_DANGEROUS_RELEASE_PTHREAD_KEY build flag.
* Add some warnings on how to use OPENSSL_memory_* functions.
* Use an unsized helper for truncated SHA-512 variants.
Update-Note: There is a small chance the asserts will trip something,
but hopefully not since I've left SHA512_Final alone.
* Fix mismatch between header and implementation of bn_sqr_comba8.
* Remove GCC 4.8.99 check.
* Bump minimum CMake version.
* Automatically enable C11 atomics when available.
Update-Note: If something fails to compile, we'll revert this and adjust
the check, or add an opt-out, or give up. Also, if building with
-std=c99, consider -std=c11.
* Make generate_build_files.py python3 compatible.
* Remove X509_REQ_set_extension_nids and document related functions.
Update-Note: This removes a pair of unused functions.
* Document a few more functions in x509.h.
* Do not access value.ptr with V_ASN1_BOOLEAN.
* Add X509_PUBKEY_get0_public_key.
* Test empty EVP_CIPHER inputs and fix exact memcpy overlap.
* Revert "Implement rsa_pkcs1_sha256_legacy."
* Fix unnecessarily direction-specific tests in cipher_tests.txt
* Refactor HPKE API to include explicit length parameters.
* Generalize make_errors.go to allow EVP covering multiple directories.
* Add a Windows no-op impl of BORINGSSL_self_test
* Only pass -handshaker-path in split handshakes tests.
* Add RNG support for FreeBSD.
* Move fips.c into a subdirectory.
* Implement rsa_pkcs1_sha256_legacy.
* Better document nullable X.509 getters.
* runner: Remove redundant -enable-all-curves shim flag.
* Initialize nonce in PerAEADTest.ABI.
* Document ASN1_TYPE and related functions.
* fips: add counters.
* Align with OpenSSL on constness of static ASN1_OBJECTs.
Update-Note: The change to OBJ_nid2obj should be compatible. The changes
to X509_PUBKEY_set0_param and X509_ALGOR_set0 may require fixing some
pointer types.
* Add -rr-record flag to runner.go.
* Register NAME_CONSTRAINTS with bssl::UniquePtr.
* Register POLICY_MAPPING with bssl::UniquePtr.
* Stub out some more of PKCS7.
* Remove TODO to reverse the output of PKCS12_parse.
* Make the X509_VAL structure opaque.
Update-Note: I believe this is now safe to do. If there are compile
failures, switch to X509_get0_notBefore, X509_getm_notBefore, and
X509_set1_notBefore, or revert this if I'm wrong and too many callers
still need updating.
* Support creating unencrypted PKCS#12 files.
* Move PKCS#12 samples to embed_test_data.
* Remove some remnants of TLS 1.3 downgrade carveouts.
Update-Note:
https://boringssl-review.googlesource.com/c/boringssl/+/44124 made these
functions a no-op, but we kept them around because there were still some
call sites floating around. That code has since been updated, so we can
remove this.
* Remove X509_REQ_to_X509.
Update-Note: This removes a function that appears to be unused. It also
hardcodes the use of MD5, so please do not use it.
* Fix OPENSSL_EC_* constants and add EC_GROUP_get_asn1_flag
* RAND_set_rand_method returns int.
* Check the inner and outer CRL signature algorithms match.
Update-Note: Invalid CRLs with inconsistent inner and outer signature
algorithms will now be rejected.
* Remove block_mask from EVP_CIPHER_CTX.
Update-Note: It doesn't look like anyone is reading into this field. If
they are, we can ideally fix it, or revert this if absolutely necessary.
* Document a couple more functions in x509.h.
* Define X509V*_VERSION constants.
* Handle the default X.509 version explicitly.
* Compile for RISC-V.
* Add ECDSA nonce-testing functions.
* Rearrange ECDSA implementation.
* Split the FIPS mode PRNG lock in two.
* Remove legacy vs_toolchain.py environment variable.
* runner: Rename 'masterSecret' on session objects to plain 'secret'.
* Test ECDSA signing is non-deterministic.
* acvp: split ACVP modulewrapper for reuse by Trusty
* No-op CL to trigger some builds.
* Use CIPD Go packages.
* Update CMake on the bots and switch to CIPD where available.
* Future-proof vs_toolchain.py for VS2019.
* Revert "Revert "Disable check that X.509 extensions implies v3.""
* Update Clang and Go on the bots.
* Check for OBJ_nid2obj failures in X509_ATTRIBUTE_create.
* Don't overflow the output length in EVP_CipherUpdate calls.
Update-Note: Passing extremely large input lengths into EVP_CipherUpdate
will now fail. Use EVP_AEAD instead, which is size_t-based and has more
explicit output bounds.
* Remove X509_issuer_and_serial_hash.
Update-Note: No one uses this function. It had a NULL dereference in
some error cases. See CVE-2021-23841.
* Fix Bazel build breakage.
* Specify VS toolchain by command-line argument.
* Update Android Bazel build support in BUILD.toplevel.
* Honor SSL_TLSEXT_ERR_ALERT_FATAL in the ALPN callback.
Update-Note: Callers that return SSL_TLSEXT_ERR_ALERT_FATAL from the
ALPN callback will change behavior. The old behavior may be restored by
returning SSL_TLSEXT_ERR_NOACK, though see the documentation for new
recommendations on return values.
* acvp: detect header element in JSON.
* Align the ARM capability functions.
* Skip runtime NEON checks if __ARM_NEON is defined.
Update-Note: Builds with __ARM_NEON (-mfpu=neon) will now drop about
30KiB of dead code, but no longer work (if they even did before) on a
particular buggy CPU. Builds without __ARM_NEON are not affected.
* acvp: don't include CMAC-AES in regcap dump.
* acvp: fix CMAC verify
* Include bn/internal.h for non-bcm.c builds.
* Add various function calls to test_fips.
* Add missing include to self_check.c.
* Revert "Disable check that X.509 extensions implies v3."
* Fix TLS13SessionID-TLS13 test.
Test: atest CtsLibcoreTestCases CtsLibcoreOkHttpTestCases
Change-Id: Idb0a37fccba5d1c3f6a40fe91a81c5189170ed23
Diffstat (limited to 'src/ssl/internal.h')
-rw-r--r-- | src/ssl/internal.h | 572 |
1 files changed, 435 insertions, 137 deletions
diff --git a/src/ssl/internal.h b/src/ssl/internal.h index b3b75405..3b7326ae 100644 --- a/src/ssl/internal.h +++ b/src/ssl/internal.h @@ -152,7 +152,9 @@ #include <utility> #include <openssl/aead.h> +#include <openssl/curve25519.h> #include <openssl/err.h> +#include <openssl/hpke.h> #include <openssl/lhash.h> #include <openssl/mem.h> #include <openssl/span.h> @@ -161,6 +163,7 @@ #include "../crypto/err/internal.h" #include "../crypto/internal.h" +#include "../crypto/lhash/internal.h" #if defined(OPENSSL_WINDOWS) @@ -276,9 +279,9 @@ class Array { T &operator[](size_t i) { return data_[i]; } T *begin() { return data_; } - const T *cbegin() const { return data_; } + const T *begin() const { return data_; } T *end() { return data_ + size_; } - const T *cend() const { return data_ + size_; } + const T *end() const { return data_ + size_; } void Reset() { Reset(nullptr, 0); } @@ -378,6 +381,8 @@ class GrowableArray { return *this; } + const T *data() const { return array_.data(); } + T *data() { return array_.data(); } size_t size() const { return size_; } bool empty() const { return size_ == 0; } @@ -385,9 +390,9 @@ class GrowableArray { T &operator[](size_t i) { return array_[i]; } T *begin() { return array_.data(); } - const T *cbegin() const { return array_.data(); } + const T *begin() const { return array_.data(); } T *end() { return array_.data() + size_; } - const T *cend() const { return array_.data() + size_; } + const T *end() const { return array_.data() + size_; } void clear() { size_ = 0; @@ -484,15 +489,17 @@ bool ssl_get_version_range(const SSL_HANDSHAKE *hs, uint16_t *out_min_version, uint16_t *out_max_version); // ssl_supports_version returns whether |hs| supports |version|. -bool ssl_supports_version(SSL_HANDSHAKE *hs, uint16_t version); +bool ssl_supports_version(const SSL_HANDSHAKE *hs, uint16_t version); // ssl_method_supports_version returns whether |method| supports |version|. bool ssl_method_supports_version(const SSL_PROTOCOL_METHOD *method, uint16_t version); // ssl_add_supported_versions writes the supported versions of |hs| to |cbb|, in -// decreasing preference order. -bool ssl_add_supported_versions(SSL_HANDSHAKE *hs, CBB *cbb); +// decreasing preference order. The version list is filtered to those whose +// protocol version is at least |extra_min_version|. +bool ssl_add_supported_versions(const SSL_HANDSHAKE *hs, CBB *cbb, + uint16_t extra_min_version); // ssl_negotiate_version negotiates a common version based on |hs|'s preferences // and the peer preference list in |peer_versions|. On success, it returns true @@ -675,6 +682,9 @@ class SSLTranscript { SSLTranscript(); ~SSLTranscript(); + SSLTranscript(SSLTranscript &&other) = default; + SSLTranscript &operator=(SSLTranscript &&other) = default; + // Init initializes the handshake transcript. If called on an existing // transcript, it resets the transcript and hash. It returns true on success // and false on failure. @@ -696,9 +706,9 @@ class SSLTranscript { // the transcript. It returns true on success and false on failure. If the // handshake buffer is still present, |digest| may be any supported digest. // Otherwise, |digest| must match the transcript hash. - bool CopyToHashContext(EVP_MD_CTX *ctx, const EVP_MD *digest); + bool CopyToHashContext(EVP_MD_CTX *ctx, const EVP_MD *digest) const; - Span<const uint8_t> buffer() { + Span<const uint8_t> buffer() const { return MakeConstSpan(reinterpret_cast<const uint8_t *>(buffer_->data), buffer_->length); } @@ -721,14 +731,14 @@ class SSLTranscript { // GetHash writes the handshake hash to |out| which must have room for at // least |DigestLen| bytes. On success, it returns true and sets |*out_len| to // the number of bytes written. Otherwise, it returns false. - bool GetHash(uint8_t *out, size_t *out_len); + bool GetHash(uint8_t *out, size_t *out_len) const; // GetFinishedMAC 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 true on success and false // on failure. bool GetFinishedMAC(uint8_t *out, size_t *out_len, const SSL_SESSION *session, - bool from_server); + bool from_server) const; private: // buffer_, if non-null, contains the handshake transcript. @@ -1066,6 +1076,10 @@ class SSLKeyShare { // |Serialize|. static UniquePtr<SSLKeyShare> Create(CBS *in); + // Serializes writes the group ID and private key, in a format that can be + // read by |Create|. + bool Serialize(CBB *out); + // GroupID returns the group ID. virtual uint16_t GroupID() const PURE_VIRTUAL; @@ -1090,13 +1104,13 @@ class SSLKeyShare { virtual bool Finish(Array<uint8_t> *out_secret, uint8_t *out_alert, Span<const uint8_t> peer_key) PURE_VIRTUAL; - // Serialize writes the state of the key exchange to |out|, returning true if - // successful and false otherwise. - virtual bool Serialize(CBB *out) { return false; } + // SerializePrivateKey writes the private key to |out|, returning true if + // successful and false otherwise. It should be called after |Offer|. + virtual bool SerializePrivateKey(CBB *out) { return false; } - // Deserialize initializes the state of the key exchange from |in|, returning - // true if successful and false otherwise. It is called by |Create|. - virtual bool Deserialize(CBS *in) { return false; } + // DeserializePrivateKey initializes the state of the key exchange from |in|, + // returning true if successful and false otherwise. + virtual bool DeserializePrivateKey(CBS *in) { return false; } }; struct NamedGroup { @@ -1352,9 +1366,10 @@ bool ssl_on_certificate_selected(SSL_HANDSHAKE *hs); bool tls13_init_key_schedule(SSL_HANDSHAKE *hs, Span<const uint8_t> psk); // tls13_init_early_key_schedule initializes the handshake hash and key -// derivation state from the resumption secret and incorporates the PSK to -// derive the early secrets. It returns one on success and zero on error. -bool tls13_init_early_key_schedule(SSL_HANDSHAKE *hs, Span<const uint8_t> psk); +// derivation state from |session| for use with 0-RTT. It returns one on success +// and zero on error. +bool tls13_init_early_key_schedule(SSL_HANDSHAKE *hs, + const SSL_SESSION *session); // tls13_advance_key_schedule incorporates |in| into the key schedule with // HKDF-Extract. It returns true on success and false on error. @@ -1407,25 +1422,184 @@ bool tls13_finished_mac(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len, // on failure. bool tls13_derive_session_psk(SSL_SESSION *session, Span<const uint8_t> nonce); -// tls13_write_psk_binder calculates the PSK binder value and replaces the last -// bytes of |msg| with the resulting value. It returns true on success, and -// false on failure. -bool tls13_write_psk_binder(SSL_HANDSHAKE *hs, Span<uint8_t> msg); +// tls13_write_psk_binder calculates the PSK binder value over |transcript| and +// |msg|, and replaces the last bytes of |msg| with the resulting value. It +// returns true on success, and false on failure. If |out_binder_len| is +// non-NULL, it sets |*out_binder_len| to the length of the value computed. +bool tls13_write_psk_binder(const SSL_HANDSHAKE *hs, + const SSLTranscript &transcript, Span<uint8_t> msg, + size_t *out_binder_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 true on success, and false on failure. -bool tls13_verify_psk_binder(SSL_HANDSHAKE *hs, SSL_SESSION *session, - const SSLMessage &msg, CBS *binders); +bool tls13_verify_psk_binder(const SSL_HANDSHAKE *hs, + const SSL_SESSION *session, const SSLMessage &msg, + CBS *binders); + + +// Encrypted ClientHello. + +struct ECHConfig { + static constexpr bool kAllowUniquePtr = true; + // raw contains the serialized ECHConfig. + Array<uint8_t> raw; + // The following fields alias into |raw|. + Span<const uint8_t> public_key; + Span<const uint8_t> public_name; + Span<const uint8_t> cipher_suites; + uint16_t kem_id = 0; + uint16_t maximum_name_length = 0; + uint8_t config_id = 0; +}; + +class ECHServerConfig { + public: + static constexpr bool kAllowUniquePtr = true; + ECHServerConfig() = default; + ECHServerConfig(const ECHServerConfig &other) = delete; + ECHServerConfig &operator=(ECHServerConfig &&) = delete; + + // Init parses |ech_config| as an ECHConfig and saves a copy of |key|. + // It returns true on success and false on error. + bool Init(Span<const uint8_t> ech_config, const EVP_HPKE_KEY *key, + bool is_retry_config); + + // SetupContext sets up |ctx| for a new connection, given the specified + // HPKE ciphersuite and encapsulated KEM key. It returns true on success and + // false on error. This function may only be called on an initialized object. + bool SetupContext(EVP_HPKE_CTX *ctx, uint16_t kdf_id, uint16_t aead_id, + Span<const uint8_t> enc) const; + + const ECHConfig &ech_config() const { return ech_config_; } + bool is_retry_config() const { return is_retry_config_; } + + private: + ECHConfig ech_config_; + ScopedEVP_HPKE_KEY key_; + bool is_retry_config_ = false; +}; + +enum ssl_client_hello_type_t { + ssl_client_hello_unencrypted, + ssl_client_hello_inner, + ssl_client_hello_outer, +}; + +// ssl_decode_client_hello_inner recovers the full ClientHelloInner from the +// EncodedClientHelloInner |encoded_client_hello_inner| by replacing its +// outer_extensions extension with the referenced extensions from the +// ClientHelloOuter |client_hello_outer|. If successful, it writes the recovered +// ClientHelloInner to |out_client_hello_inner|. It returns true on success and +// false on failure. +OPENSSL_EXPORT bool ssl_decode_client_hello_inner( + SSL *ssl, uint8_t *out_alert, Array<uint8_t> *out_client_hello_inner, + Span<const uint8_t> encoded_client_hello_inner, + const SSL_CLIENT_HELLO *client_hello_outer); + +// ssl_client_hello_decrypt attempts to decrypt the given |payload| into +// |out_encoded_client_hello_inner|. The decrypted value should be an +// EncodedClientHelloInner. It returns false if any fatal errors occur and true +// otherwise, regardless of whether the decrypt was successful. It sets +// |out_encoded_client_hello_inner| to true if the decryption fails, and false +// otherwise. +bool ssl_client_hello_decrypt(EVP_HPKE_CTX *hpke_ctx, + Array<uint8_t> *out_encoded_client_hello_inner, + bool *out_is_decrypt_error, + const SSL_CLIENT_HELLO *client_hello_outer, + uint16_t kdf_id, uint16_t aead_id, + uint8_t config_id, Span<const uint8_t> enc, + Span<const uint8_t> payload); + +#define ECH_CONFIRMATION_SIGNAL_LEN 8 + +// ssl_ech_confirmation_signal_hello_offset returns the offset of the ECH +// confirmation signal in a ServerHello message, including the handshake header. +size_t ssl_ech_confirmation_signal_hello_offset(const SSL *ssl); + +// ssl_ech_accept_confirmation computes the server's ECH acceptance signal, +// writing it to |out|. The signal is computed by concatenating |transcript| +// with |server_hello|. This function handles the fact that eight bytes of +// |server_hello| need to be replaced with zeros before hashing. It returns true +// on success, and false on failure. +bool ssl_ech_accept_confirmation(const SSL_HANDSHAKE *hs, Span<uint8_t> out, + const SSLTranscript &transcript, + Span<const uint8_t> server_hello); + +// 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. +OPENSSL_EXPORT bool ssl_is_valid_ech_public_name( + Span<const uint8_t> public_name); + +// ssl_is_valid_ech_config_list returns true if |ech_config_list| is a valid +// ECHConfigList structure and false otherwise. +bool ssl_is_valid_ech_config_list(Span<const uint8_t> ech_config_list); + +// ssl_select_ech_config selects an ECHConfig and associated parameters to offer +// on the client and updates |hs|. It returns true on success, whether an +// ECHConfig was found or not, and false on internal error. On success, the +// encapsulated key is written to |out_enc| and |*out_enc_len| is set to the +// number of bytes written. If the function did not select an ECHConfig, the +// encapsulated key is the empty string. +bool ssl_select_ech_config(SSL_HANDSHAKE *hs, Span<uint8_t> out_enc, + size_t *out_enc_len); + +// ssl_ech_extension_body_length returns the length of the body of a ClientHello +// ECH extension that encrypts |in_len| bytes with |aead| and an 'enc' value of +// length |enc_len|. The result does not include the four-byte extension header. +size_t ssl_ech_extension_body_length(const EVP_HPKE_AEAD *aead, size_t enc_len, + size_t in_len); + +// ssl_encrypt_client_hello constructs a new ClientHelloInner, adds it to the +// inner transcript, and encrypts for inclusion in the ClientHelloOuter. |enc| +// is the encapsulated key to include in the extension. It returns true on +// success and false on error. If not offering ECH, |enc| is ignored and the +// function will compute a GREASE ECH extension if necessary, and otherwise +// return success while doing nothing. +// +// Encrypting the ClientHelloInner incorporates all extensions in the +// ClientHelloOuter, so all other state necessary for |ssl_add_client_hello| +// must already be computed. +bool ssl_encrypt_client_hello(SSL_HANDSHAKE *hs, Span<const uint8_t> enc); + + +// Delegated credentials. + +// This structure stores a delegated credential (DC) as defined by +// draft-ietf-tls-subcerts-03. +struct DC { + static constexpr bool kAllowUniquePtr = true; + ~DC(); + + // Dup returns a copy of this DC and takes references to |raw| and |pkey|. + UniquePtr<DC> Dup(); + + // Parse parses the delegated credential stored in |in|. If successful it + // returns the parsed structure, otherwise it returns |nullptr| and sets + // |*out_alert|. + static UniquePtr<DC> Parse(CRYPTO_BUFFER *in, uint8_t *out_alert); + // raw is the delegated credential encoded as specified in draft-ietf-tls- + // subcerts-03. + UniquePtr<CRYPTO_BUFFER> raw; -// Encrypted Client Hello. + // expected_cert_verify_algorithm is the signature scheme of the DC public + // key. + uint16_t expected_cert_verify_algorithm = 0; -// tls13_ech_accept_confirmation computes the server's ECH acceptance signal, -// writing it to |out|. It returns true on success, and false on failure. -bool tls13_ech_accept_confirmation( - SSL_HANDSHAKE *hs, bssl::Span<uint8_t> out, - bssl::Span<const uint8_t> server_hello_ech_conf); + // pkey is the public key parsed from |public_key|. + UniquePtr<EVP_PKEY> pkey; + + private: + friend DC* New<DC>(); + DC(); +}; + +// ssl_signing_with_dc returns true if the peer has indicated support for +// delegated credentials and this host has sent a delegated credential in +// response. If this is true then we've committed to using the DC in the +// handshake. +bool ssl_signing_with_dc(const SSL_HANDSHAKE *hs); // Handshake functions. @@ -1440,7 +1614,6 @@ enum ssl_hs_wait_t { ssl_hs_handoff, ssl_hs_handback, ssl_hs_x509_lookup, - ssl_hs_channel_id_lookup, ssl_hs_private_key_operation, ssl_hs_pending_session, ssl_hs_pending_ticket, @@ -1449,6 +1622,7 @@ enum ssl_hs_wait_t { ssl_hs_read_end_of_early_data, ssl_hs_read_change_cipher_spec, ssl_hs_certificate_verify, + ssl_hs_hints_ready, }; enum ssl_grease_index_t { @@ -1458,12 +1632,14 @@ enum ssl_grease_index_t { ssl_grease_extension2, ssl_grease_version, ssl_grease_ticket_extension, - ssl_grease_last_index = ssl_grease_ticket_extension, + ssl_grease_ech_config_id, + ssl_grease_last_index = ssl_grease_ech_config_id, }; enum tls12_server_hs_state_t { state12_start_accept = 0, state12_read_client_hello, + state12_read_client_hello_after_ech, state12_select_certificate, state12_tls13, state12_select_parameters, @@ -1515,46 +1691,30 @@ enum handback_t { handback_max_value = handback_tls13, }; - -// Delegated credentials. - -// This structure stores a delegated credential (DC) as defined by -// draft-ietf-tls-subcerts-03. -struct DC { +// SSL_HANDSHAKE_HINTS contains handshake hints for a connection. See +// |SSL_request_handshake_hints| and related functions. +struct SSL_HANDSHAKE_HINTS { static constexpr bool kAllowUniquePtr = true; - ~DC(); - // Dup returns a copy of this DC and takes references to |raw| and |pkey|. - UniquePtr<DC> Dup(); + Array<uint8_t> server_random; - // Parse parses the delegated credential stored in |in|. If successful it - // returns the parsed structure, otherwise it returns |nullptr| and sets - // |*out_alert|. - static UniquePtr<DC> Parse(CRYPTO_BUFFER *in, uint8_t *out_alert); + uint16_t key_share_group_id = 0; + Array<uint8_t> key_share_public_key; + Array<uint8_t> key_share_secret; - // raw is the delegated credential encoded as specified in draft-ietf-tls- - // subcerts-03. - UniquePtr<CRYPTO_BUFFER> raw; + uint16_t signature_algorithm = 0; + Array<uint8_t> signature_input; + Array<uint8_t> signature_spki; + Array<uint8_t> signature; - // expected_cert_verify_algorithm is the signature scheme of the DC public - // key. - uint16_t expected_cert_verify_algorithm = 0; - - // pkey is the public key parsed from |public_key|. - UniquePtr<EVP_PKEY> pkey; + Array<uint8_t> decrypted_psk; + bool ignore_psk = false; - private: - friend DC* New<DC>(); - DC(); + uint16_t cert_compression_alg_id = 0; + Array<uint8_t> cert_compression_input; + Array<uint8_t> cert_compression_output; }; -// ssl_signing_with_dc returns true if the peer has indicated support for -// delegated credentials and this host has sent a delegated credential in -// response. If this is true then we've committed to using the DC in the -// handshake. -bool ssl_signing_with_dc(const SSL_HANDSHAKE *hs); - - struct SSL_HANDSHAKE { explicit SSL_HANDSHAKE(SSL *ssl); ~SSL_HANDSHAKE(); @@ -1599,7 +1759,21 @@ struct SSL_HANDSHAKE { public: void ResizeSecrets(size_t hash_len); + // GetClientHello, on the server, returns either the normal ClientHello + // message or the ClientHelloInner if it has been serialized to + // |ech_client_hello_buf|. This function should only be called when the + // current message is a ClientHello. It returns true on success and false on + // error. + // + // Note that fields of the returned |out_msg| and |out_client_hello| point + // into a handshake-owned buffer, so their lifetimes should not exceed this + // SSL_HANDSHAKE. + bool GetClientHello(SSLMessage *out_msg, SSL_CLIENT_HELLO *out_client_hello); + Span<uint8_t> secret() { return MakeSpan(secret_, hash_len_); } + Span<const uint8_t> secret() const { + return MakeConstSpan(secret_, hash_len_); + } Span<uint8_t> early_traffic_secret() { return MakeSpan(early_traffic_secret_, hash_len_); } @@ -1621,7 +1795,7 @@ struct SSL_HANDSHAKE { union { // sent is a bitset where the bits correspond to elements of kExtensions - // in t1_lib.c. Each bit is set if that extension was sent in a + // in extensions.cc. Each bit is set if that extension was sent in a // ClientHello. It's not used by servers. uint32_t sent = 0; // received is a bitset, like |sent|, but is used by servers to record @@ -1629,9 +1803,9 @@ struct SSL_HANDSHAKE { uint32_t received; } extensions; - // retry_group is the group ID selected by the server in HelloRetryRequest in - // TLS 1.3. - uint16_t retry_group = 0; + // inner_extensions_sent, on clients that offer ECH, is |extensions.sent| for + // the ClientHelloInner. + uint32_t inner_extensions_sent = 0; // error, if |wait| is |ssl_hs_error|, is the error the handshake failed on. UniquePtr<ERR_SAVE_STATE> error; @@ -1644,15 +1818,30 @@ struct SSL_HANDSHAKE { // transcript is the current handshake transcript. SSLTranscript transcript; + // inner_transcript, on the client, is the handshake transcript for the + // ClientHelloInner handshake. It is moved to |transcript| if the server + // accepts ECH. + SSLTranscript inner_transcript; + + // inner_client_random is the ClientHello random value used with + // ClientHelloInner. + uint8_t inner_client_random[SSL3_RANDOM_SIZE] = {0}; + // cookie is the value of the cookie received from the server, if any. Array<uint8_t> cookie; - // ech_grease contains the bytes of the GREASE ECH extension that was sent in - // the first ClientHello. - Array<uint8_t> ech_grease; + // ech_client_bytes contains the ECH extension to send in the ClientHello. + Array<uint8_t> ech_client_bytes; - // key_share_bytes is the value of the previously sent KeyShare extension by - // the client in TLS 1.3. + // ech_retry_configs, on the client, contains the retry configs from the + // server as a serialized ECHConfigList. + Array<uint8_t> ech_retry_configs; + + // ech_client_hello_buf, on the server, contains the bytes of the + // reconstructed ClientHelloInner message. + Array<uint8_t> ech_client_hello_buf; + + // key_share_bytes is the key_share extension that the client should send. Array<uint8_t> key_share_bytes; // ecdh_public_key, for servers, is the key share to be sent to the client in @@ -1676,17 +1865,21 @@ struct SSL_HANDSHAKE { // peer_key is the peer's ECDH key for a TLS 1.2 client. Array<uint8_t> peer_key; - // negotiated_token_binding_version is used by a server to store the - // on-the-wire encoding of the Token Binding protocol version to advertise in - // the ServerHello/EncryptedExtensions if the Token Binding extension is to be - // sent. - uint16_t negotiated_token_binding_version; + // extension_permutation is the permutation to apply to ClientHello + // extensions. It maps indices into the |kExtensions| table into other + // indices. + Array<uint8_t> extension_permutation; // cert_compression_alg_id, for a server, contains the negotiated certificate // compression algorithm for this client. It is only valid if // |cert_compression_negotiated| is true. uint16_t cert_compression_alg_id; + // ech_hpke_ctx is the HPKE context used in ECH. On the server, it is + // initialized if |ech_status| is |ssl_ech_accepted|. On the client, it is + // initialized if |selected_ech_config| is not nullptr. + ScopedEVP_HPKE_CTX ech_hpke_ctx; + // server_params, in a TLS 1.2 server, stores the ServerKeyExchange // parameters. It has client and server randoms prepended for signing // convenience. @@ -1723,12 +1916,29 @@ struct SSL_HANDSHAKE { // the client if |in_early_data| is true. UniquePtr<SSL_SESSION> early_session; + // ssl_ech_keys, for servers, is the set of ECH keys to use with this + // handshake. This is copied from |SSL_CTX| to ensure consistent behavior as + // |SSL_CTX| rotates keys. + UniquePtr<SSL_ECH_KEYS> ech_keys; + + // selected_ech_config, for clients, is the ECHConfig the client uses to offer + // ECH, or nullptr if ECH is not being offered. If non-NULL, |ech_hpke_ctx| + // will be initialized. + UniquePtr<ECHConfig> selected_ech_config; + // new_cipher is the cipher being negotiated in this handshake. const SSL_CIPHER *new_cipher = nullptr; // key_block is the record-layer key block for TLS 1.2 and earlier. Array<uint8_t> key_block; + // hints contains the handshake hints for this connection. If + // |hints_requested| is true, this field is non-null and contains the pending + // hints to filled as the predicted handshake progresses. Otherwise, this + // field, if non-null, contains hints configured by the caller and will + // influence the handshake on match. + UniquePtr<SSL_HANDSHAKE_HINTS> hints; + // ech_present, on the server, indicates whether the ClientHello contained an // encrypted_client_hello extension. bool ech_present : 1; @@ -1737,13 +1947,13 @@ struct SSL_HANDSHAKE { // contained an ech_is_inner extension. bool ech_is_inner_present : 1; + // ech_authenticated_reject, on the client, indicates whether an ECH rejection + // handshake has been authenticated. + bool ech_authenticated_reject : 1; + // scts_requested is true if the SCT extension is in the ClientHello. bool scts_requested : 1; - // needs_psk_binder is true if the ClientHello has a placeholder PSK binder to - // be filled in. - bool needs_psk_binder : 1; - // handshake_finalized is true once the handshake has completed, at which // point accessors should use the established state. bool handshake_finalized : 1; @@ -1805,15 +2015,17 @@ struct SSL_HANDSHAKE { // in progress. bool pending_private_key_op : 1; - // grease_seeded is true if |grease_seed| has been initialized. - bool grease_seeded : 1; - // handback indicates that a server should pause the handshake after // finishing operations that require private key material, in such a way that // |SSL_get_error| returns |SSL_ERROR_HANDBACK|. It is set by // |SSL_apply_handoff|. bool handback : 1; + // hints_requested indicates the caller has requested handshake hints. Only + // the first round-trip of the handshake will complete, after which the + // |hints| structure can be serialized. + bool hints_requested : 1; + // cert_compression_negotiated is true iff |cert_compression_alg_id| is valid. bool cert_compression_negotiated : 1; @@ -1821,6 +2033,14 @@ struct SSL_HANDSHAKE { // which implemented TLS 1.3 incorrectly. bool apply_jdk11_workaround : 1; + // can_release_private_key is true if the private key will no longer be used + // in this handshake. + bool can_release_private_key : 1; + + // channel_id_negotiated is true if Channel ID should be used in this + // handshake. + bool channel_id_negotiated : 1; + // client_version is the value sent or received in the ClientHello version. uint16_t client_version = 0; @@ -1832,12 +2052,14 @@ struct SSL_HANDSHAKE { // record layer. uint16_t early_data_written = 0; + // ech_config_id is the ECH config sent by the client. + uint8_t ech_config_id = 0; + // session_id is the session ID in the ClientHello. uint8_t session_id[SSL_MAX_SSL_SESSION_ID_LENGTH] = {0}; uint8_t session_id_len = 0; - // grease_seed is the entropy for GREASE values. It is valid if - // |grease_seeded| is true. + // grease_seed is the entropy for GREASE values. uint8_t grease_seed[ssl_grease_last_index + 1] = {0}; }; @@ -1897,14 +2119,24 @@ bool tls13_process_new_session_ticket(SSL *ssl, const SSLMessage &msg); bssl::UniquePtr<SSL_SESSION> tls13_create_session_with_ticket(SSL *ssl, CBS *body); +// ssl_setup_extension_permutation computes a ClientHello extension permutation +// for |hs|, if applicable. It returns true on success and false on error. +bool ssl_setup_extension_permutation(SSL_HANDSHAKE *hs); + +// ssl_setup_key_shares computes client key shares and saves them in |hs|. It +// returns true on success and false on failure. If |override_group_id| is zero, +// it offers the default groups, including GREASE. If it is non-zero, it offers +// a single key share of the specified group. +bool ssl_setup_key_shares(SSL_HANDSHAKE *hs, uint16_t override_group_id); + bool ssl_ext_key_share_parse_serverhello(SSL_HANDSHAKE *hs, Array<uint8_t> *out_secret, uint8_t *out_alert, CBS *contents); bool ssl_ext_key_share_parse_clienthello(SSL_HANDSHAKE *hs, bool *out_found, - Array<uint8_t> *out_secret, - uint8_t *out_alert, CBS *contents); -bool ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out, - bool dry_run); + Span<const uint8_t> *out_peer_key, + uint8_t *out_alert, + const SSL_CLIENT_HELLO *client_hello); +bool ssl_ext_key_share_add_serverhello(SSL_HANDSHAKE *hs, CBB *out); bool ssl_ext_pre_shared_key_parse_serverhello(SSL_HANDSHAKE *hs, uint8_t *out_alert, @@ -1919,7 +2151,17 @@ bool ssl_ext_pre_shared_key_add_serverhello(SSL_HANDSHAKE *hs, CBB *out); // returns whether it's valid. bool ssl_is_sct_list_valid(const CBS *contents); -bool ssl_write_client_hello(SSL_HANDSHAKE *hs); +// ssl_write_client_hello_without_extensions writes a ClientHello to |out|, +// up to the extensions field. |type| determines the type of ClientHello to +// write. If |omit_session_id| is true, the session ID is empty. +bool ssl_write_client_hello_without_extensions(const SSL_HANDSHAKE *hs, + CBB *cbb, + ssl_client_hello_type_t type, + bool empty_session_id); + +// ssl_add_client_hello constructs a ClientHello and adds it to the outgoing +// flight. It returns true on success and false on error. +bool ssl_add_client_hello(SSL_HANDSHAKE *hs); enum ssl_cert_verify_context_t { ssl_cert_verify_server, @@ -1935,6 +2177,9 @@ bool tls13_get_cert_verify_signature_input( SSL_HANDSHAKE *hs, Array<uint8_t> *out, enum ssl_cert_verify_context_t cert_verify_context); +// ssl_is_valid_alpn_list returns whether |in| is a valid ALPN protocol list. +bool ssl_is_valid_alpn_list(Span<const uint8_t> in); + // ssl_is_alpn_protocol_allowed returns whether |protocol| is a valid server // selection for |hs->ssl|'s client preferences. bool ssl_is_alpn_protocol_allowed(const SSL_HANDSHAKE *hs, @@ -1946,6 +2191,13 @@ bool ssl_is_alpn_protocol_allowed(const SSL_HANDSHAKE *hs, bool ssl_negotiate_alpn(SSL_HANDSHAKE *hs, uint8_t *out_alert, const SSL_CLIENT_HELLO *client_hello); +// ssl_get_local_application_settings looks up the configured ALPS value for +// |protocol|. If found, it sets |*out_settings| to the value and returns true. +// Otherwise, it returns false. +bool ssl_get_local_application_settings(const SSL_HANDSHAKE *hs, + Span<const uint8_t> *out_settings, + Span<const uint8_t> protocol); + // ssl_negotiate_alps negotiates the ALPS extension, if applicable. It returns // true on successful negotiation or if nothing was negotiated. It returns false // and sets |*out_alert| to an alert on error. @@ -1982,6 +2234,10 @@ bool ssl_output_cert_chain(SSL_HANDSHAKE *hs); // handshake. Note, in TLS 1.2 resumptions, this session is immutable. const SSL_SESSION *ssl_handshake_session(const SSL_HANDSHAKE *hs); +// ssl_done_writing_client_hello is called after the last ClientHello is written +// by |hs|. It releases some memory that is no longer needed. +void ssl_done_writing_client_hello(SSL_HANDSHAKE *hs); + // SSLKEYLOGFILE functions. @@ -1993,8 +2249,11 @@ bool ssl_log_secret(const SSL *ssl, const char *label, // ClientHello functions. -bool ssl_client_hello_init(const SSL *ssl, SSL_CLIENT_HELLO *out, - const SSLMessage &msg); +// ssl_client_hello_init parses |body| as a ClientHello message, excluding the +// message header, and writes the result to |*out|. It returns true on success +// and false on error. This function is exported for testing. +OPENSSL_EXPORT bool ssl_client_hello_init(const SSL *ssl, SSL_CLIENT_HELLO *out, + Span<const uint8_t> body); bool ssl_client_hello_get_extension(const SSL_CLIENT_HELLO *client_hello, CBS *out, uint16_t extension_type); @@ -2009,7 +2268,8 @@ bool ssl_client_cipher_list_contains_cipher( // connection, the values for each index will be deterministic. This allows the // same ClientHello be sent twice for a HelloRetryRequest or the same group be // advertised in both supported_groups and key_shares. -uint16_t ssl_get_grease_value(SSL_HANDSHAKE *hs, enum ssl_grease_index_t index); +uint16_t ssl_get_grease_value(const SSL_HANDSHAKE *hs, + enum ssl_grease_index_t index); // Signature algorithms. @@ -2169,10 +2429,11 @@ struct SSL_PROTOCOL_METHOD { // init_message begins a new handshake message of type |type|. |cbb| is the // root CBB to be passed into |finish_message|. |*body| is set to a child CBB // the caller should write to. It returns true on success and false on error. - bool (*init_message)(SSL *ssl, CBB *cbb, CBB *body, uint8_t type); + bool (*init_message)(const SSL *ssl, CBB *cbb, CBB *body, uint8_t type); // finish_message finishes a handshake message. It sets |*out_msg| to the // serialized message. It returns true on success and false on error. - bool (*finish_message)(SSL *ssl, CBB *cbb, bssl::Array<uint8_t> *out_msg); + bool (*finish_message)(const SSL *ssl, CBB *cbb, + bssl::Array<uint8_t> *out_msg); // add_message adds a handshake message to the pending flight. It returns // true on success and false on error. bool (*add_message)(SSL *ssl, bssl::Array<uint8_t> msg); @@ -2321,6 +2582,16 @@ enum ssl_shutdown_t { ssl_shutdown_error = 2, }; +enum ssl_ech_status_t { + // ssl_ech_none indicates ECH was not offered, or we have not gotten far + // enough in the handshake to determine the status. + ssl_ech_none, + // ssl_ech_accepted indicates the server accepted ECH. + ssl_ech_accepted, + // ssl_ech_rejected indicates the server was offered ECH but rejected it. + ssl_ech_rejected, +}; + struct SSL3_STATE { static constexpr bool kAllowUniquePtr = true; @@ -2383,9 +2654,8 @@ struct SSL3_STATE { // key_update_count is the number of consecutive KeyUpdates received. uint8_t key_update_count = 0; - // The negotiated Token Binding key parameter. Only valid if - // |token_binding_negotiated| is set. - uint8_t negotiated_token_binding_param = 0; + // ech_status indicates whether ECH was accepted by the server. + ssl_ech_status_t ech_status = ssl_ech_none; // skip_early_data instructs the record layer to skip unexpected early data // messages when 0RTT is rejected. @@ -2420,9 +2690,8 @@ struct SSL3_STATE { bool send_connection_binding : 1; - // In a client, this means that the server supported Channel ID and that a - // Channel ID was sent. In a server it means that we echoed support for - // Channel IDs and that |channel_id| will be valid after the handshake. + // channel_id_valid is true if, on the server, the client has negotiated a + // Channel ID and the |channel_id| field is filled in. bool channel_id_valid : 1; // key_update_pending is true if we have a KeyUpdate acknowledgment @@ -2435,9 +2704,6 @@ struct SSL3_STATE { // early_data_accepted is true if early data was accepted by the server. bool early_data_accepted : 1; - // token_binding_negotiated is set if Token Binding was negotiated. - bool token_binding_negotiated : 1; - // alert_dispatch is true there is an alert in |send_alert| to be sent. bool alert_dispatch : 1; @@ -2720,7 +2986,8 @@ struct SSL_CONFIG { Array<uint16_t> supported_group_list; // our list - // The client's Channel ID private key. + // channel_id_private is the client's Channel ID private key, or null if + // Channel ID should not be offered on this connection. UniquePtr<EVP_PKEY> channel_id_private; // For a client, this contains the list of supported protocols in wire @@ -2731,9 +2998,6 @@ struct SSL_CONFIG { // along with their corresponding ALPS values. GrowableArray<ALPSConfig> alps_configs; - // Contains a list of supported Token Binding key parameters. - Array<uint8_t> token_binding_params; - // Contains the QUIC transport params that this endpoint will send. Array<uint8_t> quic_transport_params; @@ -2748,6 +3012,10 @@ struct SSL_CONFIG { // DTLS-SRTP. UniquePtr<STACK_OF(SRTP_PROTECTION_PROFILE)> srtp_profiles; + // client_ech_config_list, if not empty, is a serialized ECHConfigList + // structure for the client to use when negotiating ECH. + Array<uint8_t> client_ech_config_list; + // verify_mode is a bitmask of |SSL_VERIFY_*| values. uint8_t verify_mode = SSL_VERIFY_NONE; @@ -2762,9 +3030,8 @@ struct SSL_CONFIG { // whether OCSP stapling will be requested. bool ocsp_stapling_enabled : 1; - // channel_id_enabled is copied from the |SSL_CTX|. For a server, means that - // we'll accept Channel IDs from clients. For a client, means that we'll - // advertise support. + // channel_id_enabled is copied from the |SSL_CTX|. For a server, it means + // that we'll accept Channel IDs from clients. It is ignored on the client. bool channel_id_enabled : 1; // If enforce_rsa_key_usage is true, the handshake will fail if the @@ -2794,6 +3061,9 @@ struct SSL_CONFIG { // QUIC drafts up to and including 32 used a different TLS extension // codepoint to convey QUIC's transport parameters. bool quic_use_legacy_codepoint : 1; + + // permute_extensions is whether to permute extensions when sending messages. + bool permute_extensions : 1; }; // From RFC 8446, used in determining PSK modes. @@ -2814,7 +3084,7 @@ bool ssl_is_key_type_supported(int key_type); bool ssl_compare_public_and_private_key(const EVP_PKEY *pubkey, const EVP_PKEY *privkey); bool ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey); -int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server); +bool ssl_get_new_session(SSL_HANDSHAKE *hs); int ssl_encrypt_ticket(SSL_HANDSHAKE *hs, CBB *out, const SSL_SESSION *session); int ssl_ctx_rotate_ticket_encryption_key(SSL_CTX *ctx); @@ -2895,7 +3165,7 @@ void ssl_session_rebase_time(SSL *ssl, SSL_SESSION *session); void ssl_session_renew_timeout(SSL *ssl, SSL_SESSION *session, uint32_t timeout); -void ssl_update_cache(SSL_HANDSHAKE *hs, int mode); +void ssl_update_cache(SSL *ssl); void ssl_send_alert(SSL *ssl, int level, int desc); int ssl_send_alert_impl(SSL *ssl, int level, int desc); @@ -2917,14 +3187,14 @@ int tls_write_app_data(SSL *ssl, bool *out_needs_handshake, const uint8_t *buf, bool tls_new(SSL *ssl); void tls_free(SSL *ssl); -bool tls_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type); -bool tls_finish_message(SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg); +bool tls_init_message(const SSL *ssl, CBB *cbb, CBB *body, uint8_t type); +bool tls_finish_message(const SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg); bool tls_add_message(SSL *ssl, Array<uint8_t> msg); bool tls_add_change_cipher_spec(SSL *ssl); int tls_flush_flight(SSL *ssl); -bool dtls1_init_message(SSL *ssl, CBB *cbb, CBB *body, uint8_t type); -bool dtls1_finish_message(SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg); +bool dtls1_init_message(const SSL *ssl, CBB *cbb, CBB *body, uint8_t type); +bool dtls1_finish_message(const SSL *ssl, CBB *cbb, Array<uint8_t> *out_msg); bool dtls1_add_message(SSL *ssl, Array<uint8_t> msg); bool dtls1_add_change_cipher_spec(SSL *ssl); int dtls1_flush_flight(SSL *ssl); @@ -3009,11 +3279,27 @@ bool tls1_set_curves(Array<uint16_t> *out_group_ids, Span<const int> curves); // false. bool tls1_set_curves_list(Array<uint16_t> *out_group_ids, const char *curves); -// ssl_add_clienthello_tlsext writes ClientHello extensions to |out|. It returns -// true on success and false on failure. The |header_len| argument is the length -// of the ClientHello written so far and is used to compute the padding length. -// (It does not include the record header.) -bool ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, size_t header_len); +// ssl_add_clienthello_tlsext writes ClientHello extensions to |out| for |type|. +// It returns true on success and false on failure. The |header_len| argument is +// the length of the ClientHello written so far and is used to compute the +// padding length. (It does not include the record header or handshake headers.) +// +// If |type| is |ssl_client_hello_inner|, this function also writes the +// compressed extensions to |out_encoded|. Otherwise, |out_encoded| should be +// nullptr. +// +// On success, the function sets |*out_needs_psk_binder| to whether the last +// ClientHello extension was the pre_shared_key extension and needs a PSK binder +// filled in. The caller should then update |out| and, if applicable, +// |out_encoded| with the binder after completing the whole message. +// +// If |omit_ech_len| is non-zero, the ECH extension is omitted, but padding is +// computed as if there were an extension of length |omit_ech_len|. This is used +// to compute ClientHelloOuterAAD. +bool ssl_add_clienthello_tlsext(SSL_HANDSHAKE *hs, CBB *out, CBB *out_encoded, + bool *out_needs_psk_binder, + ssl_client_hello_type_t type, size_t header_len, + size_t omit_ech_len); bool ssl_add_serverhello_tlsext(SSL_HANDSHAKE *hs, CBB *out); bool ssl_parse_clienthello_tlsext(SSL_HANDSHAKE *hs, @@ -3056,12 +3342,6 @@ bool tls1_channel_id_hash(SSL_HANDSHAKE *hs, uint8_t *out, size_t *out_len); // data. bool tls1_record_handshake_hashes_for_channel_id(SSL_HANDSHAKE *hs); -// ssl_do_channel_id_callback checks runs |hs->ssl->ctx->channel_id_cb| if -// necessary. It returns true on success and false on fatal error. Note that, on -// success, |hs->ssl->channel_id_private| may be unset, in which case the -// operation should be retried later. -bool ssl_do_channel_id_callback(SSL_HANDSHAKE *hs); - // ssl_can_write returns whether |ssl| is allowed to write. bool ssl_can_write(const SSL *ssl); @@ -3185,9 +3465,6 @@ struct ssl_ctx_st { int (*client_cert_cb)(SSL *ssl, X509 **out_x509, EVP_PKEY **out_pkey) = nullptr; - // get channel id callback - void (*channel_id_cb)(SSL *ssl, EVP_PKEY **out_pkey) = nullptr; - CRYPTO_EX_DATA ex_data; // Default values used when no per-SSL value is defined follow @@ -3315,9 +3592,15 @@ struct ssl_ctx_st { // Supported group values inherited by SSL structure bssl::Array<uint16_t> supported_group_list; - // The client's Channel ID private key. + // channel_id_private is the client's Channel ID private key, or null if + // Channel ID should not be offered on this connection. bssl::UniquePtr<EVP_PKEY> channel_id_private; + // ech_keys contains the server's list of ECHConfig values and associated + // private keys. This list may be swapped out at any time, so all access must + // be synchronized through |lock|. + bssl::UniquePtr<SSL_ECH_KEYS> ech_keys; + // keylog_callback, if not NULL, is the key logging callback. See // |SSL_CTX_set_keylog_callback|. void (*keylog_callback)(const SSL *ssl, const char *line) = nullptr; @@ -3365,9 +3648,12 @@ struct ssl_ctx_st { // advertise support. bool channel_id_enabled : 1; - // grease_enabled is whether draft-davidben-tls-grease-01 is enabled. + // grease_enabled is whether GREASE (RFC 8701) is enabled. bool grease_enabled : 1; + // permute_extensions is whether to permute extensions when sending messages. + bool permute_extensions : 1; + // allow_unknown_alpn_protos is whether the client allows unsolicited ALPN // protocols from the peer. bool allow_unknown_alpn_protos : 1; @@ -3631,5 +3917,17 @@ struct ssl_session_st { friend void SSL_SESSION_free(SSL_SESSION *); }; +struct ssl_ech_keys_st { + ssl_ech_keys_st() = default; + ssl_ech_keys_st(const ssl_ech_keys_st &) = delete; + ssl_ech_keys_st &operator=(const ssl_ech_keys_st &) = delete; + + bssl::GrowableArray<bssl::UniquePtr<bssl::ECHServerConfig>> configs; + CRYPTO_refcount_t references = 1; + + private: + ~ssl_ech_keys_st() = default; + friend void SSL_ECH_KEYS_free(SSL_ECH_KEYS *); +}; #endif // OPENSSL_HEADER_SSL_INTERNAL_H |