summaryrefslogtreecommitdiff
path: root/src/ssl/internal.h
diff options
context:
space:
mode:
authorPete Bentley <prb@google.com>2021-07-23 17:57:12 +0100
committerPete Bentley <prb@google.com>2021-07-23 17:57:20 +0100
commit00a7c4040a2a6f6242d962a19cb9963f7f420818 (patch)
tree92137424b51b87f2224120b0f7c9875384fb0f91 /src/ssl/internal.h
parent62b47fae9dba725737229b6d3421558d771f0bdd (diff)
downloadboringssl-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.h572
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