| rfc9849v4.txt | rfc9849.txt | |||
|---|---|---|---|---|
| skipping to change at line 76 ¶ | skipping to change at line 76 ¶ | |||
| 6.1.4. Determining ECH Acceptance | 6.1.4. Determining ECH Acceptance | |||
| 6.1.5. Handshaking with ClientHelloInner | 6.1.5. Handshaking with ClientHelloInner | |||
| 6.1.6. Handshaking with ClientHelloOuter | 6.1.6. Handshaking with ClientHelloOuter | |||
| 6.1.7. Authenticating for the Public Name | 6.1.7. Authenticating for the Public Name | |||
| 6.1.8. Impact of Retry on Future Connections | 6.1.8. Impact of Retry on Future Connections | |||
| 6.2. GREASE ECH | 6.2. GREASE ECH | |||
| 6.2.1. Client Greasing | 6.2.1. Client Greasing | |||
| 6.2.2. Server Greasing | 6.2.2. Server Greasing | |||
| 7. Server Behavior | 7. Server Behavior | |||
| 7.1. Client-Facing Server | 7.1. Client-Facing Server | |||
| 7.1.1. Sending HelloRetryRequest | 7.1.1. Processing ClientHello after HelloRetryRequest | |||
| 7.2. Backend Server | 7.2. Backend Server | |||
| 7.2.1. Sending HelloRetryRequest | 7.2.1. Sending HelloRetryRequest | |||
| 8. Deployment Considerations | 8. Deployment Considerations | |||
| 8.1. Compatibility Issues | 8.1. Compatibility Issues | |||
| 8.1.1. Misconfiguration and Deployment Concerns | 8.1.1. Misconfiguration and Deployment Concerns | |||
| 8.1.2. Middleboxes | 8.1.2. Middleboxes | |||
| 8.2. Deployment Impact | 8.2. Deployment Impact | |||
| 9. Compliance Requirements | 9. Compliance Requirements | |||
| 10. Security Considerations | 10. Security Considerations | |||
| 10.1. Security and Privacy Goals | 10.1. Security and Privacy Goals | |||
| skipping to change at line 433 ¶ | skipping to change at line 433 ¶ | |||
| enabler for authenticated key mismatch signals (see Section 7). In | enabler for authenticated key mismatch signals (see Section 7). In | |||
| contrast, the inner ClientHello is the true ClientHello used upon ECH | contrast, the inner ClientHello is the true ClientHello used upon ECH | |||
| negotiation. | negotiation. | |||
| 5. The "encrypted_client_hello" Extension | 5. The "encrypted_client_hello" Extension | |||
| To offer ECH, the client sends an "encrypted_client_hello" extension | To offer ECH, the client sends an "encrypted_client_hello" extension | |||
| in the ClientHelloOuter. When it does, it MUST also send the | in the ClientHelloOuter. When it does, it MUST also send the | |||
| extension in ClientHelloInner. | extension in ClientHelloInner. | |||
| ~~ enum { encrypted_client_hello(0xfe0d), (65535) } ExtensionType; ~~ | enum { | |||
| encrypted_client_hello(0xfe0d), (65535) | ||||
| } ExtensionType; | ||||
| The payload of the extension has the following structure: | The payload of the extension has the following structure: | |||
| enum { outer(0), inner(1) } ECHClientHelloType; | enum { outer(0), inner(1) } ECHClientHelloType; | |||
| struct { | struct { | |||
| ECHClientHelloType type; | ECHClientHelloType type; | |||
| select (ECHClientHello.type) { | select (ECHClientHello.type) { | |||
| case outer: | case outer: | |||
| HpkeSymmetricCipherSuite cipher_suite; | HpkeSymmetricCipherSuite cipher_suite; | |||
| skipping to change at line 463 ¶ | skipping to change at line 465 ¶ | |||
| uses the inner variant. The inner extension has an empty payload, | uses the inner variant. The inner extension has an empty payload, | |||
| which is included because TLS servers are not allowed to provide | which is included because TLS servers are not allowed to provide | |||
| extensions in ServerHello which were not included in ClientHello. | extensions in ServerHello which were not included in ClientHello. | |||
| The outer extension has the following fields: | The outer extension has the following fields: | |||
| config_id: The ECHConfigContents.key_config.config_id for the chosen | config_id: The ECHConfigContents.key_config.config_id for the chosen | |||
| ECHConfig. | ECHConfig. | |||
| cipher_suite: The cipher suite used to encrypt ClientHelloInner. | cipher_suite: The cipher suite used to encrypt ClientHelloInner. | |||
| This MUST match a value provided in the corresponding | This MUST match a value provided in the corresponding | |||
| ECHConfigContents.cipher_suites list. | ECHConfigContents.key_config.cipher_suites list. | |||
| enc: The HPKE encapsulated key used by servers to decrypt the | enc: The HPKE encapsulated key used by servers to decrypt the | |||
| corresponding payload field. This field is empty in a | corresponding payload field. This field is empty in a | |||
| ClientHelloOuter sent in response to HelloRetryRequest. | ClientHelloOuter sent in response to HelloRetryRequest. | |||
| payload: The serialized and encrypted EncodedClientHelloInner | payload: The serialized and encrypted EncodedClientHelloInner | |||
| structure, encrypted using HPKE as described in Section 6.1. | structure, encrypted using HPKE as described in Section 6.1. | |||
| When a client offers the outer version of an "encrypted_client_hello" | When a client offers the outer version of an "encrypted_client_hello" | |||
| extension, the server MAY include an "encrypted_client_hello" | extension, the server MAY include an "encrypted_client_hello" | |||
| extension in its EncryptedExtensions message, as described in | extension in its EncryptedExtensions message, as described in | |||
| Section 7.1, with the following payload: | Section 7.1, with the following payload: | |||
| ~~ struct { ECHConfigList retry_configs; } ECHEncryptedExtensions; ~~ | struct { | |||
| ECHConfigList retry_configs; | ||||
| } ECHEncryptedExtensions; | ||||
| The response is valid only when the server used the ClientHelloOuter. | The response is valid only when the server used the ClientHelloOuter. | |||
| If the server sent this extension in response to the inner variant, | If the server sent this extension in response to the inner variant, | |||
| then the client MUST abort with an "unsupported_extension" alert. | then the client MUST abort with an "unsupported_extension" alert. | |||
| retry_configs: An ECHConfigList structure containing one or more | retry_configs: An ECHConfigList structure containing one or more | |||
| ECHConfig structures, in decreasing order of preference, to be | ECHConfig structures, in decreasing order of preference, to be | |||
| used by the client as described in Section 6.1.6. These are known | used by the client as described in Section 6.1.6. These are known | |||
| as the server's "retry configurations". | as the server's "retry configurations". | |||
| Finally, when the client offers the "encrypted_client_hello", if the | Finally, when the client offers the "encrypted_client_hello", if the | |||
| payload is the inner variant and the server responds with | payload is the inner variant and the server responds with | |||
| HelloRetryRequest, it MUST include an "encrypted_client_hello" | HelloRetryRequest, it MUST include an "encrypted_client_hello" | |||
| extension with the following payload: | extension with the following payload: | |||
| ~~ struct { opaque confirmation[8]; } ECHHelloRetryRequest; ~~ | struct { | |||
| opaque confirmation[8]; | ||||
| } ECHHelloRetryRequest; | ||||
| The value of ECHHelloRetryRequest.confirmation is set to | The value of ECHHelloRetryRequest.confirmation is set to | |||
| hrr_accept_confirmation as described in Section 7.2.1. | hrr_accept_confirmation as described in Section 7.2.1. | |||
| This document also defines the "ech_required" alert, which the client | This document also defines the "ech_required" alert, which the client | |||
| MUST send when it offered an "encrypted_client_hello" extension that | MUST send when it offered an "encrypted_client_hello" extension that | |||
| was not accepted by the server. (See Section 11.2.) | was not accepted by the server. (See Section 11.2.) | |||
| 5.1. Encoding the ClientHelloInner | 5.1. Encoding the ClientHelloInner | |||
| Before encrypting, the client pads and optionally compresses | Before encrypting, the client pads and optionally compresses | |||
| ClientHelloInner into an EncodedClientHelloInner structure, defined | ClientHelloInner into an EncodedClientHelloInner structure, defined | |||
| below: | below: | |||
| ~~ struct { ClientHello client_hello; uint8 zeros[length_of_padding]; | struct { | |||
| } EncodedClientHelloInner; ~~ | ClientHello client_hello; | |||
| uint8 zeros[length_of_padding]; | ||||
| } EncodedClientHelloInner; | ||||
| The client_hello field is computed by first making a copy of | The client_hello field is computed by first making a copy of | |||
| ClientHelloInner and setting the legacy_session_id field to the empty | ClientHelloInner and setting the legacy_session_id field to the empty | |||
| string. In TLS, this field uses the ClientHello structure defined in | string. In TLS, this field uses the ClientHello structure defined in | |||
| Section 4.1.2 of [RFC8446]. In DTLS, it uses the ClientHello | Section 4.1.2 of [RFC8446]. In DTLS, it uses the ClientHello | |||
| structure defined in Section 5.3 of [RFC9147]. This does not include | structure defined in Section 5.3 of [RFC9147]. This does not include | |||
| Handshake structure's four-byte header in TLS, nor twelve-byte header | the Handshake structure's four-byte header in TLS, nor the twelve- | |||
| in DTLS. The zeros field MUST be all zeroes of length | byte header in DTLS. The zeros field MUST be all zeros of length | |||
| length_of_padding (see Section 6.1.3). | length_of_padding (see Section 6.1.3). | |||
| Repeating large extensions, such as "key_share" with post-quantum | Repeating large extensions, such as "key_share" with post-quantum | |||
| algorithms, between ClientHelloInner and ClientHelloOuter can lead to | algorithms, between ClientHelloInner and ClientHelloOuter can lead to | |||
| excessive size. To reduce the size impact, the client MAY substitute | excessive size. To reduce the size impact, the client MAY substitute | |||
| extensions which it knows will be duplicated in ClientHelloOuter. It | extensions which it knows will be duplicated in ClientHelloOuter. It | |||
| does so by removing and replacing extensions from | does so by removing and replacing extensions from | |||
| EncodedClientHelloInner with a single "ech_outer_extensions" | EncodedClientHelloInner with a single "ech_outer_extensions" | |||
| extension, defined as follows: | extension, defined as follows: | |||
| ~~ enum { ech_outer_extensions(0xfd00), (65535) } ExtensionType; | enum { | |||
| ech_outer_extensions(0xfd00), (65535) | ||||
| } ExtensionType; | ||||
| ExtensionType OuterExtensions<2..254>; ~~ | ExtensionType OuterExtensions<2..254>; | |||
| OuterExtensions contains the removed ExtensionType values. Each | OuterExtensions contains a list of the removed ExtensionType values. | |||
| value references the matching extension in ClientHelloOuter. The | Each value references the matching extension in ClientHelloOuter. | |||
| values MUST be ordered contiguously in ClientHelloInner, and the | The values MUST be ordered contiguously in ClientHelloInner, and the | |||
| "ech_outer_extensions" extension MUST be inserted in the | "ech_outer_extensions" extension MUST be inserted in the | |||
| corresponding position in EncodedClientHelloInner. Additionally, the | corresponding position in EncodedClientHelloInner. Additionally, the | |||
| extensions MUST appear in ClientHelloOuter in the same relative | extensions MUST appear in ClientHelloOuter in the same relative | |||
| order. However, there is no requirement that they be contiguous. | order. However, there is no requirement that they be contiguous. | |||
| For example, OuterExtensions may contain extensions A, B, and C, | For example, OuterExtensions may contain extensions A, B, and C, | |||
| while ClientHelloOuter contains extensions A, D, B, C, E, and F. | while ClientHelloOuter contains extensions A, D, B, C, E, and F. | |||
| The "ech_outer_extensions" extension can only be included in | The "ech_outer_extensions" extension can only be included in | |||
| EncodedClientHelloInner and MUST NOT appear in either | EncodedClientHelloInner and MUST NOT appear in either | |||
| ClientHelloOuter or ClientHelloInner. | ClientHelloOuter or ClientHelloInner. | |||
| skipping to change at line 578 ¶ | skipping to change at line 588 ¶ | |||
| * "encrypted_client_hello" is referenced in OuterExtensions. | * "encrypted_client_hello" is referenced in OuterExtensions. | |||
| * The extensions in ClientHelloOuter corresponding to those in | * The extensions in ClientHelloOuter corresponding to those in | |||
| OuterExtensions do not occur in the same order. | OuterExtensions do not occur in the same order. | |||
| These requirements prevent an attacker from performing a packet | These requirements prevent an attacker from performing a packet | |||
| amplification attack by crafting a ClientHelloOuter which | amplification attack by crafting a ClientHelloOuter which | |||
| decompresses to a much larger ClientHelloInner. This is discussed | decompresses to a much larger ClientHelloInner. This is discussed | |||
| further in Section 10.12.4. | further in Section 10.12.4. | |||
| Implementations SHOULD construct the ClientHelloInner in linear time. | Receiving implementations SHOULD construct the ClientHelloInner in | |||
| Quadratic time implementations (such as may happen via naive copying) | linear time. Quadratic time implementations (such as may happen via | |||
| create a denial-of-service risk. Appendix A describes a linear-time | naive copying) create a denial-of-service risk. Appendix A describes | |||
| procedure that may be used for this purpose. | a linear-time procedure that may be used for this purpose. | |||
| 5.2. Authenticating the ClientHelloOuter | 5.2. Authenticating the ClientHelloOuter | |||
| To prevent a network attacker from modifying the ClientHelloOuter | To prevent a network attacker from modifying the ClientHelloOuter | |||
| while keeping the same encrypted ClientHelloInner (see | while keeping the same encrypted ClientHelloInner (see | |||
| Section 10.12.3), ECH authenticates ClientHelloOuter by passing | Section 10.12.3), ECH authenticates ClientHelloOuter by passing | |||
| ClientHelloOuterAAD as the associated data for HPKE sealing and | ClientHelloOuterAAD as the associated data for HPKE sealing and | |||
| opening operations. The ClientHelloOuterAAD is a serialized | opening operations. The ClientHelloOuterAAD is a serialized | |||
| ClientHello structure, defined in Section 4.1.2 of [RFC8446] for TLS | ClientHello structure, defined in Section 4.1.2 of [RFC8446] for TLS | |||
| and Section 5.3 of [RFC9147] for DTLS, which matches the | and Section 5.3 of [RFC9147] for DTLS, which matches the | |||
| ClientHelloOuter except that the payload field of the | ClientHelloOuter except that the payload field of the | |||
| "encrypted_client_hello" is replaced with a byte string of the same | "encrypted_client_hello" is replaced with a byte string of the same | |||
| length but whose contents are zeros. This value does not include | length but whose contents are zeros. This value does not include the | |||
| Handshake structure's four-byte header in TLS nor twelve-byte header | Handshake structure's four-byte header in TLS nor the twelve-byte | |||
| in DTLS. | header in DTLS. | |||
| 6. Client Behavior | 6. Client Behavior | |||
| Clients that implement the ECH extension behave in one of two ways: | Clients that implement the ECH extension behave in one of two ways: | |||
| either they offer a real ECH extension, as described in Section 6.1, | either they offer a real ECH extension, as described in Section 6.1, | |||
| or they send a Generate Random Extensions And Sustain Extensibility | or they send a Generate Random Extensions And Sustain Extensibility | |||
| (GREASE) [RFC8701] ECH extension, as described in Section 6.2. | (GREASE) [RFC8701] ECH extension, as described in Section 6.2. The | |||
| Clients of the latter type do not negotiate ECH. Instead, they | client offers ECH if it is in possession of a compatible ECH | |||
| configuration and sends GREASE ECH (see Section 6.2) otherwise. | ||||
| Clients of the latter type do not negotiate ECH; instead, they | ||||
| generate a dummy ECH extension that is ignored by the server. (See | generate a dummy ECH extension that is ignored by the server. (See | |||
| Section 10.10.4 for an explanation.) The client offers ECH if it is | Section 10.10.4 for an explanation.) It is also possible for clients | |||
| in possession of a compatible ECH configuration and sends GREASE ECH | to always send GREASE ECH without implementing the remainder of this | |||
| (see Section 6.2) otherwise. | specification. | |||
| 6.1. Offering ECH | 6.1. Offering ECH | |||
| To offer ECH, the client first chooses a suitable ECHConfig from the | To offer ECH, the client first chooses a suitable ECHConfig from the | |||
| server's ECHConfigList. To determine if a given ECHConfig is | server's ECHConfigList. To determine if a given ECHConfig is | |||
| suitable, it checks that it supports the KEM algorithm identified by | suitable, it checks that it supports the KEM algorithm identified by | |||
| ECHConfig.contents.kem_id, at least one KDF/AEAD algorithm identified | ECHConfig.contents.key_config.kem_id, at least one KDF/AEAD algorithm | |||
| by ECHConfig.contents.cipher_suites, and the version of ECH indicated | identified by ECHConfig.contents.key_config.cipher_suites, and the | |||
| by ECHConfig.version. Once a suitable configuration is found, the | version of ECH indicated by ECHConfig.version. Once a suitable | |||
| client selects the cipher suite it will use for encryption. It MUST | configuration is found, the client selects the cipher suite it will | |||
| NOT choose a cipher suite or version not advertised by the | use for encryption. It MUST NOT choose a cipher suite or version not | |||
| configuration. If no compatible configuration is found, then the | advertised by the configuration. If no compatible configuration is | |||
| client SHOULD proceed as described in Section 6.2. | found, then the client SHOULD proceed as described in Section 6.2. | |||
| Next, the client constructs the ClientHelloInner message just as it | Next, the client constructs the ClientHelloInner message just as it | |||
| does a standard ClientHello, with the exception of the following | does a standard ClientHello, with the exception of the following | |||
| rules: | rules: | |||
| 1. It MUST NOT offer to negotiate TLS 1.2 or below. This is | 1. It MUST NOT offer to negotiate TLS 1.2 or below. This is | |||
| necessary to ensure the backend server does not negotiate a TLS | necessary to ensure the backend server does not negotiate a TLS | |||
| version that is incompatible with ECH. | version that is incompatible with ECH. | |||
| 2. It MUST NOT offer to resume any session for TLS 1.2 and below. | 2. It MUST NOT offer to resume any session for TLS 1.2 and below. | |||
| skipping to change at line 645 ¶ | skipping to change at line 657 ¶ | |||
| 4. It MUST include the "encrypted_client_hello" extension of type | 4. It MUST include the "encrypted_client_hello" extension of type | |||
| inner as described in Section 5. (This requirement is not | inner as described in Section 5. (This requirement is not | |||
| applicable when the "encrypted_client_hello" extension is | applicable when the "encrypted_client_hello" extension is | |||
| generated as described in Section 6.2.) | generated as described in Section 6.2.) | |||
| The client then constructs EncodedClientHelloInner as described in | The client then constructs EncodedClientHelloInner as described in | |||
| Section 5.1. It also computes an HPKE encryption context and enc | Section 5.1. It also computes an HPKE encryption context and enc | |||
| value as: | value as: | |||
| ~~ pkR = DeserializePublicKey(ECHConfig.contents.public_key) enc, | pkR = DeserializePublicKey(ECHConfig.contents.key_config.public_key) | |||
| context = SetupBaseS(pkR, "tls ech" || 0x00 || ECHConfig) ~~ | enc, context = SetupBaseS(pkR, | |||
| "tls ech" || 0x00 || ECHConfig) | ||||
| Next, it constructs a partial ClientHelloOuterAAD as it does a | Next, it constructs a partial ClientHelloOuterAAD as it does a | |||
| standard ClientHello, with the exception of the following rules: | standard ClientHello, with the exception of the following rules: | |||
| 1. It MUST offer to negotiate TLS 1.3 or above. | 1. It MUST offer to negotiate TLS 1.3 or above. | |||
| 2. If it compressed any extensions in EncodedClientHelloInner, it | 2. If it compressed any extensions in EncodedClientHelloInner, it | |||
| MUST copy the corresponding extensions from ClientHelloInner. | MUST copy the corresponding extensions from ClientHelloInner. | |||
| The copied extensions additionally MUST be in the same relative | The copied extensions additionally MUST be in the same relative | |||
| order as in ClientHelloInner. | order as in ClientHelloInner. | |||
| skipping to change at line 733 ¶ | skipping to change at line 746 ¶ | |||
| * payload, a placeholder byte string containing L zeros. | * payload, a placeholder byte string containing L zeros. | |||
| If configuration identifiers (see Section 10.4) are to be ignored, | If configuration identifiers (see Section 10.4) are to be ignored, | |||
| config_id SHOULD be set to a randomly generated byte in the first | config_id SHOULD be set to a randomly generated byte in the first | |||
| ClientHelloOuter and, in the event of a HelloRetryRequest (HRR), MUST | ClientHelloOuter and, in the event of a HelloRetryRequest (HRR), MUST | |||
| be left unchanged for the second ClientHelloOuter. | be left unchanged for the second ClientHelloOuter. | |||
| The client serializes this structure to construct the | The client serializes this structure to construct the | |||
| ClientHelloOuterAAD. It then computes the final payload as: | ClientHelloOuterAAD. It then computes the final payload as: | |||
| ~~ final_payload = context.Seal(ClientHelloOuterAAD, | final_payload = context.Seal(ClientHelloOuterAAD, | |||
| EncodedClientHelloInner) ~~ | EncodedClientHelloInner) | |||
| Including ClientHelloOuterAAD as the HPKE AAD binds the | Including ClientHelloOuterAAD as the HPKE AAD binds the | |||
| ClientHelloOuter to the ClientHelloInner, thus preventing attackers | ClientHelloOuter to the ClientHelloInner, thus preventing attackers | |||
| from modifying ClientHelloOuter while keeping the same | from modifying ClientHelloOuter while keeping the same | |||
| ClientHelloInner, as described in Section 10.12.3. | ClientHelloInner, as described in Section 10.12.3. | |||
| Finally, the client replaces payload with final_payload to obtain | Finally, the client replaces payload with final_payload to obtain | |||
| ClientHelloOuter. The two values have the same length, so it is not | ClientHelloOuter. The two values have the same length, so it is not | |||
| necessary to recompute length prefixes in the serialized structure. | necessary to recompute length prefixes in the serialized structure. | |||
| skipping to change at line 836 ¶ | skipping to change at line 849 ¶ | |||
| EncryptedExtension, so that handshake message also needs to be padded | EncryptedExtension, so that handshake message also needs to be padded | |||
| using TLS record layer padding. | using TLS record layer padding. | |||
| 6.1.4. Determining ECH Acceptance | 6.1.4. Determining ECH Acceptance | |||
| As described in Section 7, the server may either accept ECH and use | As described in Section 7, the server may either accept ECH and use | |||
| ClientHelloInner or reject it and use ClientHelloOuter. This is | ClientHelloInner or reject it and use ClientHelloOuter. This is | |||
| determined by the server's initial message. | determined by the server's initial message. | |||
| If the message does not negotiate TLS 1.3 or higher, the server has | If the message does not negotiate TLS 1.3 or higher, the server has | |||
| rejected ECH. Otherwise, it is either a ServerHello or | rejected ECH. Otherwise, the message will be either a ServerHello or | |||
| HelloRetryRequest. | a HelloRetryRequest. | |||
| If the message is a ServerHello, the client computes | If the message is a ServerHello, the client computes | |||
| accept_confirmation as described in Section 7.2. If this value | accept_confirmation as described in Section 7.2. If this value | |||
| matches the last 8 bytes of ServerHello.random, the server has | matches the last 8 bytes of ServerHello.random, the server has | |||
| accepted ECH. Otherwise, it has rejected ECH. | accepted ECH. Otherwise, it has rejected ECH. | |||
| If the message is a HelloRetryRequest, the client checks for the | If the message is a HelloRetryRequest, the client checks for the | |||
| "encrypted_client_hello" extension. If none is found, the server has | "encrypted_client_hello" extension. If none is found, the server has | |||
| rejected ECH. Otherwise, if it has a length other than 8, the client | rejected ECH. Otherwise, if the extension has a length other than 8, | |||
| aborts the handshake with a "decode_error" alert. Otherwise, the | the client MUST abort the handshake with a "decode_error" alert. | |||
| client computes hrr_accept_confirmation as described in | Otherwise, the client computes hrr_accept_confirmation as described | |||
| Section 7.2.1. If this value matches the extension payload, the | in Section 7.2.1. If this value matches the extension payload, the | |||
| server has accepted ECH. Otherwise, it has rejected ECH. | server has accepted ECH. Otherwise, it has rejected ECH. | |||
| If the server accepts ECH, the client handshakes with | If the server accepts ECH, the client handshakes with | |||
| ClientHelloInner as described in Section 6.1.5. Otherwise, the | ClientHelloInner as described in Section 6.1.5. Otherwise, the | |||
| client handshakes with ClientHelloOuter as described in | client handshakes with ClientHelloOuter as described in | |||
| Section 6.1.6. | Section 6.1.6. | |||
| 6.1.5. Handshaking with ClientHelloInner | 6.1.5. Handshaking with ClientHelloInner | |||
| If the server accepts ECH, the client proceeds with the connection as | If the server accepts ECH, the client proceeds with the connection as | |||
| skipping to change at line 929 ¶ | skipping to change at line 942 ¶ | |||
| processing described below and then abort the connection with an | processing described below and then abort the connection with an | |||
| "ech_required" alert before sending any application data to the | "ech_required" alert before sending any application data to the | |||
| server. | server. | |||
| If the server provided "retry_configs" and if at least one of the | If the server provided "retry_configs" and if at least one of the | |||
| values contains a version supported by the client, the client can | values contains a version supported by the client, the client can | |||
| regard the ECH configuration as securely replaced by the server. It | regard the ECH configuration as securely replaced by the server. It | |||
| SHOULD retry the handshake with a new transport connection using the | SHOULD retry the handshake with a new transport connection using the | |||
| retry configurations supplied by the server. | retry configurations supplied by the server. | |||
| Clients can implement a new transport connection in a way that best | Because the new ECH configuration replaces the old ECH configuration, | |||
| suits their deployment. For example, clients can reuse the same | clients can implement a new transport connection in any way that is | |||
| server IP address when establishing the new transport connection or | consistent with the previous ECH configuration. For example, clients | |||
| they can choose to use a different IP address if provided with | can reuse the same server IP address when establishing the new | |||
| options from DNS. ECH does not mandate any specific implementation | transport connection or they can choose to use a different IP address | |||
| choices when establishing this new connection. | if DNS provided other IP addresses for the previous configuration. | |||
| However, it is not safe to use IP addresses discovered with a new DNS | ||||
| query, as those may correspond to a different ECH server | ||||
| configuration, for instance associated with a different ECH server | ||||
| with a different public_name. | ||||
| The retry configurations are meant to be used for retried | The retry configurations are meant to be used for retried | |||
| connections. Further use of retry configurations could yield a | connections. Further use of retry configurations could yield a | |||
| tracking vector. In settings where the client will otherwise already | tracking vector. In settings where the client will otherwise already | |||
| let the server track the client, e.g., because the client will send | let the server track the client, e.g., because the client will send | |||
| cookies to the server in parallel connections, using the retry | cookies to the server in parallel connections, using the retry | |||
| configurations for these parallel connections does not introduce a | configurations for these parallel connections does not introduce a | |||
| new tracking vector. | new tracking vector. | |||
| If none of the values provided in "retry_configs" contains a | If none of the values provided in "retry_configs" contains a | |||
| skipping to change at line 996 ¶ | skipping to change at line 1013 ¶ | |||
| Note that authenticating a connection for the public name does not | Note that authenticating a connection for the public name does not | |||
| authenticate it for the origin. The TLS implementation MUST NOT | authenticate it for the origin. The TLS implementation MUST NOT | |||
| report such connections as successful to the application. It | report such connections as successful to the application. It | |||
| additionally MUST ignore all session tickets and session IDs | additionally MUST ignore all session tickets and session IDs | |||
| presented by the server. These connections are only used to trigger | presented by the server. These connections are only used to trigger | |||
| retries, as described in Section 6.1.6. This may be implemented, for | retries, as described in Section 6.1.6. This may be implemented, for | |||
| instance, by reporting a failed connection with a dedicated error | instance, by reporting a failed connection with a dedicated error | |||
| code. | code. | |||
| Prior to attempting a connection, a client SHOULD validate the | Prior to attempting a connection, a client SHOULD validate the | |||
| ECHConfig. Clients SHOULD ignore any ECHConfig structure with a | ECHConfig.contents.public_name. Clients SHOULD ignore any ECHConfig | |||
| public_name that is not a valid host name in preferred name syntax | structure with a public_name that is not a valid host name in | |||
| (see Section 2 of [DNS-TERMS]). That is, to be valid, the | preferred name syntax (see Section 2 of [DNS-TERMS]). That is, to be | |||
| public_name needs to be a dot-separated sequence of LDH labels, as | valid, the public_name needs to be a dot-separated sequence of LDH | |||
| defined in Section 2.3.1 of [RFC5890], where: | labels, as defined in Section 2.3.1 of [RFC5890], where: | |||
| * the sequence does not begin or end with an ASCII dot, and | * the sequence does not begin or end with an ASCII dot, and | |||
| * all labels are at most 63 octets. | * all labels are at most 63 octets. | |||
| Clients additionally SHOULD ignore the structure if the final LDH | Clients additionally SHOULD ignore the structure if the final LDH | |||
| label either consists of all ASCII digits (i.e., '0' through '9') or | label either consists of all ASCII digits (i.e., '0' through '9') or | |||
| is "0x" or "0X" followed by some, possibly empty, sequence of ASCII | is "0x" or "0X" followed by some, possibly empty, sequence of ASCII | |||
| hexadecimal digits (i.e., '0' through '9', 'a' through 'f', and 'A' | hexadecimal digits (i.e., '0' through '9', 'a' through 'f', and 'A' | |||
| through 'F'). This avoids public_name values that may be interpreted | through 'F'). This avoids public_name values that may be interpreted | |||
| skipping to change at line 1060 ¶ | skipping to change at line 1077 ¶ | |||
| 6.2.1. Client Greasing | 6.2.1. Client Greasing | |||
| If the client attempts to connect to a server and does not have an | If the client attempts to connect to a server and does not have an | |||
| ECHConfig structure available for the server, it SHOULD send a GREASE | ECHConfig structure available for the server, it SHOULD send a GREASE | |||
| [RFC8701] "encrypted_client_hello" extension in the first ClientHello | [RFC8701] "encrypted_client_hello" extension in the first ClientHello | |||
| as follows: | as follows: | |||
| * Set the config_id field to a random byte. | * Set the config_id field to a random byte. | |||
| * Set the cipher_suite field to a supported | * Set the cipher_suite field to a supported | |||
| HpkeSymmetricCipherSuite. The selection SHOULD vary to exercise | HpkeSymmetricCipherSuite. The selection SHOULD vary, so that all | |||
| all supported configurations, but MAY be held constant for | plausible configurations are exercised, but MAY be held constant | |||
| successive connections to the same server in the same session. | for successive connections to the same server in the same session. | |||
| Note: A "plausible" configuration is one that an observer might | ||||
| expect to see. A client that fully supports ECH will have a set | ||||
| of supported HPKE cipher suites to select from. A client that | ||||
| only supports GREASE ECH has no such list, so it should select | ||||
| from a set of values that are in common usage. | ||||
| * Set the enc field to a randomly generated valid encapsulated | * Set the enc field to a randomly generated valid encapsulated | |||
| public key output by the HPKE KEM. | public key output by the HPKE KEM. | |||
| * Set the payload field to a randomly generated string of L+C bytes, | * Set the payload field to a randomly generated string of L+C bytes, | |||
| where C is the ciphertext expansion of the selected AEAD scheme | where C is the ciphertext expansion of the selected AEAD scheme | |||
| and L is the size of the EncodedClientHelloInner the client would | and L is the size of the EncodedClientHelloInner the client would | |||
| compute when offering ECH, padded according to Section 6.1.3. | compute when offering ECH, padded according to Section 6.1.3. | |||
| If sending a second ClientHello in response to a HelloRetryRequest, | If sending a second ClientHello in response to a HelloRetryRequest, | |||
| skipping to change at line 1130 ¶ | skipping to change at line 1152 ¶ | |||
| the client-facing server or as the backend server. Depending on the | the client-facing server or as the backend server. Depending on the | |||
| server role, the ECHClientHello will be different: | server role, the ECHClientHello will be different: | |||
| * A client-facing server expects an ECHClientHello.type of outer, | * A client-facing server expects an ECHClientHello.type of outer, | |||
| and proceeds as described in Section 7.1 to extract a | and proceeds as described in Section 7.1 to extract a | |||
| ClientHelloInner, if available. | ClientHelloInner, if available. | |||
| * A backend server expects an ECHClientHello.type of inner, and | * A backend server expects an ECHClientHello.type of inner, and | |||
| proceeds as described in Section 7.2. | proceeds as described in Section 7.2. | |||
| If ECHClientHello.type is not a valid ECHClientHelloType, then the | ||||
| server MUST abort with an "illegal_parameter" alert. | ||||
| In split mode, a client-facing server which receives a ClientHello | In split mode, a client-facing server which receives a ClientHello | |||
| with ECHClientHello.type of inner MUST abort with an | with ECHClientHello.type of inner MUST abort with an | |||
| "illegal_parameter" alert. Similarly, in split mode, a backend | "illegal_parameter" alert. Similarly, in split mode, a backend | |||
| server which receives a ClientHello with ECHClientHello.type of outer | server which receives a ClientHello with ECHClientHello.type of outer | |||
| MUST abort with an "illegal_parameter" alert. | MUST abort with an "illegal_parameter" alert. | |||
| In shared mode, a server plays both roles, first decrypting the | In shared mode, a server plays both roles, first decrypting the | |||
| ClientHelloOuter and then using the contents of the ClientHelloInner. | ClientHelloOuter and then using the contents of the ClientHelloInner. | |||
| A shared mode server which receives a ClientHello with | A shared mode server which receives a ClientHello with | |||
| ECHClientHello.type of inner MUST abort with an "illegal_parameter" | ECHClientHello.type of inner MUST abort with an "illegal_parameter" | |||
| alert, because such a ClientHello should never be received directly | alert, because such a ClientHello should never be received directly | |||
| from the network. | from the network. | |||
| If ECHClientHello.type is not a valid ECHClientHelloType, then the | ||||
| server MUST abort with an "illegal_parameter" alert. | ||||
| If the "encrypted_client_hello" is not present, then the server | If the "encrypted_client_hello" is not present, then the server | |||
| completes the handshake normally, as described in [RFC8446]. | completes the handshake normally, as described in [RFC8446]. | |||
| 7.1. Client-Facing Server | 7.1. Client-Facing Server | |||
| Upon receiving an "encrypted_client_hello" extension in an initial | Upon receiving an "encrypted_client_hello" extension in an initial | |||
| ClientHello, the client-facing server determines if it will accept | ClientHello, the client-facing server determines if it will accept | |||
| ECH prior to negotiating any other TLS parameters. Note that | ECH prior to negotiating any other TLS parameters. Note that | |||
| successfully decrypting the extension will result in a new | successfully decrypting the extension will result in a new | |||
| ClientHello to process, so even the client's TLS version preferences | ClientHello to process, so even the client's TLS version preferences | |||
| skipping to change at line 1187 ¶ | skipping to change at line 1209 ¶ | |||
| follows. | follows. | |||
| The server verifies that the ECHConfig supports the cipher suite | The server verifies that the ECHConfig supports the cipher suite | |||
| indicated by the ECHClientHello.cipher_suite and that the version of | indicated by the ECHClientHello.cipher_suite and that the version of | |||
| ECH indicated by the client matches the ECHConfig.version. If not, | ECH indicated by the client matches the ECHConfig.version. If not, | |||
| the server continues to the next candidate ECHConfig. | the server continues to the next candidate ECHConfig. | |||
| Next, the server decrypts ECHClientHello.payload, using the private | Next, the server decrypts ECHClientHello.payload, using the private | |||
| key skR corresponding to ECHConfig, as follows: | key skR corresponding to ECHConfig, as follows: | |||
| ~~ context = SetupBaseR(ECHClientHello.enc, skR, "tls ech" || 0x00 || | context = SetupBaseR(ECHClientHello.enc, skR, | |||
| ECHConfig) EncodedClientHelloInner = | "tls ech" || 0x00 || ECHConfig) | |||
| context.Open(ClientHelloOuterAAD, ECHClientHello.payload) ~~ | EncodedClientHelloInner = context.Open(ClientHelloOuterAAD, | |||
| ECHClientHello.payload) | ||||
| ClientHelloOuterAAD is computed from ClientHelloOuter as described in | ClientHelloOuterAAD is computed from ClientHelloOuter as described in | |||
| Section 5.2. The info parameter to SetupBaseR is the concatenation | Section 5.2. The info parameter to SetupBaseR is the concatenation | |||
| "tls ech", a zero byte, and the serialized ECHConfig. If decryption | "tls ech", a zero byte, and the serialized ECHConfig. If decryption | |||
| fails, the server continues to the next candidate ECHConfig. | fails, the server continues to the next candidate ECHConfig. | |||
| Otherwise, the server reconstructs ClientHelloInner from | Otherwise, the server reconstructs ClientHelloInner from | |||
| EncodedClientHelloInner, as described in Section 5.1. It then stops | EncodedClientHelloInner, as described in Section 5.1. It then stops | |||
| iterating over the candidate ECHConfig values. | iterating over the candidate ECHConfig values. | |||
| Once the server has chosen the correct ECHConfig, it MAY verify that | Once the server has chosen the correct ECHConfig, it MAY verify that | |||
| skipping to change at line 1247 ¶ | skipping to change at line 1270 ¶ | |||
| support multiple versions at once. | support multiple versions at once. | |||
| Note that decryption failure could indicate a GREASE ECH extension | Note that decryption failure could indicate a GREASE ECH extension | |||
| (see Section 6.2), so it is necessary for servers to proceed with the | (see Section 6.2), so it is necessary for servers to proceed with the | |||
| connection and rely on the client to abort if ECH was required. In | connection and rely on the client to abort if ECH was required. In | |||
| particular, the unrecognized value alone does not indicate a | particular, the unrecognized value alone does not indicate a | |||
| misconfigured ECH advertisement (Section 8.1.1). Instead, servers | misconfigured ECH advertisement (Section 8.1.1). Instead, servers | |||
| can measure occurrences of the "ech_required" alert to detect this | can measure occurrences of the "ech_required" alert to detect this | |||
| case. | case. | |||
| 7.1.1. Sending HelloRetryRequest | 7.1.1. Processing ClientHello after HelloRetryRequest | |||
| After sending or forwarding a HelloRetryRequest, the client-facing | After sending or forwarding a HelloRetryRequest, the client-facing | |||
| server does not repeat the steps in Section 7.1 with the second | server does not repeat the steps in Section 7.1 with the second | |||
| ClientHelloOuter. Instead, it continues with the ECHConfig selection | ClientHelloOuter. Instead, it continues with the ECHConfig selection | |||
| from the first ClientHelloOuter as follows: | from the first ClientHelloOuter as follows: | |||
| If the client-facing server accepted ECH, it checks that the second | If the client-facing server accepted ECH, it checks that the second | |||
| ClientHelloOuter also contains the "encrypted_client_hello" | ClientHelloOuter also contains the "encrypted_client_hello" | |||
| extension. If not, it MUST abort the handshake with a | extension. If not, it MUST abort the handshake with a | |||
| "missing_extension" alert. Otherwise, it checks that | "missing_extension" alert. Otherwise, it checks that | |||
| ECHClientHello.cipher_suite and ECHClientHello.config_id are | ECHClientHello.cipher_suite and ECHClientHello.config_id are | |||
| unchanged, and that ECHClientHello.enc is empty. If not, it MUST | unchanged, and that ECHClientHello.enc is empty. If not, it MUST | |||
| abort the handshake with an "illegal_parameter" alert. | abort the handshake with an "illegal_parameter" alert. | |||
| Finally, it decrypts the new ECHClientHello.payload as a second | Finally, it decrypts the new ECHClientHello.payload as a second | |||
| message with the previous HPKE context: | message with the previous HPKE context: | |||
| ~~ EncodedClientHelloInner = context.Open(ClientHelloOuterAAD, | EncodedClientHelloInner = context.Open(ClientHelloOuterAAD, | |||
| ECHClientHello.payload) ~~ | ECHClientHello.payload) | |||
| ClientHelloOuterAAD is computed as described in Section 5.2, but | ClientHelloOuterAAD is computed as described in Section 5.2, but | |||
| using the second ClientHelloOuter. If decryption fails, the client- | using the second ClientHelloOuter. If decryption fails, the client- | |||
| facing server MUST abort the handshake with a "decrypt_error" alert. | facing server MUST abort the handshake with a "decrypt_error" alert. | |||
| Otherwise, it reconstructs the second ClientHelloInner from the new | Otherwise, it reconstructs the second ClientHelloInner from the new | |||
| EncodedClientHelloInner as described in Section 5.1, using the second | EncodedClientHelloInner as described in Section 5.1, using the second | |||
| ClientHelloOuter for any referenced extensions. | ClientHelloOuter for any referenced extensions. | |||
| The client-facing server then forwards the resulting ClientHelloInner | The client-facing server then forwards the resulting ClientHelloInner | |||
| to the backend server. It forwards all subsequent TLS messages | to the backend server. It forwards all subsequent TLS messages | |||
| skipping to change at line 1312 ¶ | skipping to change at line 1335 ¶ | |||
| The backend server embeds in ServerHello.random a string derived from | The backend server embeds in ServerHello.random a string derived from | |||
| the inner handshake. It begins by computing its ServerHello as | the inner handshake. It begins by computing its ServerHello as | |||
| usual, except the last 8 bytes of ServerHello.random are set to zero. | usual, except the last 8 bytes of ServerHello.random are set to zero. | |||
| It then computes the transcript hash for ClientHelloInner up to and | It then computes the transcript hash for ClientHelloInner up to and | |||
| including the modified ServerHello, as described in [RFC8446], | including the modified ServerHello, as described in [RFC8446], | |||
| Section 4.4.1. Let transcript_ech_conf denote the output. Finally, | Section 4.4.1. Let transcript_ech_conf denote the output. Finally, | |||
| the backend server overwrites the last 8 bytes of the | the backend server overwrites the last 8 bytes of the | |||
| ServerHello.random with the following string: | ServerHello.random with the following string: | |||
| ~~ accept_confirmation = HKDF-Expand-Label( HKDF-Extract(0, | accept_confirmation = HKDF-Expand-Label( | |||
| ClientHelloInner.random), "ech accept confirmation", | HKDF-Extract(0, ClientHelloInner.random), | |||
| transcript_ech_conf, 8) ~~ | "ech accept confirmation", | |||
| transcript_ech_conf, | ||||
| 8) | ||||
| where HKDF-Expand-Label is defined in [RFC8446], Section 7.1, "0" | where HKDF-Expand-Label is defined in [RFC8446], Section 7.1, "0" | |||
| indicates a string of Hash.length bytes set to zero, and Hash is the | indicates a string of Hash.length bytes set to zero, and Hash is the | |||
| hash function used to compute the transcript hash. In DTLS, the | hash function used to compute the transcript hash. In DTLS, the | |||
| modified version of HKDF-Expand-Label defined in [RFC9147], | modified version of HKDF-Expand-Label defined in [RFC9147], | |||
| Section 5.9 is used instead. | Section 5.9 is used instead. | |||
| The backend server MUST NOT perform this operation if it negotiated | The backend server MUST NOT perform this operation if it negotiated | |||
| TLS 1.2 or below. Note that doing so would overwrite the downgrade | TLS 1.2 or below. Note that doing so would overwrite the downgrade | |||
| signal for TLS 1.3 (see [RFC8446], Section 4.1.3). | signal for TLS 1.3 (see [RFC8446], Section 4.1.3). | |||
| skipping to change at line 1344 ¶ | skipping to change at line 1369 ¶ | |||
| The backend server begins by computing HelloRetryRequest as usual, | The backend server begins by computing HelloRetryRequest as usual, | |||
| except that it also contains an "encrypted_client_hello" extension | except that it also contains an "encrypted_client_hello" extension | |||
| with a payload of 8 zero bytes. It then computes the transcript hash | with a payload of 8 zero bytes. It then computes the transcript hash | |||
| for the first ClientHelloInner, denoted ClientHelloInner1, up to and | for the first ClientHelloInner, denoted ClientHelloInner1, up to and | |||
| including the modified HelloRetryRequest. Let | including the modified HelloRetryRequest. Let | |||
| transcript_hrr_ech_conf denote the output. Finally, the backend | transcript_hrr_ech_conf denote the output. Finally, the backend | |||
| server overwrites the payload of the "encrypted_client_hello" | server overwrites the payload of the "encrypted_client_hello" | |||
| extension with the following string: | extension with the following string: | |||
| ~~ hrr_accept_confirmation = HKDF-Expand-Label( HKDF-Extract(0, | hrr_accept_confirmation = HKDF-Expand-Label( | |||
| ClientHelloInner1.random), "hrr ech accept confirmation", | HKDF-Extract(0, ClientHelloInner1.random), | |||
| transcript_hrr_ech_conf, 8) ~~ | "hrr ech accept confirmation", | |||
| transcript_hrr_ech_conf, | ||||
| 8) | ||||
| In the subsequent ServerHello message, the backend server sends the | In the subsequent ServerHello message, the backend server sends the | |||
| accept_confirmation value as described in Section 7.2. | accept_confirmation value as described in Section 7.2. | |||
| 8. Deployment Considerations | 8. Deployment Considerations | |||
| The design of ECH as specified in this document necessarily requires | The design of ECH as specified in this document necessarily requires | |||
| changes to client, client-facing server, and backend server. | changes to client, client-facing server, and backend server. | |||
| Coordination between client-facing and backend server requires care, | Coordination between client-facing and backend server requires care, | |||
| as deployment mistakes can lead to compatibility issues. These are | as deployment mistakes can lead to compatibility issues. These are | |||
| discussed in Section 8.1. | discussed in Section 8.1. | |||
| Beyond coordination difficulties, ECH deployments may also induce | Beyond coordination difficulties, ECH deployments may also create | |||
| challenges for use cases of information that ECH protects. In | challenges for uses of information that ECH protects. In particular, | |||
| particular, use cases which depend on this unencrypted information | use cases which depend on this unencrypted information may no longer | |||
| may no longer work as desired. This is elaborated upon in | work as desired. This is elaborated upon in Section 8.2. | |||
| Section 8.2. | ||||
| 8.1. Compatibility Issues | 8.1. Compatibility Issues | |||
| Unlike most TLS extensions, placing the SNI value in an ECH extension | Unlike most TLS extensions, placing the SNI value in an ECH extension | |||
| is not interoperable with existing servers, which expect the value in | is not interoperable with existing servers, which expect the value in | |||
| the existing plaintext extension. Thus, server operators SHOULD | the existing plaintext extension. Thus, server operators SHOULD | |||
| ensure servers understand a given set of ECH keys before advertising | ensure servers understand a given set of ECH keys before advertising | |||
| them. Additionally, servers SHOULD retain support for any previously | them. Additionally, servers SHOULD retain support for any previously | |||
| advertised keys for the duration of their validity. | advertised keys for the duration of their validity. | |||
| skipping to change at line 1610 ¶ | skipping to change at line 1636 ¶ | |||
| perform trial decryption since they cannot identify the client's | perform trial decryption since they cannot identify the client's | |||
| chosen ECH key using the config_id value. As a result, ignoring | chosen ECH key using the config_id value. As a result, ignoring | |||
| configuration identifiers may exacerbate DoS attacks. Specifically, | configuration identifiers may exacerbate DoS attacks. Specifically, | |||
| an adversary may send malicious ClientHello messages, i.e., those | an adversary may send malicious ClientHello messages, i.e., those | |||
| which will not decrypt with any known ECH key, in order to force | which will not decrypt with any known ECH key, in order to force | |||
| wasteful decryption. Servers that support this feature should, for | wasteful decryption. Servers that support this feature should, for | |||
| example, implement some form of rate limiting mechanism to limit the | example, implement some form of rate limiting mechanism to limit the | |||
| potential damage caused by such attacks. | potential damage caused by such attacks. | |||
| Unless specified by the application using (D)TLS or externally | Unless specified by the application using (D)TLS or externally | |||
| configured, implementations MUST NOT use this mode. | configured, client implementations MUST NOT use this mode. | |||
| 10.5. Outer ClientHello | 10.5. Outer ClientHello | |||
| Any information that the client includes in the ClientHelloOuter is | Any information that the client includes in the ClientHelloOuter is | |||
| visible to passive observers. The client SHOULD NOT send values in | visible to passive observers. The client SHOULD NOT send values in | |||
| the ClientHelloOuter which would reveal a sensitive ClientHelloInner | the ClientHelloOuter which would reveal a sensitive ClientHelloInner | |||
| property, such as the true server name. It MAY send values | property, such as the true server name. It MAY send values | |||
| associated with the public name in the ClientHelloOuter. | associated with the public name in the ClientHelloOuter. | |||
| In particular, some extensions require the client send a server-name- | In particular, some extensions require the client send a server-name- | |||
| skipping to change at line 1903 ¶ | skipping to change at line 1929 ¶ | |||
| the attacker learns that its test certificate name was incorrect. As | the attacker learns that its test certificate name was incorrect. As | |||
| an example, suppose the client's SNI value in its inner ClientHello | an example, suppose the client's SNI value in its inner ClientHello | |||
| is "example.com," and the attacker replied with a Certificate for | is "example.com," and the attacker replied with a Certificate for | |||
| "test.com". If the client produces a verification failure alert | "test.com". If the client produces a verification failure alert | |||
| because of the mismatch faster than it would due to the Certificate | because of the mismatch faster than it would due to the Certificate | |||
| signature validation, information about the name leaks. Note that | signature validation, information about the name leaks. Note that | |||
| the attacker can also withhold the CertificateVerify message. In | the attacker can also withhold the CertificateVerify message. In | |||
| that scenario, a client which first verifies the Certificate would | that scenario, a client which first verifies the Certificate would | |||
| then respond similarly and leak the same information. | then respond similarly and leak the same information. | |||
| ~~ Client Attacker Server ClientHello + key_share + ech ------> | Client Attacker Server | |||
| (intercept) -----> X (drop) | ClientHello | |||
| + key_share | ||||
| + ech ------> (intercept) -----> X (drop) | ||||
| ServerHello | ServerHello | |||
| + key_share | + key_share | |||
| {EncryptedExtensions} | {EncryptedExtensions} | |||
| {CertificateRequest*} | {CertificateRequest*} | |||
| {Certificate*} | {Certificate*} | |||
| {CertificateVerify*} | {CertificateVerify*} | |||
| <------ Alert | <------ | |||
| ------> ~~ | Alert | |||
| ------> | ||||
| Figure 3: Client Reaction Attack | Figure 3: Client Reaction Attack | |||
| ClientHelloInner.random prevents this attack. In particular, since | ClientHelloInner.random prevents this attack: because the attacker | |||
| the attacker does not have access to this value, it cannot produce | does not have access to this value, it cannot produce the right | |||
| the right transcript and handshake keys needed for encrypting the | transcript and handshake keys needed for encrypting the Certificate | |||
| Certificate message. Thus, the client will fail to decrypt the | message. Thus, the client will fail to decrypt the Certificate and | |||
| Certificate and abort the connection. | abort the connection. | |||
| 10.12.2. HelloRetryRequest Hijack Mitigation | 10.12.2. HelloRetryRequest Hijack Mitigation | |||
| This attack aims to exploit server HRR state management to recover | This attack aims to exploit server HRR state management to recover | |||
| information about a legitimate ClientHello using its own attacker- | information about a legitimate ClientHello using its own attacker- | |||
| controlled ClientHello. To begin, the attacker intercepts and | controlled ClientHello. To begin, the attacker intercepts and | |||
| forwards a legitimate ClientHello with an "encrypted_client_hello" | forwards a legitimate ClientHello with an "encrypted_client_hello" | |||
| (ech) extension to the server, which triggers a legitimate | (ech) extension to the server, which triggers a legitimate | |||
| HelloRetryRequest in return. Rather than forward the retry to the | HelloRetryRequest in return. Rather than forward the retry to the | |||
| client, the attacker attempts to generate its own ClientHello in | client, the attacker attempts to generate its own ClientHello in | |||
| response based on the contents of the first ClientHello and | response based on the contents of the first ClientHello and | |||
| HelloRetryRequest exchange with the result that the server encrypts | HelloRetryRequest exchange with the result that the server encrypts | |||
| the Certificate to the attacker. If the server used the SNI from the | the Certificate to the attacker. If the server used the SNI from the | |||
| first ClientHello and the key share from the second (attacker- | first ClientHello and the key share from the second (attacker- | |||
| controlled) ClientHello, the Certificate produced would leak the | controlled) ClientHello, the Certificate produced would leak the | |||
| client's chosen SNI to the attacker. | client's chosen SNI to the attacker. | |||
| ~~ Client Attacker Server ClientHello + key_share + ech ------> | Client Attacker Server | |||
| (forward) -------> HelloRetryRequest + key_share (intercept) <------- | ClientHello | |||
| + key_share | ||||
| + ech ------> (forward) -------> | ||||
| HelloRetryRequest | ||||
| + key_share | ||||
| (intercept) <------- | ||||
| ClientHello | ClientHello | |||
| + key_share' | + key_share' | |||
| + ech' -------> | + ech' -------> | |||
| ServerHello | ServerHello | |||
| + key_share | + key_share | |||
| {EncryptedExtensions} | {EncryptedExtensions} | |||
| {CertificateRequest*} | {CertificateRequest*} | |||
| {Certificate*} | {Certificate*} | |||
| {CertificateVerify*} | {CertificateVerify*} | |||
| {Finished} | {Finished} | |||
| <------- | <------- | |||
| (process server flight) ~~ | (process server flight) | |||
| Figure 4: HelloRetryRequest Hijack Attack | Figure 4: HelloRetryRequest Hijack Attack | |||
| This attack is mitigated by using the same HPKE context for both | This attack is mitigated by using the same HPKE context for both | |||
| ClientHello messages. The attacker does not possess the context's | ClientHello messages. The attacker does not possess the context's | |||
| keys, so it cannot generate a valid encryption of the second inner | keys, so it cannot generate a valid encryption of the second inner | |||
| ClientHello. | ClientHello. | |||
| If the attacker could manipulate the second ClientHello, it might be | If the attacker could manipulate the second ClientHello, it might be | |||
| possible for the server to act as an oracle if it required parameters | possible for the server to act as an oracle if it required parameters | |||
| skipping to change at line 1991 ¶ | skipping to change at line 2025 ¶ | |||
| To begin, the attacker first interacts with a server to obtain a | To begin, the attacker first interacts with a server to obtain a | |||
| resumption ticket for a given test domain, such as "example.com". | resumption ticket for a given test domain, such as "example.com". | |||
| Later, upon receipt of a ClientHelloOuter, it modifies it such that | Later, upon receipt of a ClientHelloOuter, it modifies it such that | |||
| the server will process the resumption ticket with ClientHelloInner. | the server will process the resumption ticket with ClientHelloInner. | |||
| If the server only accepts resumption PSKs that match the server | If the server only accepts resumption PSKs that match the server | |||
| name, it will fail the PSK binder check with an alert when | name, it will fail the PSK binder check with an alert when | |||
| ClientHelloInner is for "example.com" but silently ignore the PSK and | ClientHelloInner is for "example.com" but silently ignore the PSK and | |||
| continue when ClientHelloInner is for any other name. This | continue when ClientHelloInner is for any other name. This | |||
| introduces an oracle for testing encrypted SNI values. | introduces an oracle for testing encrypted SNI values. | |||
| ~~ Client Attacker Server | Client Attacker Server | |||
| handshake and ticket | handshake and ticket | |||
| for "example.com" | for "example.com" | |||
| <--------> | <--------> | |||
| ClientHello | ClientHello | |||
| + key_share | + key_share | |||
| + ech | + ech | |||
| + ech_outer_extensions(pre_shared_key) | + ech_outer_extensions(pre_shared_key) | |||
| + pre_shared_key | + pre_shared_key | |||
| --------> | --------> | |||
| (intercept) | (intercept) | |||
| ClientHello | ClientHello | |||
| + key_share | + key_share | |||
| + ech | + ech | |||
| + ech_outer_extensions(pre_shared_key) | + ech_outer_extensions(pre_shared_key) | |||
| + pre_shared_key' | + pre_shared_key' | |||
| --------> | --------> | |||
| Alert | Alert | |||
| -or- | -or- | |||
| ServerHello | ServerHello | |||
| ... | ... | |||
| Finished | Finished | |||
| <-------- ~~ | <-------- | |||
| Figure 5: Message Flow for Malleable ClientHello | Figure 5: Message Flow for Malleable ClientHello | |||
| This attack may be generalized to any parameter which the server | This attack may be generalized to any parameter which the server | |||
| varies by server name, such as ALPN preferences. | varies by server name, such as ALPN preferences. | |||
| ECH mitigates this attack by only negotiating TLS parameters from | ECH mitigates this attack by only negotiating TLS parameters from | |||
| ClientHelloInner and authenticating all inputs to the | ClientHelloInner and authenticating all inputs to the | |||
| ClientHelloInner (EncodedClientHelloInner and ClientHelloOuter) with | ClientHelloInner (EncodedClientHelloInner and ClientHelloOuter) with | |||
| the HPKE AEAD. See Section 5.2. The decompression process in | the HPKE AEAD. See Section 5.2. The decompression process in | |||
| End of changes. 39 change blocks. | ||||
| 130 lines changed or deleted | 164 lines changed or added | |||
This html diff was produced by rfcdiff 1.48. | ||||