Based on Nekogram. Key additions: - Rebrand to FoxiGram (app name, APK name, applicationId com.foxigram.app) - Embedded Xray (VLESS+Reality) proxy client via JNI libxray.so - Bundled hidden one-tap proxies (LTE + WiFi), read-only in UI - Auto-restore proxy on restart, rebind to active network (LTE/WiFi) - Server credentials externalized to git-ignored XrayServers.java (+ template) - libxray Go source included; compiled .so, keystore, google-services.json ignored
2066 lines
57 KiB
Go
2066 lines
57 KiB
Go
// Copyright 2025 The BoringSSL Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package runner
|
|
|
|
import "strconv"
|
|
|
|
func addTLS13RecordTests() {
|
|
for _, protocol := range []protocol{tls, dtls} {
|
|
testCases = append(testCases, testCase{
|
|
protocol: protocol,
|
|
name: "TLS13-RecordPadding-" + protocol.String(),
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
RecordPadding: 10,
|
|
},
|
|
},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
protocol: protocol,
|
|
name: "TLS13-EmptyRecords-" + protocol.String(),
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
OmitRecordContents: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
protocol: protocol,
|
|
name: "TLS13-OnlyPadding-" + protocol.String(),
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
OmitRecordContents: true,
|
|
RecordPadding: 10,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
|
|
})
|
|
|
|
if protocol == tls {
|
|
testCases = append(testCases, testCase{
|
|
protocol: protocol,
|
|
name: "TLS13-WrongOuterRecord-" + protocol.String(),
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
OuterRecordType: recordTypeHandshake,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":INVALID_OUTER_RECORD_TYPE:",
|
|
})
|
|
}
|
|
}
|
|
}
|
|
|
|
func addTLS13HandshakeTests() {
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "NegotiatePSKResumption-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
NegotiatePSKResumption: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
shouldFail: true,
|
|
expectedError: ":MISSING_KEY_SHARE:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "MissingKeyShare-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
MissingKeyShare: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":MISSING_KEY_SHARE:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "MissingKeyShare-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
MissingKeyShare: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":MISSING_KEY_SHARE:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "DuplicateKeyShares-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
DuplicateKeyShares: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":DUPLICATE_KEY_SHARE:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SkipEarlyData-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendFakeEarlyDataLength: 4,
|
|
},
|
|
},
|
|
})
|
|
|
|
// Test that enabling TLS 1.3 does not interfere with TLS 1.2 session ID
|
|
// resumption.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "ResumeTLS12SessionID-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS12,
|
|
SessionTicketsDisabled: true,
|
|
},
|
|
flags: []string{"-max-version", strconv.Itoa(VersionTLS13)},
|
|
resumeSession: true,
|
|
})
|
|
|
|
// Test that the client correctly handles a TLS 1.3 ServerHello which echoes
|
|
// a TLS 1.2 session ID.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "TLS12SessionID-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS12,
|
|
SessionTicketsDisabled: true,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeSession: true,
|
|
expectResumeRejected: true,
|
|
})
|
|
|
|
// Test that the server correctly echoes back session IDs of
|
|
// various lengths. The first test additionally asserts that
|
|
// BoringSSL always sends the ChangeCipherSpec messages for
|
|
// compatibility mode, rather than negotiating it based on the
|
|
// ClientHello.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EmptySessionID-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendClientHelloSessionID: []byte{},
|
|
},
|
|
},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "Server-ShortSessionID-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendClientHelloSessionID: make([]byte, 16),
|
|
},
|
|
},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "Server-FullSessionID-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendClientHelloSessionID: make([]byte, 32),
|
|
},
|
|
},
|
|
})
|
|
|
|
// The server should reject ClientHellos whose session IDs are too long.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "Server-TooLongSessionID-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendClientHelloSessionID: make([]byte, 33),
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":CLIENTHELLO_PARSE_FAILED:",
|
|
expectedLocalError: "remote error: error decoding message",
|
|
})
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "Server-TooLongSessionID-TLS12",
|
|
config: Config{
|
|
MaxVersion: VersionTLS12,
|
|
Bugs: ProtocolBugs{
|
|
SendClientHelloSessionID: make([]byte, 33),
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":CLIENTHELLO_PARSE_FAILED:",
|
|
expectedLocalError: "remote error: error decoding message",
|
|
})
|
|
|
|
// Test that the client correctly accepts or rejects short session IDs from
|
|
// the server. Our tests use 32 bytes by default, so the boundary condition
|
|
// is already covered.
|
|
testCases = append(testCases, testCase{
|
|
name: "Client-ShortSessionID",
|
|
config: Config{
|
|
MaxVersion: VersionTLS12,
|
|
SessionTicketsDisabled: true,
|
|
Bugs: ProtocolBugs{
|
|
NewSessionIDLength: 1,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
})
|
|
testCases = append(testCases, testCase{
|
|
name: "Client-TooLongSessionID",
|
|
config: Config{
|
|
MaxVersion: VersionTLS12,
|
|
SessionTicketsDisabled: true,
|
|
Bugs: ProtocolBugs{
|
|
NewSessionIDLength: 33,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":DECODE_ERROR:",
|
|
expectedLocalError: "remote error: error decoding message",
|
|
})
|
|
|
|
// Test that the client sends a fake session ID in TLS 1.3. We cover both
|
|
// normal and resumption handshakes to capture interactions with the
|
|
// session resumption path.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "TLS13SessionID-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
ExpectClientHelloSessionID: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
})
|
|
|
|
// Test that the client omits the fake session ID when the max version is TLS 1.2 and below.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "TLS12NoSessionID-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
ExpectNoSessionID: true,
|
|
},
|
|
},
|
|
flags: []string{"-max-version", strconv.Itoa(VersionTLS12)},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
flags: []string{
|
|
"-on-initial-expect-early-data-reason", "no_session_offered",
|
|
"-on-resume-expect-early-data-reason", "accept",
|
|
},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-Reject-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
AlwaysRejectEarlyData: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-on-retry-expect-early-data-reason", "peer_declined",
|
|
},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyData-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
},
|
|
messageCount: 2,
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
flags: []string{
|
|
"-on-initial-expect-early-data-reason", "no_session_offered",
|
|
"-on-resume-expect-early-data-reason", "accept",
|
|
},
|
|
})
|
|
|
|
// The above tests the most recent ticket. Additionally test that 0-RTT
|
|
// works on the first ticket issued by the server.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyData-FirstTicket-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
UseFirstSessionTicket: true,
|
|
},
|
|
},
|
|
messageCount: 2,
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
flags: []string{
|
|
"-on-resume-expect-early-data-reason", "accept",
|
|
},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SkipEarlyData-OmitEarlyDataExtension-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendFakeEarlyDataLength: 4,
|
|
OmitEarlyDataExtension: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SkipEarlyData-OmitEarlyDataExtension-HelloRetryRequest-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// Require a HelloRetryRequest for every curve.
|
|
DefaultCurves: []CurveID{},
|
|
Bugs: ProtocolBugs{
|
|
SendFakeEarlyDataLength: 4,
|
|
OmitEarlyDataExtension: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_RECORD:",
|
|
expectedLocalError: "remote error: unexpected message",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SkipEarlyData-TooMuchData-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendFakeEarlyDataLength: 16384 + 1,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":TOO_MUCH_SKIPPED_EARLY_DATA:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SkipEarlyData-Interleaved-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendFakeEarlyDataLength: 4,
|
|
InterleaveEarlyData: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SkipEarlyData-EarlyDataInTLS12-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendFakeEarlyDataLength: 4,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_RECORD:",
|
|
flags: []string{"-max-version", strconv.Itoa(VersionTLS12)},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SkipEarlyData-HRR-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendFakeEarlyDataLength: 4,
|
|
},
|
|
DefaultCurves: []CurveID{},
|
|
},
|
|
// Though the session is not resumed and we send HelloRetryRequest,
|
|
// early data being disabled takes priority as the reject reason.
|
|
flags: []string{"-expect-early-data-reason", "disabled"},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SkipEarlyData-HRR-Interleaved-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendFakeEarlyDataLength: 4,
|
|
InterleaveEarlyData: true,
|
|
},
|
|
DefaultCurves: []CurveID{},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_RECORD:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SkipEarlyData-HRR-TooMuchData-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendFakeEarlyDataLength: 16384 + 1,
|
|
},
|
|
DefaultCurves: []CurveID{},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":TOO_MUCH_SKIPPED_EARLY_DATA:",
|
|
})
|
|
|
|
// Test that skipping early data looking for cleartext correctly
|
|
// processes an alert record.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SkipEarlyData-HRR-FatalAlert-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendEarlyAlert: true,
|
|
SendFakeEarlyDataLength: 4,
|
|
},
|
|
DefaultCurves: []CurveID{},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":SSLV3_ALERT_HANDSHAKE_FAILURE:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SkipEarlyData-SecondClientHelloEarlyData-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendEarlyDataOnSecondClientHello: true,
|
|
},
|
|
DefaultCurves: []CurveID{},
|
|
},
|
|
shouldFail: true,
|
|
expectedLocalError: "remote error: bad record MAC",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EmptyEncryptedExtensions-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
EmptyEncryptedExtensions: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedLocalError: "remote error: error decoding message",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EncryptedExtensionsWithKeyShare-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
EncryptedExtensionsWithKeyShare: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedLocalError: "remote error: unsupported extension",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SendHelloRetryRequest-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// Require a HelloRetryRequest for every curve.
|
|
DefaultCurves: []CurveID{},
|
|
CurvePreferences: []CurveID{CurveX25519},
|
|
},
|
|
expectations: connectionExpectations{
|
|
curveID: CurveX25519,
|
|
},
|
|
flags: []string{"-expect-hrr"},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SendHelloRetryRequest-2-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
DefaultCurves: []CurveID{CurveP384},
|
|
CurvePreferences: []CurveID{CurveX25519, CurveP384},
|
|
},
|
|
// Although the ClientHello did not predict our preferred curve,
|
|
// we always select it whether it is predicted or not.
|
|
expectations: connectionExpectations{
|
|
curveID: CurveX25519,
|
|
},
|
|
flags: []string{"-expect-hrr"},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "UnknownCurve-HelloRetryRequest-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// P-384 requires HelloRetryRequest in BoringSSL.
|
|
CurvePreferences: []CurveID{CurveP384},
|
|
Bugs: ProtocolBugs{
|
|
SendHelloRetryRequestCurve: bogusCurve,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":WRONG_CURVE:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "HelloRetryRequest-CipherChange-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// P-384 requires HelloRetryRequest in BoringSSL.
|
|
CurvePreferences: []CurveID{CurveP384},
|
|
Bugs: ProtocolBugs{
|
|
SendCipherSuite: TLS_AES_128_GCM_SHA256,
|
|
SendHelloRetryRequestCipherSuite: TLS_CHACHA20_POLY1305_SHA256,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":WRONG_CIPHER_RETURNED:",
|
|
})
|
|
|
|
// Test that the client does not offer a PSK in the second ClientHello if the
|
|
// HelloRetryRequest is incompatible with it.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "HelloRetryRequest-NonResumableCipher-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
CipherSuites: []uint16{
|
|
TLS_AES_128_GCM_SHA256,
|
|
},
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
// P-384 requires HelloRetryRequest in BoringSSL.
|
|
CurvePreferences: []CurveID{CurveP384},
|
|
Bugs: ProtocolBugs{
|
|
ExpectNoTLS13PSKAfterHRR: true,
|
|
},
|
|
CipherSuites: []uint16{
|
|
TLS_AES_256_GCM_SHA384,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
expectResumeRejected: true,
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "DisabledCurve-HelloRetryRequest-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
CurvePreferences: []CurveID{CurveP256},
|
|
Bugs: ProtocolBugs{
|
|
IgnorePeerCurvePreferences: true,
|
|
},
|
|
},
|
|
flags: []string{"-curves", strconv.Itoa(int(CurveP384))},
|
|
shouldFail: true,
|
|
expectedError: ":WRONG_CURVE:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "UnnecessaryHelloRetryRequest-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
CurvePreferences: []CurveID{CurveX25519},
|
|
Bugs: ProtocolBugs{
|
|
SendHelloRetryRequestCurve: CurveX25519,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":WRONG_CURVE:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "SecondHelloRetryRequest-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// P-384 requires HelloRetryRequest in BoringSSL.
|
|
CurvePreferences: []CurveID{CurveP384},
|
|
Bugs: ProtocolBugs{
|
|
SecondHelloRetryRequest: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_MESSAGE:",
|
|
expectedLocalError: "remote error: unexpected message",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "HelloRetryRequest-Empty-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
AlwaysSendHelloRetryRequest: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":EMPTY_HELLO_RETRY_REQUEST:",
|
|
expectedLocalError: "remote error: illegal parameter",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "HelloRetryRequest-DuplicateCurve-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// P-384 requires a HelloRetryRequest against BoringSSL's default
|
|
// configuration. Assert this ExpectMissingKeyShare.
|
|
CurvePreferences: []CurveID{CurveP384},
|
|
Bugs: ProtocolBugs{
|
|
ExpectMissingKeyShare: true,
|
|
DuplicateHelloRetryRequestExtensions: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":DUPLICATE_EXTENSION:",
|
|
expectedLocalError: "remote error: illegal parameter",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "HelloRetryRequest-Cookie-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendHelloRetryRequestCookie: []byte("cookie"),
|
|
},
|
|
},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "HelloRetryRequest-DuplicateCookie-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendHelloRetryRequestCookie: []byte("cookie"),
|
|
DuplicateHelloRetryRequestExtensions: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":DUPLICATE_EXTENSION:",
|
|
expectedLocalError: "remote error: illegal parameter",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "HelloRetryRequest-EmptyCookie-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendHelloRetryRequestCookie: []byte{},
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":DECODE_ERROR:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "HelloRetryRequest-Cookie-Curve-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// P-384 requires HelloRetryRequest in BoringSSL.
|
|
CurvePreferences: []CurveID{CurveP384},
|
|
Bugs: ProtocolBugs{
|
|
SendHelloRetryRequestCookie: []byte("cookie"),
|
|
ExpectMissingKeyShare: true,
|
|
},
|
|
},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "HelloRetryRequest-Unknown-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
CustomHelloRetryRequestExtension: "extension",
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_EXTENSION:",
|
|
expectedLocalError: "remote error: unsupported extension",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SecondClientHelloMissingKeyShare-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
DefaultCurves: []CurveID{},
|
|
Bugs: ProtocolBugs{
|
|
SecondClientHelloMissingKeyShare: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":MISSING_KEY_SHARE:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SecondClientHelloWrongCurve-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
DefaultCurves: []CurveID{},
|
|
Bugs: ProtocolBugs{
|
|
MisinterpretHelloRetryRequestCurve: CurveP521,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":WRONG_CURVE:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "HelloRetryRequestVersionMismatch-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// P-384 requires HelloRetryRequest in BoringSSL.
|
|
CurvePreferences: []CurveID{CurveP384},
|
|
Bugs: ProtocolBugs{
|
|
SendServerHelloVersion: 0x0305,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":DECODE_ERROR:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "HelloRetryRequestCurveMismatch-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// P-384 requires HelloRetryRequest in BoringSSL.
|
|
CurvePreferences: []CurveID{CurveP384},
|
|
Bugs: ProtocolBugs{
|
|
// Send P-384 (correct) in the HelloRetryRequest.
|
|
SendHelloRetryRequestCurve: CurveP384,
|
|
// But send P-256 in the ServerHello.
|
|
SendCurve: CurveP256,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":WRONG_CURVE:",
|
|
})
|
|
|
|
// Test the server selecting a curve that requires a HelloRetryRequest
|
|
// without sending it.
|
|
testCases = append(testCases, testCase{
|
|
name: "SkipHelloRetryRequest-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// P-384 requires HelloRetryRequest in BoringSSL.
|
|
CurvePreferences: []CurveID{CurveP384},
|
|
Bugs: ProtocolBugs{
|
|
SkipHelloRetryRequest: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":WRONG_CURVE:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "SecondServerHelloNoVersion-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// P-384 requires HelloRetryRequest in BoringSSL.
|
|
CurvePreferences: []CurveID{CurveP384},
|
|
Bugs: ProtocolBugs{
|
|
OmitServerSupportedVersionExtension: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":SECOND_SERVERHELLO_VERSION_MISMATCH:",
|
|
})
|
|
testCases = append(testCases, testCase{
|
|
name: "SecondServerHelloWrongVersion-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// P-384 requires HelloRetryRequest in BoringSSL.
|
|
CurvePreferences: []CurveID{CurveP384},
|
|
Bugs: ProtocolBugs{
|
|
SendServerSupportedVersionExtension: 0x1234,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":SECOND_SERVERHELLO_VERSION_MISMATCH:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "RequestContextInHandshake-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
ClientAuth: RequireAnyClientCert,
|
|
Bugs: ProtocolBugs{
|
|
SendRequestContext: []byte("request context"),
|
|
},
|
|
},
|
|
shimCertificate: &rsaCertificate,
|
|
shouldFail: true,
|
|
expectedError: ":DECODE_ERROR:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "UnknownExtensionInCertificateRequest-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
ClientAuth: RequireAnyClientCert,
|
|
Bugs: ProtocolBugs{
|
|
SendCustomCertificateRequest: 0x1212,
|
|
},
|
|
},
|
|
shimCertificate: &rsaCertificate,
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "MissingSignatureAlgorithmsInCertificateRequest-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
ClientAuth: RequireAnyClientCert,
|
|
Bugs: ProtocolBugs{
|
|
OmitCertificateRequestAlgorithms: true,
|
|
},
|
|
},
|
|
shimCertificate: &rsaCertificate,
|
|
shouldFail: true,
|
|
expectedError: ":DECODE_ERROR:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "TrailingKeyShareData-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
TrailingKeyShareData: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":DECODE_ERROR:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "AlwaysSelectPSKIdentity-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
AlwaysSelectPSKIdentity: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_EXTENSION:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "InvalidPSKIdentity-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SelectPSKIdentityOnResume: 1,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
shouldFail: true,
|
|
expectedError: ":PSK_IDENTITY_NOT_FOUND:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "ExtraPSKIdentity-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
ExtraPSKIdentity: true,
|
|
SendExtraPSKBinder: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
})
|
|
|
|
// Test that unknown NewSessionTicket extensions are tolerated.
|
|
testCases = append(testCases, testCase{
|
|
name: "CustomTicketExtension-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
CustomTicketExtension: "1234",
|
|
},
|
|
},
|
|
})
|
|
|
|
// Test the client handles 0-RTT being rejected by a full handshake
|
|
// and correctly reports a certificate change.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-RejectTicket-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Credential: &rsaCertificate,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
Credential: &ecdsaP256Certificate,
|
|
SessionTicketsDisabled: true,
|
|
},
|
|
resumeSession: true,
|
|
expectResumeRejected: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-on-retry-expect-early-data-reason", "session_not_resumed",
|
|
// Test the peer certificate is reported correctly in each of the
|
|
// three logical connections.
|
|
"-on-initial-expect-peer-cert-file", rsaCertificate.ChainPath,
|
|
"-on-resume-expect-peer-cert-file", rsaCertificate.ChainPath,
|
|
"-on-retry-expect-peer-cert-file", ecdsaP256Certificate.ChainPath,
|
|
// Session tickets are disabled, so the runner will not send a ticket.
|
|
"-on-retry-expect-no-session",
|
|
},
|
|
})
|
|
|
|
// Test the server rejects 0-RTT if it does not recognize the ticket.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyData-RejectTicket-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
// Corrupt the ticket.
|
|
FilterTicket: func(in []byte) ([]byte, error) {
|
|
in[len(in)-1] ^= 1
|
|
return in, nil
|
|
},
|
|
},
|
|
},
|
|
messageCount: 2,
|
|
resumeSession: true,
|
|
expectResumeRejected: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-on-resume-expect-early-data-reason", "session_not_resumed",
|
|
},
|
|
})
|
|
|
|
// Test the client handles 0-RTT being rejected via a HelloRetryRequest.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-HRR-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendHelloRetryRequestCookie: []byte{1, 2, 3, 4},
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-on-retry-expect-early-data-reason", "hello_retry_request",
|
|
},
|
|
})
|
|
|
|
// Test the server rejects 0-RTT if it needs to send a HelloRetryRequest.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyData-HRR-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
// Require a HelloRetryRequest for every curve.
|
|
DefaultCurves: []CurveID{},
|
|
},
|
|
messageCount: 2,
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-on-resume-expect-early-data-reason", "hello_retry_request",
|
|
},
|
|
})
|
|
|
|
// Test the client handles a 0-RTT reject from both ticket rejection and
|
|
// HelloRetryRequest.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-HRR-RejectTicket-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Credential: &rsaCertificate,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
Credential: &ecdsaP256Certificate,
|
|
SessionTicketsDisabled: true,
|
|
Bugs: ProtocolBugs{
|
|
SendHelloRetryRequestCookie: []byte{1, 2, 3, 4},
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
expectResumeRejected: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
// The client sees HelloRetryRequest before the resumption result,
|
|
// though neither value is inherently preferable.
|
|
"-on-retry-expect-early-data-reason", "hello_retry_request",
|
|
// Test the peer certificate is reported correctly in each of the
|
|
// three logical connections.
|
|
"-on-initial-expect-peer-cert-file", rsaCertificate.ChainPath,
|
|
"-on-resume-expect-peer-cert-file", rsaCertificate.ChainPath,
|
|
"-on-retry-expect-peer-cert-file", ecdsaP256Certificate.ChainPath,
|
|
// Session tickets are disabled, so the runner will not send a ticket.
|
|
"-on-retry-expect-no-session",
|
|
},
|
|
})
|
|
|
|
// Test the server rejects 0-RTT if it needs to send a HelloRetryRequest.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyData-HRR-RejectTicket-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MinVersion: VersionTLS13,
|
|
// Require a HelloRetryRequest for every curve.
|
|
DefaultCurves: []CurveID{},
|
|
Bugs: ProtocolBugs{
|
|
// Corrupt the ticket.
|
|
FilterTicket: func(in []byte) ([]byte, error) {
|
|
in[len(in)-1] ^= 1
|
|
return in, nil
|
|
},
|
|
},
|
|
},
|
|
messageCount: 2,
|
|
resumeSession: true,
|
|
expectResumeRejected: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
// The server sees the missed resumption before HelloRetryRequest,
|
|
// though neither value is inherently preferable.
|
|
"-on-resume-expect-early-data-reason", "session_not_resumed",
|
|
},
|
|
})
|
|
|
|
// The client must check the server does not send the early_data
|
|
// extension while rejecting the session.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyDataWithoutResume-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MaxEarlyDataSize: 16384,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
SessionTicketsDisabled: true,
|
|
Bugs: ProtocolBugs{
|
|
SendEarlyDataExtension: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_EXTENSION:",
|
|
})
|
|
|
|
// The client must fail with a dedicated error code if the server
|
|
// responds with TLS 1.2 when offering 0-RTT.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyDataVersionDowngrade-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS12,
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
shouldFail: true,
|
|
expectedError: ":WRONG_VERSION_ON_EARLY_DATA:",
|
|
})
|
|
|
|
// Same as above, but the server also sends a warning alert before the
|
|
// ServerHello. Although the shim predicts TLS 1.3 for 0-RTT, it should
|
|
// still interpret data before ServerHello in a TLS-1.2-compatible way.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyDataVersionDowngrade-Client-TLS13-WarningAlert",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS12,
|
|
Bugs: ProtocolBugs{
|
|
SendSNIWarningAlert: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
shouldFail: true,
|
|
expectedError: ":WRONG_VERSION_ON_EARLY_DATA:",
|
|
})
|
|
|
|
// Test that the client rejects an (unsolicited) early_data extension if
|
|
// the server sent an HRR.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "ServerAcceptsEarlyDataOnHRR-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendHelloRetryRequestCookie: []byte{1, 2, 3, 4},
|
|
SendEarlyDataExtension: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
// The client will first process an early data reject from the HRR.
|
|
expectEarlyDataRejected: true,
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_EXTENSION:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "SkipChangeCipherSpec-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SkipChangeCipherSpec: true,
|
|
},
|
|
},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "SkipChangeCipherSpec-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SkipChangeCipherSpec: true,
|
|
},
|
|
},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "TooManyChangeCipherSpec-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendExtraChangeCipherSpec: 33,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "TooManyChangeCipherSpec-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendExtraChangeCipherSpec: 33,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
name: "SendPostHandshakeChangeCipherSpec-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendPostHandshakeChangeCipherSpec: true,
|
|
},
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_RECORD:",
|
|
expectedLocalError: "remote error: unexpected message",
|
|
})
|
|
|
|
fooString := "foo"
|
|
barString := "bar"
|
|
|
|
// Test that the client reports the correct ALPN after a 0-RTT reject
|
|
// that changed it.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-ALPNMismatch-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
ALPNProtocol: &fooString,
|
|
},
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
ALPNProtocol: &barString,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-advertise-alpn", "\x03foo\x03bar",
|
|
// The client does not learn ALPN was the cause.
|
|
"-on-retry-expect-early-data-reason", "peer_declined",
|
|
// In the 0-RTT state, we surface the predicted ALPN. After
|
|
// processing the reject, we surface the real one.
|
|
"-on-initial-expect-alpn", "foo",
|
|
"-on-resume-expect-alpn", "foo",
|
|
"-on-retry-expect-alpn", "bar",
|
|
},
|
|
})
|
|
|
|
// Test that the client reports the correct ALPN after a 0-RTT reject if
|
|
// ALPN was omitted from the first connection.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-ALPNOmitted1-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
NextProtos: []string{"foo"},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-advertise-alpn", "\x03foo\x03bar",
|
|
// The client does not learn ALPN was the cause.
|
|
"-on-retry-expect-early-data-reason", "peer_declined",
|
|
// In the 0-RTT state, we surface the predicted ALPN. After
|
|
// processing the reject, we surface the real one.
|
|
"-on-initial-expect-alpn", "",
|
|
"-on-resume-expect-alpn", "",
|
|
"-on-retry-expect-alpn", "foo",
|
|
},
|
|
})
|
|
|
|
// Test that the client reports the correct ALPN after a 0-RTT reject if
|
|
// ALPN was omitted from the second connection.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-ALPNOmitted2-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
NextProtos: []string{"foo"},
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-advertise-alpn", "\x03foo\x03bar",
|
|
// The client does not learn ALPN was the cause.
|
|
"-on-retry-expect-early-data-reason", "peer_declined",
|
|
// In the 0-RTT state, we surface the predicted ALPN. After
|
|
// processing the reject, we surface the real one.
|
|
"-on-initial-expect-alpn", "foo",
|
|
"-on-resume-expect-alpn", "foo",
|
|
"-on-retry-expect-alpn", "",
|
|
},
|
|
})
|
|
|
|
// Test that the client enforces ALPN match on 0-RTT accept.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-BadALPNMismatch-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
ALPNProtocol: &fooString,
|
|
},
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
AlwaysAcceptEarlyData: true,
|
|
ALPNProtocol: &barString,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
flags: []string{
|
|
"-advertise-alpn", "\x03foo\x03bar",
|
|
"-on-initial-expect-alpn", "foo",
|
|
"-on-resume-expect-alpn", "foo",
|
|
"-on-retry-expect-alpn", "bar",
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":ALPN_MISMATCH_ON_EARLY_DATA:",
|
|
expectedLocalError: "remote error: illegal parameter",
|
|
})
|
|
|
|
// Test that the client does not offer early data if it is incompatible
|
|
// with ALPN preferences.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-ALPNPreferenceChanged-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
MaxEarlyDataSize: 16384,
|
|
NextProtos: []string{"foo", "bar"},
|
|
},
|
|
resumeSession: true,
|
|
flags: []string{
|
|
"-enable-early-data",
|
|
"-expect-ticket-supports-early-data",
|
|
"-expect-no-offer-early-data",
|
|
// Offer different ALPN values in the initial and resumption.
|
|
"-on-initial-advertise-alpn", "\x03foo",
|
|
"-on-initial-expect-alpn", "foo",
|
|
"-on-resume-advertise-alpn", "\x03bar",
|
|
"-on-resume-expect-alpn", "bar",
|
|
// The ALPN mismatch comes from the client, so it reports it as the
|
|
// reason.
|
|
"-on-resume-expect-early-data-reason", "alpn_mismatch",
|
|
},
|
|
})
|
|
|
|
// Test that the client does not offer 0-RTT to servers which never
|
|
// advertise it.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-NonZeroRTTSession-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeSession: true,
|
|
flags: []string{
|
|
"-enable-early-data",
|
|
"-on-resume-expect-no-offer-early-data",
|
|
// The client declines to offer 0-RTT because of the session.
|
|
"-on-resume-expect-early-data-reason", "unsupported_for_session",
|
|
},
|
|
})
|
|
|
|
// Test that the server correctly rejects 0-RTT when the previous
|
|
// session did not allow early data on resumption.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyData-NonZeroRTTSession-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendEarlyData: [][]byte{{1, 2, 3, 4}},
|
|
ExpectEarlyDataAccepted: false,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
// This test configures early data manually instead of the earlyData
|
|
// option, to customize the -enable-early-data flag.
|
|
flags: []string{
|
|
"-on-resume-enable-early-data",
|
|
"-expect-reject-early-data",
|
|
// The server rejects 0-RTT because of the session.
|
|
"-on-resume-expect-early-data-reason", "unsupported_for_session",
|
|
},
|
|
})
|
|
|
|
// Test that we reject early data where ALPN is omitted from the first
|
|
// connection, but negotiated in the second.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyData-ALPNOmitted1-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
NextProtos: []string{},
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
NextProtos: []string{"foo"},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-on-initial-select-alpn", "",
|
|
"-on-resume-select-alpn", "foo",
|
|
"-on-resume-expect-early-data-reason", "alpn_mismatch",
|
|
},
|
|
})
|
|
|
|
// Test that we reject early data where ALPN is omitted from the second
|
|
// connection, but negotiated in the first.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyData-ALPNOmitted2-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
NextProtos: []string{"foo"},
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
NextProtos: []string{},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-on-initial-select-alpn", "foo",
|
|
"-on-resume-select-alpn", "",
|
|
"-on-resume-expect-early-data-reason", "alpn_mismatch",
|
|
},
|
|
})
|
|
|
|
// Test that we reject early data with mismatched ALPN.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyData-ALPNMismatch-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
NextProtos: []string{"foo"},
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
NextProtos: []string{"bar"},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-on-initial-select-alpn", "foo",
|
|
"-on-resume-select-alpn", "bar",
|
|
"-on-resume-expect-early-data-reason", "alpn_mismatch",
|
|
},
|
|
})
|
|
|
|
// Test that the client offering 0-RTT and Channel ID forbids the server
|
|
// from accepting both.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyDataChannelID-AcceptBoth-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
RequestChannelID: true,
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectations: connectionExpectations{
|
|
channelID: true,
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_EXTENSION_ON_EARLY_DATA:",
|
|
expectedLocalError: "remote error: illegal parameter",
|
|
flags: []string{
|
|
"-send-channel-id", channelIDKeyPath,
|
|
},
|
|
})
|
|
|
|
// Test that the client offering Channel ID and 0-RTT allows the server
|
|
// to decline 0-RTT.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyDataChannelID-AcceptChannelID-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
RequestChannelID: true,
|
|
Bugs: ProtocolBugs{
|
|
AlwaysRejectEarlyData: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
expectations: connectionExpectations{
|
|
channelID: true,
|
|
},
|
|
flags: []string{
|
|
"-send-channel-id", channelIDKeyPath,
|
|
// The client never learns the reason was Channel ID.
|
|
"-on-retry-expect-early-data-reason", "peer_declined",
|
|
},
|
|
})
|
|
|
|
// Test that the client offering Channel ID and 0-RTT allows the server
|
|
// to decline Channel ID.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyDataChannelID-AcceptEarlyData-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
flags: []string{
|
|
"-send-channel-id", channelIDKeyPath,
|
|
},
|
|
})
|
|
|
|
// Test that the server supporting Channel ID and 0-RTT declines 0-RTT
|
|
// if it would negotiate Channel ID.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyDataChannelID-OfferBoth-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
ChannelID: &channelIDKey,
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
expectations: connectionExpectations{
|
|
channelID: true,
|
|
},
|
|
flags: []string{
|
|
"-expect-channel-id",
|
|
base64FlagValue(channelIDBytes),
|
|
"-on-resume-expect-early-data-reason", "channel_id",
|
|
},
|
|
})
|
|
|
|
// Test that the server supporting Channel ID and 0-RTT accepts 0-RTT
|
|
// if not offered Channel ID.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyDataChannelID-OfferEarlyData-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
expectations: connectionExpectations{
|
|
channelID: false,
|
|
},
|
|
flags: []string{
|
|
"-enable-channel-id",
|
|
"-on-resume-expect-early-data-reason", "accept",
|
|
},
|
|
})
|
|
|
|
// Test that the server errors on 0-RTT streams without EndOfEarlyData.
|
|
// The subsequent records should fail to decrypt.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyData-SkipEndOfEarlyData-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SkipEndOfEarlyData: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
shouldFail: true,
|
|
expectedLocalError: "remote error: bad record MAC",
|
|
expectedError: ":BAD_DECRYPT:",
|
|
})
|
|
|
|
// Test that EndOfEarlyData is rejected in QUIC. Since we leave application
|
|
// data to the QUIC implementation, we never accept any data at all in
|
|
// the 0-RTT epoch, so the error is that the encryption level is rejected
|
|
// outright.
|
|
//
|
|
// TODO(crbug.com/381113363): Test this for DTLS 1.3 as well.
|
|
testCases = append(testCases, testCase{
|
|
protocol: quic,
|
|
testType: serverTest,
|
|
name: "EarlyData-UnexpectedEndOfEarlyData-QUIC",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendEndOfEarlyDataInQUICAndDTLS: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
shouldFail: true,
|
|
expectedError: ":WRONG_ENCRYPTION_LEVEL_RECEIVED:",
|
|
})
|
|
|
|
// Test that the server errors on 0-RTT streams with a stray handshake
|
|
// message in them.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyData-UnexpectedHandshake-Server-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
SendStrayEarlyHandshake: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_MESSAGE:",
|
|
expectedLocalError: "remote error: unexpected message",
|
|
})
|
|
|
|
// Test that the client reports TLS 1.3 as the version while sending
|
|
// early data.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-Client-VersionAPI-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
flags: []string{
|
|
"-expect-version", strconv.Itoa(VersionTLS13),
|
|
// EMS and RI are always reported as supported when we report
|
|
// TLS 1.3.
|
|
"-expect-extended-master-secret",
|
|
"-expect-secure-renegotiation",
|
|
},
|
|
})
|
|
|
|
// Test that client and server both notice handshake errors after data
|
|
// has started flowing.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-Client-BadFinished-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
BadFinished: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
shouldFail: true,
|
|
expectedError: ":DIGEST_CHECK_FAILED:",
|
|
expectedLocalError: "remote error: error decrypting message",
|
|
})
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyData-Server-BadFinished-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
BadFinished: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
shouldFail: true,
|
|
expectedError: ":DIGEST_CHECK_FAILED:",
|
|
expectedLocalError: "remote error: error decrypting message",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "Server-NonEmptyEndOfEarlyData-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
NonEmptyEndOfEarlyData: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
shouldFail: true,
|
|
expectedError: ":DECODE_ERROR:",
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "ServerSkipCertificateVerify-TLS13",
|
|
config: Config{
|
|
MinVersion: VersionTLS13,
|
|
MaxVersion: VersionTLS13,
|
|
Credential: &rsaChainCertificate,
|
|
Bugs: ProtocolBugs{
|
|
SkipCertificateVerify: true,
|
|
},
|
|
},
|
|
expectations: connectionExpectations{
|
|
peerCertificate: &rsaCertificate,
|
|
},
|
|
shimCertificate: &rsaCertificate,
|
|
flags: []string{
|
|
"-require-any-client-certificate",
|
|
},
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_MESSAGE:",
|
|
expectedLocalError: "remote error: unexpected message",
|
|
})
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "ClientSkipCertificateVerify-TLS13",
|
|
config: Config{
|
|
MinVersion: VersionTLS13,
|
|
MaxVersion: VersionTLS13,
|
|
Credential: &rsaChainCertificate,
|
|
Bugs: ProtocolBugs{
|
|
SkipCertificateVerify: true,
|
|
},
|
|
},
|
|
expectations: connectionExpectations{
|
|
peerCertificate: &rsaCertificate,
|
|
},
|
|
shimCertificate: &rsaCertificate,
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_MESSAGE:",
|
|
expectedLocalError: "remote error: unexpected message",
|
|
})
|
|
|
|
// PSK/resumption handshakes should not accept CertificateRequest or
|
|
// Certificate messages.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "CertificateInResumption-TLS13",
|
|
config: Config{
|
|
MinVersion: VersionTLS13,
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
AlwaysSendCertificate: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_MESSAGE:",
|
|
expectedLocalError: "remote error: unexpected message",
|
|
})
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "CertificateRequestInResumption-TLS13",
|
|
config: Config{
|
|
MinVersion: VersionTLS13,
|
|
MaxVersion: VersionTLS13,
|
|
ClientAuth: RequireAnyClientCert,
|
|
Bugs: ProtocolBugs{
|
|
AlwaysSendCertificateRequest: true,
|
|
},
|
|
},
|
|
shimCertificate: &rsaCertificate,
|
|
resumeSession: true,
|
|
shouldFail: true,
|
|
expectedError: ":UNEXPECTED_MESSAGE:",
|
|
expectedLocalError: "remote error: unexpected message",
|
|
})
|
|
|
|
// If the client or server has 0-RTT enabled but disabled TLS 1.3, it should
|
|
// report a reason of protocol_version.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyDataEnabled-Client-MaxTLS12",
|
|
expectations: connectionExpectations{
|
|
version: VersionTLS12,
|
|
},
|
|
flags: []string{
|
|
"-enable-early-data",
|
|
"-max-version", strconv.Itoa(VersionTLS12),
|
|
"-expect-early-data-reason", "protocol_version",
|
|
},
|
|
})
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyDataEnabled-Server-MaxTLS12",
|
|
expectations: connectionExpectations{
|
|
version: VersionTLS12,
|
|
},
|
|
flags: []string{
|
|
"-enable-early-data",
|
|
"-max-version", strconv.Itoa(VersionTLS12),
|
|
"-expect-early-data-reason", "protocol_version",
|
|
},
|
|
})
|
|
|
|
// The server additionally reports protocol_version if it enabled TLS 1.3,
|
|
// but the peer negotiated TLS 1.2. (The corresponding situation does not
|
|
// exist on the client because negotiating TLS 1.2 with a 0-RTT ClientHello
|
|
// is a fatal error.)
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "EarlyDataEnabled-Server-NegotiateTLS12",
|
|
config: Config{
|
|
MaxVersion: VersionTLS12,
|
|
},
|
|
expectations: connectionExpectations{
|
|
version: VersionTLS12,
|
|
},
|
|
flags: []string{
|
|
"-enable-early-data",
|
|
"-expect-early-data-reason", "protocol_version",
|
|
},
|
|
})
|
|
|
|
// On 0-RTT reject, the server may end up negotiating a cipher suite with a
|
|
// different PRF hash. Test that the client handles this correctly.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-Reject0RTT-DifferentPRF-Client",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
CipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
CipherSuites: []uint16{TLS_AES_256_GCM_SHA384},
|
|
},
|
|
resumeSession: true,
|
|
expectResumeRejected: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-on-initial-expect-cipher", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
|
|
// The client initially reports the old cipher suite while sending
|
|
// early data. After processing the 0-RTT reject, it reports the
|
|
// true cipher suite.
|
|
"-on-resume-expect-cipher", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
|
|
"-on-retry-expect-cipher", strconv.Itoa(int(TLS_AES_256_GCM_SHA384)),
|
|
},
|
|
})
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-Reject0RTT-DifferentPRF-HRR-Client",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
CipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
CipherSuites: []uint16{TLS_AES_256_GCM_SHA384},
|
|
// P-384 requires a HelloRetryRequest against BoringSSL's default
|
|
// configuration. Assert this with ExpectMissingKeyShare.
|
|
CurvePreferences: []CurveID{CurveP384},
|
|
Bugs: ProtocolBugs{
|
|
ExpectMissingKeyShare: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
expectResumeRejected: true,
|
|
earlyData: true,
|
|
expectEarlyDataRejected: true,
|
|
flags: []string{
|
|
"-on-initial-expect-cipher", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
|
|
// The client initially reports the old cipher suite while sending
|
|
// early data. After processing the 0-RTT reject, it reports the
|
|
// true cipher suite.
|
|
"-on-resume-expect-cipher", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
|
|
"-on-retry-expect-cipher", strconv.Itoa(int(TLS_AES_256_GCM_SHA384)),
|
|
},
|
|
})
|
|
|
|
// Test that the client enforces cipher suite match on 0-RTT accept.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-CipherMismatch-Client-TLS13",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
CipherSuites: []uint16{TLS_AES_128_GCM_SHA256},
|
|
},
|
|
resumeConfig: &Config{
|
|
MaxVersion: VersionTLS13,
|
|
CipherSuites: []uint16{TLS_CHACHA20_POLY1305_SHA256},
|
|
Bugs: ProtocolBugs{
|
|
AlwaysAcceptEarlyData: true,
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
shouldFail: true,
|
|
expectedError: ":CIPHER_MISMATCH_ON_EARLY_DATA:",
|
|
expectedLocalError: "remote error: illegal parameter",
|
|
})
|
|
|
|
// Test that the client can write early data when it has received a partial
|
|
// ServerHello..Finished flight. See https://crbug.com/1208784. Note the
|
|
// EncryptedExtensions test assumes EncryptedExtensions and Finished are in
|
|
// separate records, i.e. that PackHandshakeFlight is disabled.
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-WriteAfterServerHello",
|
|
config: Config{
|
|
MinVersion: VersionTLS13,
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
// Write the server response before expecting early data.
|
|
ExpectEarlyData: [][]byte{},
|
|
ExpectLateEarlyData: [][]byte{[]byte(shimInitialWrite)},
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
flags: []string{
|
|
"-async",
|
|
"-on-resume-early-write-after-message",
|
|
strconv.Itoa(int(typeServerHello)),
|
|
},
|
|
})
|
|
testCases = append(testCases, testCase{
|
|
testType: clientTest,
|
|
name: "EarlyData-WriteAfterEncryptedExtensions",
|
|
config: Config{
|
|
MinVersion: VersionTLS13,
|
|
MaxVersion: VersionTLS13,
|
|
Bugs: ProtocolBugs{
|
|
// Write the server response before expecting early data.
|
|
ExpectEarlyData: [][]byte{},
|
|
ExpectLateEarlyData: [][]byte{[]byte(shimInitialWrite)},
|
|
},
|
|
},
|
|
resumeSession: true,
|
|
earlyData: true,
|
|
flags: []string{
|
|
"-async",
|
|
"-on-resume-early-write-after-message",
|
|
strconv.Itoa(int(typeEncryptedExtensions)),
|
|
},
|
|
})
|
|
}
|
|
|
|
func addTLS13CipherPreferenceTests() {
|
|
// Test that client preference is honored if the shim has AES hardware
|
|
// and ChaCha20-Poly1305 is preferred otherwise.
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "TLS13-CipherPreference-Server-ChaCha20-AES",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
CipherSuites: []uint16{
|
|
TLS_CHACHA20_POLY1305_SHA256,
|
|
TLS_AES_128_GCM_SHA256,
|
|
},
|
|
CurvePreferences: []CurveID{CurveX25519},
|
|
},
|
|
flags: []string{
|
|
"-expect-cipher-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
|
|
"-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
|
|
},
|
|
})
|
|
|
|
testCases = append(testCases, testCase{
|
|
testType: serverTest,
|
|
name: "TLS13-CipherPreference-Server-AES-ChaCha20",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
CipherSuites: []uint16{
|
|
TLS_AES_128_GCM_SHA256,
|
|
TLS_CHACHA20_POLY1305_SHA256,
|
|
},
|
|
CurvePreferences: []CurveID{CurveX25519},
|
|
},
|
|
flags: []string{
|
|
"-expect-cipher-aes", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
|
|
"-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
|
|
},
|
|
})
|
|
|
|
// Test that the client orders ChaCha20-Poly1305 and AES-GCM based on
|
|
// whether it has AES hardware.
|
|
testCases = append(testCases, testCase{
|
|
name: "TLS13-CipherPreference-Client",
|
|
config: Config{
|
|
MaxVersion: VersionTLS13,
|
|
// Use the client cipher order. (This is the default but
|
|
// is listed to be explicit.)
|
|
PreferServerCipherSuites: false,
|
|
},
|
|
flags: []string{
|
|
"-expect-cipher-aes", strconv.Itoa(int(TLS_AES_128_GCM_SHA256)),
|
|
"-expect-cipher-no-aes", strconv.Itoa(int(TLS_CHACHA20_POLY1305_SHA256)),
|
|
},
|
|
})
|
|
}
|