Fix client 0-RTT handling with ALPS.
When offering 0-RTT, the client should check that all carried-over
values are consistent with its preferences. This ensures that parameter
negotiation happens independently of 0-RTT. The ALPS version of this
check was a tad too aggressive: a session without ALPS should be treated
as always compatible.
I'll follow this with a fix to the draft spec to clarify this.
Change-Id: Ia3c2a60449c555d1d91c4e528215f8e551a90a9f
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/45104
Commit-Queue: David Benjamin <davidben@google.com>
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index 9dd6a39..5ca96109 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -2180,14 +2180,17 @@
return true;
}
- Span<const uint8_t> settings;
- bool has_alps = ssl_get_local_application_settings(
- hs, &settings, ssl->session->early_alpn);
- if (has_alps != ssl->session->has_application_settings ||
- settings != ssl->session->local_application_settings) {
- // 0-RTT carries ALPS over, so we only offer it when the value matches.
- ssl->s3->early_data_reason = ssl_early_data_alps_mismatch;
- return true;
+ // If the previous connection negotiated ALPS, only offer 0-RTT when the
+ // local are settings are consistent with what we'd offer for this
+ // connection.
+ if (ssl->session->has_application_settings) {
+ Span<const uint8_t> settings;
+ if (!ssl_get_local_application_settings(hs, &settings,
+ ssl->session->early_alpn) ||
+ settings != ssl->session->local_application_settings) {
+ ssl->s3->early_data_reason = ssl_early_data_alps_mismatch;
+ return true;
+ }
}
}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 2a58be7..04d4d3e 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -7437,35 +7437,41 @@
flags = append(flags, "-on-resume-expect-peer-application-settings", "runner")
}
- // The client should not offer early data.
- testCases = append(testCases, testCase{
- protocol: protocol,
- testType: clientTest,
- name: fmt.Sprintf("ALPS-EarlyData-Mismatch-%s-Client-%s", test.name, suffix),
- skipQUICALPNConfig: true,
- config: Config{
- MaxVersion: ver.version,
- MaxEarlyDataSize: 16384,
- NextProtos: []string{"proto"},
- ApplicationSettings: map[string][]byte{"proto": []byte("runner")},
- },
- resumeSession: true,
- flags: append([]string{
- "-enable-early-data",
- "-expect-ticket-supports-early-data",
- "-expect-no-offer-early-data",
- "-advertise-alpn", "\x05proto",
- "-expect-alpn", "proto",
- }, flags...),
- expectations: connectionExpectations{
- peerApplicationSettings: test.initialSettings,
- },
- resumeExpectations: &connectionExpectations{
- peerApplicationSettings: test.resumeSettings,
- },
- })
+ // The client should not offer early data if the session is
+ // inconsistent with the new configuration. Note that if
+ // the session did not negotiate ALPS (test.initialSettings
+ // is nil), the client always offers early data.
+ if test.initialSettings != nil {
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: clientTest,
+ name: fmt.Sprintf("ALPS-EarlyData-Mismatch-%s-Client-%s", test.name, suffix),
+ skipQUICALPNConfig: true,
+ config: Config{
+ MaxVersion: ver.version,
+ MaxEarlyDataSize: 16384,
+ NextProtos: []string{"proto"},
+ ApplicationSettings: map[string][]byte{"proto": []byte("runner")},
+ },
+ resumeSession: true,
+ flags: append([]string{
+ "-enable-early-data",
+ "-expect-ticket-supports-early-data",
+ "-expect-no-offer-early-data",
+ "-advertise-alpn", "\x05proto",
+ "-expect-alpn", "proto",
+ }, flags...),
+ expectations: connectionExpectations{
+ peerApplicationSettings: test.initialSettings,
+ },
+ resumeExpectations: &connectionExpectations{
+ peerApplicationSettings: test.resumeSettings,
+ },
+ })
+ }
- // The server should reject early data.
+ // The server should reject early data if the session is
+ // inconsistent with the new selection.
testCases = append(testCases, testCase{
protocol: protocol,
testType: serverTest,
@@ -7490,6 +7496,42 @@
},
})
}
+
+ // Test that 0-RTT continues working when the shim configures
+ // ALPS but the peer does not.
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: clientTest,
+ name: "ALPS-EarlyData-Client-ServerDecline-" + suffix,
+ skipQUICALPNConfig: true,
+ config: Config{
+ MaxVersion: ver.version,
+ NextProtos: []string{"proto"},
+ },
+ resumeSession: true,
+ earlyData: true,
+ flags: []string{
+ "-advertise-alpn", "\x05proto",
+ "-expect-alpn", "proto",
+ "-application-settings", "proto,shim",
+ },
+ })
+ testCases = append(testCases, testCase{
+ protocol: protocol,
+ testType: serverTest,
+ name: "ALPS-EarlyData-Server-ClientNoOffer-" + suffix,
+ skipQUICALPNConfig: true,
+ config: Config{
+ MaxVersion: ver.version,
+ NextProtos: []string{"proto"},
+ },
+ resumeSession: true,
+ earlyData: true,
+ flags: []string{
+ "-select-alpn", "proto",
+ "-application-settings", "proto,shim",
+ },
+ })
} else {
// Test the client rejects the ALPS extension if the server
// negotiated TLS 1.2 or below.