| // 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 ( | |
| "slices" | |
| "strconv" | |
| ) | |
| func addBasicTests() { | |
| basicTests := []testCase{ | |
| { | |
| name: "NoFallbackSCSV", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| FailIfNotFallbackSCSV: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedLocalError: "no fallback SCSV found", | |
| }, | |
| { | |
| name: "SendFallbackSCSV", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| FailIfNotFallbackSCSV: true, | |
| }, | |
| }, | |
| flags: []string{"-fallback-scsv"}, | |
| }, | |
| { | |
| name: "ClientCertificateTypes", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| ClientAuth: RequestClientCert, | |
| ClientCertificateTypes: []byte{ | |
| CertTypeDSSSign, | |
| CertTypeRSASign, | |
| CertTypeECDSASign, | |
| }, | |
| }, | |
| flags: []string{ | |
| "-expect-certificate-types", | |
| base64FlagValue([]byte{ | |
| CertTypeDSSSign, | |
| CertTypeRSASign, | |
| CertTypeECDSASign, | |
| }), | |
| }, | |
| }, | |
| { | |
| name: "CheckClientCertificateTypes", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| ClientAuth: RequestClientCert, | |
| ClientCertificateTypes: []byte{CertTypeECDSASign}, | |
| }, | |
| shimCertificate: &rsaCertificate, | |
| shouldFail: true, | |
| expectedError: ":UNKNOWN_CERTIFICATE_TYPE:", | |
| }, | |
| { | |
| name: "UnauthenticatedECDH", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, | |
| Bugs: ProtocolBugs{ | |
| UnauthenticatedECDH: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_MESSAGE:", | |
| }, | |
| { | |
| name: "SkipCertificateStatus", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Credential: rsaCertificate.WithOCSP(testOCSPResponse), | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, | |
| Bugs: ProtocolBugs{ | |
| SkipCertificateStatus: true, | |
| }, | |
| }, | |
| flags: []string{ | |
| "-enable-ocsp-stapling", | |
| // This test involves an optional message. Test the message callback | |
| // trace to ensure we do not miss or double-report any. | |
| "-expect-msg-callback", | |
| `write hs 1 | |
| read hs 2 | |
| read hs 11 | |
| read hs 12 | |
| read hs 14 | |
| write hs 16 | |
| write ccs | |
| write hs 20 | |
| read hs 4 | |
| read ccs | |
| read hs 20 | |
| read alert 1 0 | |
| `, | |
| }, | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "SkipCertificateStatus-DTLS", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Credential: rsaCertificate.WithOCSP(testOCSPResponse), | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, | |
| Bugs: ProtocolBugs{ | |
| SkipCertificateStatus: true, | |
| }, | |
| }, | |
| flags: []string{ | |
| // Exact message trace of the handshake depends on selected curves, | |
| // as MLKEM causes messages to be split due to its handshake size | |
| // and DTLS trying to respect a MTU here. | |
| // TODO(crbug.com/507830312): Eventually fix that? | |
| "-curves", strconv.Itoa(int(CurveX25519)), | |
| "-enable-ocsp-stapling", | |
| // This test involves an optional message. Test the message callback | |
| // trace to ensure we do not miss or double-report any. | |
| "-expect-msg-callback", | |
| `write hs 1 | |
| read hs 3 | |
| write hs 1 | |
| read hs 2 | |
| read hs 11 | |
| read hs 12 | |
| read hs 14 | |
| write hs 16 | |
| write ccs | |
| write hs 20 | |
| read hs 4 | |
| read ccs | |
| read hs 20 | |
| read alert 1 0 | |
| `, | |
| }, | |
| }, | |
| { | |
| name: "SkipServerKeyExchange", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, | |
| Bugs: ProtocolBugs{ | |
| SkipServerKeyExchange: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_MESSAGE:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "ServerSkipCertificateVerify", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Credential: &rsaCertificate, | |
| Bugs: ProtocolBugs{ | |
| SkipCertificateVerify: true, | |
| }, | |
| }, | |
| expectations: connectionExpectations{ | |
| peerCertificate: &rsaCertificate, | |
| }, | |
| flags: []string{ | |
| "-require-any-client-certificate", | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| expectedLocalError: "remote error: unexpected message", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "Alert", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SendSpuriousAlert: alertRecordOverflow, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", | |
| }, | |
| { | |
| protocol: dtls, | |
| testType: serverTest, | |
| name: "Alert-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SendSpuriousAlert: alertRecordOverflow, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "FragmentAlert", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| FragmentAlert: true, | |
| SendSpuriousAlert: alertRecordOverflow, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":BAD_ALERT:", | |
| }, | |
| { | |
| protocol: dtls, | |
| testType: serverTest, | |
| name: "FragmentAlert-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| FragmentAlert: true, | |
| SendSpuriousAlert: alertRecordOverflow, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":BAD_ALERT:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "DoubleAlert", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| DoubleAlert: true, | |
| SendSpuriousAlert: alertRecordOverflow, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":BAD_ALERT:", | |
| }, | |
| { | |
| protocol: dtls, | |
| testType: serverTest, | |
| name: "DoubleAlert-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| DoubleAlert: true, | |
| SendSpuriousAlert: alertRecordOverflow, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":BAD_ALERT:", | |
| }, | |
| { | |
| name: "SkipNewSessionTicket", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| SkipNewSessionTicket: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "FallbackSCSV", | |
| config: Config{ | |
| MaxVersion: VersionTLS11, | |
| Bugs: ProtocolBugs{ | |
| SendFallbackSCSV: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":INAPPROPRIATE_FALLBACK:", | |
| expectedLocalError: "remote error: inappropriate fallback", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "FallbackSCSV-VersionMatch-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| SendFallbackSCSV: true, | |
| }, | |
| }, | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "FallbackSCSV-VersionMatch-TLS12", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| SendFallbackSCSV: true, | |
| }, | |
| }, | |
| flags: []string{"-max-version", strconv.Itoa(VersionTLS12)}, | |
| }, | |
| // Regression test for CVE-2014-3511. Even when the ClientHello is | |
| // maximally fragmented, version negotiation works correctly. | |
| { | |
| testType: serverTest, | |
| name: "FragmentedClientVersion", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| MaxHandshakeRecordLength: 1, | |
| }, | |
| }, | |
| expectations: connectionExpectations{ | |
| version: VersionTLS13, | |
| }, | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "HttpGET", | |
| sendPrefix: "GET / HTTP/1.0\n", | |
| shouldFail: true, | |
| expectedError: ":HTTP_REQUEST:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "HttpPOST", | |
| sendPrefix: "POST / HTTP/1.0\n", | |
| shouldFail: true, | |
| expectedError: ":HTTP_REQUEST:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "HttpHEAD", | |
| sendPrefix: "HEAD / HTTP/1.0\n", | |
| shouldFail: true, | |
| expectedError: ":HTTP_REQUEST:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "HttpPUT", | |
| sendPrefix: "PUT / HTTP/1.0\n", | |
| shouldFail: true, | |
| expectedError: ":HTTP_REQUEST:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "HttpCONNECT", | |
| sendPrefix: "CONNECT www.google.com:443 HTTP/1.0\n", | |
| shouldFail: true, | |
| expectedError: ":HTTPS_PROXY_REQUEST:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "Garbage", | |
| sendPrefix: "blah", | |
| shouldFail: true, | |
| expectedError: ":WRONG_VERSION_NUMBER:", | |
| }, | |
| { | |
| name: "RSAEphemeralKey", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, | |
| Bugs: ProtocolBugs{ | |
| RSAEphemeralKey: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_MESSAGE:", | |
| }, | |
| { | |
| name: "DisableEverything", | |
| flags: []string{"-no-tls13", "-no-tls12", "-no-tls11", "-no-tls1"}, | |
| shouldFail: true, | |
| expectedError: ":NO_SUPPORTED_VERSIONS_ENABLED:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "DisableEverything-DTLS", | |
| flags: []string{"-no-tls13", "-no-tls12", "-no-tls1"}, | |
| shouldFail: true, | |
| expectedError: ":NO_SUPPORTED_VERSIONS_ENABLED:", | |
| }, | |
| { | |
| protocol: dtls, | |
| testType: serverTest, | |
| name: "MTU-DTLS12-AEAD", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, | |
| Bugs: ProtocolBugs{ | |
| MaxPacketLength: 256, | |
| }, | |
| }, | |
| flags: []string{"-mtu", "256"}, | |
| }, | |
| { | |
| protocol: dtls, | |
| testType: serverTest, | |
| name: "MTU-DTLS12-AES-CBC", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256}, | |
| Bugs: ProtocolBugs{ | |
| MaxPacketLength: 256, | |
| }, | |
| }, | |
| flags: []string{"-mtu", "256"}, | |
| }, | |
| { | |
| protocol: dtls, | |
| testType: serverTest, | |
| name: "MTU-DTLS12-3DES-CBC", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_RSA_WITH_3DES_EDE_CBC_SHA}, | |
| Bugs: ProtocolBugs{ | |
| MaxPacketLength: 256, | |
| }, | |
| }, | |
| flags: []string{"-mtu", "256", "-cipher", "TLS_RSA_WITH_3DES_EDE_CBC_SHA"}, | |
| }, | |
| { | |
| protocol: dtls, | |
| testType: serverTest, | |
| name: "MTU-DTLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| MaxPacketLength: 256, | |
| }, | |
| }, | |
| flags: []string{"-mtu", "256"}, | |
| }, | |
| { | |
| name: "EmptyCertificateList", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| EmptyCertificateList: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":DECODE_ERROR:", | |
| }, | |
| { | |
| name: "EmptyCertificateList-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| EmptyCertificateList: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":PEER_DID_NOT_RETURN_A_CERTIFICATE:", | |
| }, | |
| { | |
| name: "TLSFatalBadPackets", | |
| damageFirstWrite: true, | |
| shouldFail: true, | |
| expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "DTLSIgnoreBadPackets", | |
| damageFirstWrite: true, | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "DTLSIgnoreBadPackets-Async", | |
| damageFirstWrite: true, | |
| flags: []string{"-async"}, | |
| }, | |
| { | |
| name: "AppDataBeforeHandshake", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| AppDataBeforeHandshake: []byte("TEST MESSAGE"), | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| }, | |
| { | |
| name: "AppDataBeforeHandshake-Empty", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| AppDataBeforeHandshake: []byte{}, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "AppDataBeforeHandshake-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| AppDataBeforeHandshake: []byte("TEST MESSAGE"), | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "AppDataBeforeHandshake-DTLS-Empty", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| AppDataBeforeHandshake: []byte{}, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| }, | |
| { | |
| name: "AppDataBeforeTLS13KeyChange", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| AppDataBeforeTLS13KeyChange: []byte("TEST MESSAGE"), | |
| }, | |
| }, | |
| // The shim should fail to decrypt this record. | |
| shouldFail: true, | |
| expectedError: ":BAD_DECRYPT:", | |
| expectedLocalError: "remote error: bad record MAC", | |
| }, | |
| { | |
| name: "AppDataBeforeTLS13KeyChange-Empty", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| AppDataBeforeTLS13KeyChange: []byte{}, | |
| }, | |
| }, | |
| // The shim should fail to decrypt this record. | |
| shouldFail: true, | |
| expectedError: ":BAD_DECRYPT:", | |
| expectedLocalError: "remote error: bad record MAC", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "AppDataBeforeTLS13KeyChange-DTLS", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| AppDataBeforeTLS13KeyChange: []byte("TEST MESSAGE"), | |
| }, | |
| }, | |
| // The shim will decrypt the record, because it has not | |
| // yet applied the key change, but it should know to | |
| // reject the record. | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| expectedLocalError: "remote error: unexpected message", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "AppDataBeforeTLS13KeyChange-DTLS-Empty", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| AppDataBeforeTLS13KeyChange: []byte{}, | |
| }, | |
| }, | |
| // The shim will decrypt the record, because it has not | |
| // yet applied the key change, but it should know to | |
| // reject the record. | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| expectedLocalError: "remote error: unexpected message", | |
| }, | |
| { | |
| name: "UnencryptedEncryptedExtensions", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| UnencryptedEncryptedExtensions: true, | |
| }, | |
| }, | |
| // The shim should fail to decrypt this record. | |
| shouldFail: true, | |
| expectedError: ":DECRYPTION_FAILED_OR_BAD_RECORD_MAC:", | |
| expectedLocalError: "remote error: bad record MAC", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "UnencryptedEncryptedExtensions-DTLS", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| UnencryptedEncryptedExtensions: true, | |
| }, | |
| }, | |
| // The shim will decrypt the record, because it has not | |
| // yet applied the key change, but it should know to | |
| // reject new handshake data on the previous epoch. | |
| shouldFail: true, | |
| expectedError: ":EXCESS_HANDSHAKE_DATA:", | |
| expectedLocalError: "remote error: unexpected message", | |
| }, | |
| { | |
| name: "AppDataAfterChangeCipherSpec", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"), | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| }, | |
| { | |
| name: "AppDataAfterChangeCipherSpec-Empty", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| AppDataAfterChangeCipherSpec: []byte{}, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "AppDataAfterChangeCipherSpec-DTLS", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| AppDataAfterChangeCipherSpec: []byte("TEST MESSAGE"), | |
| }, | |
| }, | |
| // BoringSSL's DTLS implementation will drop the out-of-order | |
| // application data. | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "AppDataAfterChangeCipherSpec-DTLS-Empty", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| AppDataAfterChangeCipherSpec: []byte{}, | |
| }, | |
| }, | |
| // BoringSSL's DTLS implementation will drop the out-of-order | |
| // application data. | |
| }, | |
| { | |
| name: "AlertAfterChangeCipherSpec", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| AlertAfterChangeCipherSpec: alertRecordOverflow, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "AlertAfterChangeCipherSpec-DTLS", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| AlertAfterChangeCipherSpec: alertRecordOverflow, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":TLSV1_ALERT_RECORD_OVERFLOW:", | |
| }, | |
| { | |
| name: "SendInvalidRecordType", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SendInvalidRecordType: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "SendInvalidRecordType-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SendInvalidRecordType: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| }, | |
| { | |
| name: "FalseStart-SkipServerSecondLeg", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, | |
| NextProtos: []string{"foo"}, | |
| Bugs: ProtocolBugs{ | |
| SkipNewSessionTicket: true, | |
| SkipChangeCipherSpec: true, | |
| SkipFinished: true, | |
| ExpectFalseStart: true, | |
| }, | |
| }, | |
| flags: []string{ | |
| "-false-start", | |
| "-handshake-never-done", | |
| "-advertise-alpn", "\x03foo", | |
| "-expect-alpn", "foo", | |
| }, | |
| shimWritesFirst: true, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| }, | |
| { | |
| name: "FalseStart-SkipServerSecondLeg-Implicit", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, | |
| NextProtos: []string{"foo"}, | |
| Bugs: ProtocolBugs{ | |
| SkipNewSessionTicket: true, | |
| SkipChangeCipherSpec: true, | |
| SkipFinished: true, | |
| }, | |
| }, | |
| flags: []string{ | |
| "-implicit-handshake", | |
| "-false-start", | |
| "-handshake-never-done", | |
| "-advertise-alpn", "\x03foo", | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "FailEarlyCallback", | |
| flags: []string{"-fail-early-callback"}, | |
| shouldFail: true, | |
| expectedError: ":CONNECTION_REJECTED:", | |
| expectedLocalError: "remote error: handshake failure", | |
| }, | |
| { | |
| name: "FailCertCallback-Client-TLS12", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| ClientAuth: RequestClientCert, | |
| }, | |
| flags: []string{"-fail-cert-callback"}, | |
| shouldFail: true, | |
| expectedError: ":CERT_CB_ERROR:", | |
| expectedLocalError: "remote error: internal error", | |
| }, | |
| { | |
| name: "FailCertCallback-Client-TLS12-CustomAlert", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| ClientAuth: RequestClientCert, | |
| }, | |
| flags: []string{ | |
| "-fail-cert-callback", | |
| "-fail-cert-callback-alert", | |
| strconv.Itoa(int(alertAccessDenied)), | |
| }, | |
| shouldFail: true, | |
| expectedError: ":CERT_CB_ERROR:", | |
| expectedLocalError: "remote error: access denied", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "FailCertCallback-Server-TLS12", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| flags: []string{"-fail-cert-callback"}, | |
| shouldFail: true, | |
| expectedError: ":CERT_CB_ERROR:", | |
| expectedLocalError: "remote error: internal error", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "FailCertCallback-Server-TLS12-CustomAlert", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| flags: []string{ | |
| "-fail-cert-callback", | |
| "-fail-cert-callback-alert", | |
| strconv.Itoa(int(alertUnrecognizedName)), | |
| }, | |
| shouldFail: true, | |
| expectedError: ":CERT_CB_ERROR:", | |
| expectedLocalError: "remote error: unrecognized name", | |
| }, | |
| { | |
| name: "FailCertCallback-Client-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| ClientAuth: RequestClientCert, | |
| }, | |
| flags: []string{"-fail-cert-callback"}, | |
| shouldFail: true, | |
| expectedError: ":CERT_CB_ERROR:", | |
| expectedLocalError: "remote error: internal error", | |
| }, | |
| { | |
| name: "FailCertCallback-Client-TLS13-CustomAlert", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| ClientAuth: RequestClientCert, | |
| }, | |
| flags: []string{ | |
| "-fail-cert-callback", | |
| "-fail-cert-callback-alert", | |
| strconv.Itoa(int(alertAccessDenied)), | |
| }, | |
| shouldFail: true, | |
| expectedError: ":CERT_CB_ERROR:", | |
| expectedLocalError: "remote error: access denied", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "FailCertCallback-Server-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| flags: []string{"-fail-cert-callback"}, | |
| shouldFail: true, | |
| expectedError: ":CERT_CB_ERROR:", | |
| expectedLocalError: "remote error: internal error", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "FailCertCallback-Server-TLS13-CustomAlert", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| flags: []string{ | |
| "-fail-cert-callback", | |
| "-fail-cert-callback-alert", | |
| strconv.Itoa(int(alertUnrecognizedName)), | |
| }, | |
| shouldFail: true, | |
| expectedError: ":CERT_CB_ERROR:", | |
| expectedLocalError: "remote error: unrecognized name", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "FragmentMessageTypeMismatch-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) { | |
| f1 := next[0].Fragment(0, 1) | |
| f2 := next[0].Fragment(1, 1) | |
| f2.Type++ | |
| c.WriteFragments([]DTLSFragment{f1, f2}) | |
| }, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":FRAGMENT_MISMATCH:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "FragmentMessageLengthMismatch-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) { | |
| f1 := next[0].Fragment(0, 1) | |
| f2 := next[0].Fragment(1, 1) | |
| f2.TotalLength++ | |
| c.WriteFragments([]DTLSFragment{f1, f2}) | |
| }, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":FRAGMENT_MISMATCH:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "SplitFragments-Header-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SplitFragments: 2, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":BAD_HANDSHAKE_RECORD:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "SplitFragments-Boundary-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SplitFragments: dtlsMaxRecordHeaderLen, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":BAD_HANDSHAKE_RECORD:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "SplitFragments-Body-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SplitFragments: dtlsMaxRecordHeaderLen + 1, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":BAD_HANDSHAKE_RECORD:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "SendEmptyFragments-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SendEmptyFragments: true, | |
| }, | |
| }, | |
| }, | |
| { | |
| testType: serverTest, | |
| protocol: dtls, | |
| name: "SendEmptyFragments-Padded-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| // Test empty fragments for a message with a | |
| // nice power-of-two length. | |
| PadClientHello: 64, | |
| SendEmptyFragments: true, | |
| }, | |
| }, | |
| }, | |
| { | |
| name: "BadFinished-Client", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| BadFinished: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":DIGEST_CHECK_FAILED:", | |
| }, | |
| { | |
| name: "BadFinished-Client-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| BadFinished: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":DIGEST_CHECK_FAILED:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "BadFinished-Server", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| BadFinished: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":DIGEST_CHECK_FAILED:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "BadFinished-Server-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| BadFinished: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":DIGEST_CHECK_FAILED:", | |
| }, | |
| { | |
| name: "FalseStart-BadFinished", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, | |
| NextProtos: []string{"foo"}, | |
| Bugs: ProtocolBugs{ | |
| BadFinished: true, | |
| ExpectFalseStart: true, | |
| }, | |
| }, | |
| flags: []string{ | |
| "-false-start", | |
| "-handshake-never-done", | |
| "-advertise-alpn", "\x03foo", | |
| "-expect-alpn", "foo", | |
| }, | |
| shimWritesFirst: true, | |
| shouldFail: true, | |
| expectedError: ":DIGEST_CHECK_FAILED:", | |
| }, | |
| { | |
| name: "NoFalseStart-NoALPN", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, | |
| Bugs: ProtocolBugs{ | |
| ExpectFalseStart: true, | |
| AlertBeforeFalseStartTest: alertAccessDenied, | |
| }, | |
| }, | |
| flags: []string{ | |
| "-false-start", | |
| }, | |
| shimWritesFirst: true, | |
| shouldFail: true, | |
| expectedError: ":TLSV1_ALERT_ACCESS_DENIED:", | |
| expectedLocalError: "tls: peer did not false start: EOF", | |
| }, | |
| { | |
| name: "FalseStart-NoALPNAllowed", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, | |
| Bugs: ProtocolBugs{ | |
| ExpectFalseStart: true, | |
| }, | |
| }, | |
| flags: []string{ | |
| "-false-start", | |
| "-allow-false-start-without-alpn", | |
| }, | |
| shimWritesFirst: true, | |
| }, | |
| { | |
| name: "NoFalseStart-NoAEAD", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA}, | |
| NextProtos: []string{"foo"}, | |
| Bugs: ProtocolBugs{ | |
| ExpectFalseStart: true, | |
| AlertBeforeFalseStartTest: alertAccessDenied, | |
| }, | |
| }, | |
| flags: []string{ | |
| "-false-start", | |
| "-advertise-alpn", "\x03foo", | |
| }, | |
| shimWritesFirst: true, | |
| shouldFail: true, | |
| expectedError: ":TLSV1_ALERT_ACCESS_DENIED:", | |
| expectedLocalError: "tls: peer did not false start: EOF", | |
| }, | |
| { | |
| name: "NoFalseStart-RSA", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}, | |
| NextProtos: []string{"foo"}, | |
| Bugs: ProtocolBugs{ | |
| ExpectFalseStart: true, | |
| AlertBeforeFalseStartTest: alertAccessDenied, | |
| }, | |
| }, | |
| flags: []string{ | |
| "-false-start", | |
| "-advertise-alpn", "\x03foo", | |
| }, | |
| shimWritesFirst: true, | |
| shouldFail: true, | |
| expectedError: ":TLSV1_ALERT_ACCESS_DENIED:", | |
| expectedLocalError: "tls: peer did not false start: EOF", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "SendSplitAlert-Sync", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SendSplitAlert: true, | |
| }, | |
| }, | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "SendSplitAlert-Async", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SendSplitAlert: true, | |
| }, | |
| }, | |
| flags: []string{"-async"}, | |
| }, | |
| { | |
| name: "SendEmptyRecords-Pass", | |
| sendEmptyRecords: 32, | |
| }, | |
| { | |
| name: "SendEmptyRecords", | |
| sendEmptyRecords: 33, | |
| shouldFail: true, | |
| expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:", | |
| }, | |
| { | |
| name: "SendEmptyRecords-Async", | |
| sendEmptyRecords: 33, | |
| flags: []string{"-async"}, | |
| shouldFail: true, | |
| expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:", | |
| }, | |
| { | |
| name: "SendWarningAlerts-Pass", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| sendWarningAlerts: 4, | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "SendWarningAlerts-DTLS-Pass", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| sendWarningAlerts: 4, | |
| }, | |
| { | |
| name: "SendWarningAlerts-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| sendWarningAlerts: 4, | |
| shouldFail: true, | |
| expectedError: ":BAD_ALERT:", | |
| expectedLocalError: "remote error: error decoding message", | |
| }, | |
| // Although TLS 1.3 intended to remove warning alerts, it left in | |
| // user_canceled. JDK11 misuses this alert as a post-handshake | |
| // full-duplex signal. As a workaround, skip user_canceled as in | |
| // TLS 1.2, which is consistent with NSS and OpenSSL. | |
| { | |
| name: "SendUserCanceledAlerts-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| sendUserCanceledAlerts: 4, | |
| }, | |
| { | |
| name: "SendUserCanceledAlerts-TooMany-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| sendUserCanceledAlerts: 5, | |
| shouldFail: true, | |
| expectedError: ":TOO_MANY_WARNING_ALERTS:", | |
| }, | |
| { | |
| name: "SendWarningAlerts-TooMany", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| sendWarningAlerts: 5, | |
| shouldFail: true, | |
| expectedError: ":TOO_MANY_WARNING_ALERTS:", | |
| }, | |
| { | |
| name: "SendWarningAlerts-TooMany-Async", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| sendWarningAlerts: 5, | |
| flags: []string{"-async"}, | |
| shouldFail: true, | |
| expectedError: ":TOO_MANY_WARNING_ALERTS:", | |
| }, | |
| { | |
| name: "AlternateEmptyRecordsAndWarningAlerts", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| sendEmptyRecords: 32, | |
| sendWarningAlerts: 4, | |
| }, | |
| { | |
| name: "AlternateTooManyEmptyRecordsAndWarningAlerts", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| sendEmptyRecords: 33, | |
| sendWarningAlerts: 4, | |
| shouldFail: true, | |
| expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:", | |
| }, | |
| { | |
| name: "AlternateEmptyRecordsAndTooManyWarningAlerts", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| sendEmptyRecords: 32, | |
| sendWarningAlerts: 5, | |
| shouldFail: true, | |
| expectedError: ":TOO_MANY_WARNING_ALERTS:", | |
| }, | |
| { | |
| name: "SendBogusAlertType", | |
| sendBogusAlertType: true, | |
| shouldFail: true, | |
| expectedError: ":UNKNOWN_ALERT_TYPE:", | |
| expectedLocalError: "remote error: illegal parameter", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "SendBogusAlertType-DTLS", | |
| sendBogusAlertType: true, | |
| shouldFail: true, | |
| expectedError: ":UNKNOWN_ALERT_TYPE:", | |
| expectedLocalError: "remote error: illegal parameter", | |
| }, | |
| { | |
| name: "TooManyKeyUpdates", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| sendKeyUpdates: 33, | |
| keyUpdateRequest: keyUpdateNotRequested, | |
| shouldFail: true, | |
| expectedError: ":TOO_MANY_KEY_UPDATES:", | |
| }, | |
| { | |
| name: "EmptySessionID", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| SessionTicketsDisabled: true, | |
| }, | |
| noSessionCache: true, | |
| flags: []string{"-expect-no-session"}, | |
| }, | |
| { | |
| name: "Unclean-Shutdown", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| NoCloseNotify: true, | |
| ExpectCloseNotify: true, | |
| }, | |
| }, | |
| shimShutsDown: true, | |
| flags: []string{"-check-close-notify"}, | |
| shouldFail: true, | |
| expectedError: "Unexpected SSL_shutdown result: -1 != 1", | |
| }, | |
| { | |
| name: "Unclean-Shutdown-Ignored", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| NoCloseNotify: true, | |
| }, | |
| }, | |
| shimShutsDown: true, | |
| }, | |
| { | |
| name: "Unclean-Shutdown-Alert", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SendAlertOnShutdown: alertDecompressionFailure, | |
| ExpectCloseNotify: true, | |
| }, | |
| }, | |
| shimShutsDown: true, | |
| flags: []string{"-check-close-notify"}, | |
| shouldFail: true, | |
| expectedError: ":SSLV3_ALERT_DECOMPRESSION_FAILURE:", | |
| }, | |
| { | |
| name: "LargePlaintext", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SendLargeRecords: true, | |
| }, | |
| }, | |
| messageLen: maxPlaintext + 1, | |
| shouldFail: true, | |
| expectedError: ":DATA_LENGTH_TOO_LONG:", | |
| expectedLocalError: "remote error: record overflow", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "LargePlaintext-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SendLargeRecords: true, | |
| }, | |
| }, | |
| messageLen: maxPlaintext + 1, | |
| shouldFail: true, | |
| expectedError: ":DATA_LENGTH_TOO_LONG:", | |
| expectedLocalError: "remote error: record overflow", | |
| }, | |
| { | |
| name: "LargePlaintext-TLS13-Padded-8192-8192", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| RecordPadding: 8192, | |
| SendLargeRecords: true, | |
| }, | |
| }, | |
| messageLen: 8192, | |
| }, | |
| { | |
| name: "LargePlaintext-TLS13-Padded-8193-8192", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| RecordPadding: 8193, | |
| SendLargeRecords: true, | |
| }, | |
| }, | |
| messageLen: 8192, | |
| shouldFail: true, | |
| expectedError: ":DATA_LENGTH_TOO_LONG:", | |
| expectedLocalError: "remote error: record overflow", | |
| }, | |
| { | |
| name: "LargePlaintext-TLS13-Padded-16383-1", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| RecordPadding: 1, | |
| SendLargeRecords: true, | |
| }, | |
| }, | |
| messageLen: 16383, | |
| }, | |
| { | |
| name: "LargePlaintext-TLS13-Padded-16384-1", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| RecordPadding: 1, | |
| SendLargeRecords: true, | |
| }, | |
| }, | |
| messageLen: 16384, | |
| shouldFail: true, | |
| expectedError: ":DATA_LENGTH_TOO_LONG:", | |
| expectedLocalError: "remote error: record overflow", | |
| }, | |
| { | |
| name: "LargeCiphertext", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SendLargeRecords: true, | |
| }, | |
| }, | |
| messageLen: maxPlaintext * 2, | |
| shouldFail: true, | |
| expectedError: ":ENCRYPTED_LENGTH_TOO_LONG:", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "LargeCiphertext-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SendLargeRecords: true, | |
| }, | |
| }, | |
| messageLen: maxPlaintext * 2, | |
| // Unlike the other four cases, DTLS drops records which | |
| // are invalid before authentication, so the connection | |
| // does not fail. | |
| expectMessageDropped: true, | |
| }, | |
| { | |
| name: "BadHelloRequest-1", | |
| renegotiate: 1, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| BadHelloRequest: []byte{typeHelloRequest, 0, 0, 1, 1}, | |
| }, | |
| }, | |
| flags: []string{ | |
| "-renegotiate-freely", | |
| "-expect-total-renegotiations", "1", | |
| }, | |
| shouldFail: true, | |
| expectedError: ":BAD_HELLO_REQUEST:", | |
| }, | |
| { | |
| name: "BadHelloRequest-2", | |
| renegotiate: 1, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| BadHelloRequest: []byte{typeServerKeyExchange, 0, 0, 0}, | |
| }, | |
| }, | |
| flags: []string{ | |
| "-renegotiate-freely", | |
| "-expect-total-renegotiations", "1", | |
| }, | |
| shouldFail: true, | |
| expectedError: ":BAD_HELLO_REQUEST:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "SupportTicketsWithSessionID", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| SessionTicketsDisabled: true, | |
| }, | |
| resumeConfig: &Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| resumeSession: true, | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "DTLS12-SendExtraFinished", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| SendExtraFinished: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_RECORD:", | |
| expectedLocalError: "remote error: unexpected message", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "DTLS12-SendExtraFinished-Reordered", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| SendExtraFinished: true, | |
| WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) { | |
| if next[len(next)-1].Type == typeFinished { | |
| // Reorder such that the extra Finished is sent first. | |
| if len(next) < 2 || next[len(next)-2].Type != typeFinished { | |
| panic("expected two Finished messages") | |
| } | |
| slices.Reverse(next[len(next)-2:]) | |
| } | |
| c.WriteFlight(next) | |
| }, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":EXCESS_HANDSHAKE_DATA:", | |
| expectedLocalError: "remote error: unexpected message", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "DTLS12-SendExtraFinished-Packed", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| SendExtraFinished: true, | |
| PackHandshakeFragments: 1000, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":EXCESS_HANDSHAKE_DATA:", | |
| expectedLocalError: "remote error: unexpected message", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "DTLS13-SendExtraFinished", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| SendExtraFinished: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":EXCESS_HANDSHAKE_DATA:", | |
| expectedLocalError: "remote error: unexpected message", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "DTLS13-SendExtraFinished-Reordered", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| SendExtraFinished: true, | |
| WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) { | |
| if next[len(next)-1].Type == typeFinished { | |
| // Reorder such that the extra Finished is sent first. | |
| if len(next) < 2 || next[len(next)-2].Type != typeFinished { | |
| panic("expected two Finished messages") | |
| } | |
| slices.Reverse(next[len(next)-2:]) | |
| } | |
| c.WriteFlight(next) | |
| }, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":EXCESS_HANDSHAKE_DATA:", | |
| expectedLocalError: "remote error: unexpected message", | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "DTLS13-SendExtraFinished-Packed", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| SendExtraFinished: true, | |
| PackHandshakeFragments: 1000, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":EXCESS_HANDSHAKE_DATA:", | |
| expectedLocalError: "remote error: unexpected message", | |
| }, | |
| { | |
| protocol: dtls, | |
| testType: serverTest, | |
| name: "DTLS13-SendExtraFinished-AfterAppData", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| SkipImplicitACKRead: true, | |
| WriteFlightDTLS: func(c *DTLSController, prev, received, next []DTLSMessage, records []DTLSRecordNumberInfo) { | |
| if next[len(next)-1].Type != typeFinished { | |
| c.WriteFlight(next) | |
| return | |
| } | |
| // Complete the handshake. | |
| c.WriteFlight(next) | |
| c.ReadACK(c.InEpoch()) | |
| // Send some application data. The shim is now on epoch 3. | |
| msg := []byte("hello") | |
| c.WriteAppData(c.OutEpoch(), msg) | |
| c.ReadAppData(c.InEpoch(), expectedReply(msg)) | |
| // The shim is still accepting data from epoch 2, so it can | |
| // ACK a retransmit if needed, but it should not accept new | |
| // messages at epoch three. | |
| extraFinished := next[len(next)-1] | |
| extraFinished.Sequence++ | |
| c.WriteFlight([]DTLSMessage{extraFinished}) | |
| }, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":EXCESS_HANDSHAKE_DATA:", | |
| expectedLocalError: "remote error: unexpected message", | |
| // Disable tickets on the shim to avoid NewSessionTicket | |
| // interfering with the test callback. | |
| flags: []string{"-no-ticket"}, | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "V2ClientHello-EmptyRecordPrefix", | |
| config: Config{ | |
| // Choose a cipher suite that does not involve | |
| // elliptic curves, so no extensions are | |
| // involved. | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, | |
| Bugs: ProtocolBugs{ | |
| SendV2ClientHello: true, | |
| }, | |
| }, | |
| sendPrefix: string([]byte{ | |
| byte(recordTypeHandshake), | |
| 3, 1, // version | |
| 0, 0, // length | |
| }), | |
| // A no-op empty record may not be sent before V2ClientHello. | |
| shouldFail: true, | |
| expectedError: ":WRONG_VERSION_NUMBER:", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "V2ClientHello-WarningAlertPrefix", | |
| config: Config{ | |
| // Choose a cipher suite that does not involve | |
| // elliptic curves, so no extensions are | |
| // involved. | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA}, | |
| Bugs: ProtocolBugs{ | |
| SendV2ClientHello: true, | |
| }, | |
| }, | |
| sendPrefix: string([]byte{ | |
| byte(recordTypeAlert), | |
| 3, 1, // version | |
| 0, 2, // length | |
| alertLevelWarning, byte(alertDecompressionFailure), | |
| }), | |
| // A no-op warning alert may not be sent before V2ClientHello. | |
| shouldFail: true, | |
| expectedError: ":WRONG_VERSION_NUMBER:", | |
| }, | |
| { | |
| name: "SendSNIWarningAlert", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| SendSNIWarningAlert: true, | |
| }, | |
| }, | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "ExtraCompressionMethods-TLS12", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| SendCompressionMethods: []byte{1, 2, 3, compressionNone, 4, 5, 6}, | |
| }, | |
| }, | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "ExtraCompressionMethods-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| SendCompressionMethods: []byte{1, 2, 3, compressionNone, 4, 5, 6}, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":INVALID_COMPRESSION_LIST:", | |
| expectedLocalError: "remote error: illegal parameter", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "NoNullCompression-TLS12", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| SendCompressionMethods: []byte{1, 2, 3, 4, 5, 6}, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":INVALID_COMPRESSION_LIST:", | |
| expectedLocalError: "remote error: illegal parameter", | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "NoNullCompression-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| SendCompressionMethods: []byte{1, 2, 3, 4, 5, 6}, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":INVALID_COMPRESSION_LIST:", | |
| expectedLocalError: "remote error: illegal parameter", | |
| }, | |
| // Test that the client rejects invalid compression methods | |
| // from the server. | |
| { | |
| testType: clientTest, | |
| name: "InvalidCompressionMethod", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| SendCompressionMethod: 1, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNSUPPORTED_COMPRESSION_ALGORITHM:", | |
| expectedLocalError: "remote error: illegal parameter", | |
| }, | |
| { | |
| testType: clientTest, | |
| name: "TLS13-InvalidCompressionMethod", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| SendCompressionMethod: 1, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":DECODE_ERROR:", | |
| }, | |
| { | |
| testType: clientTest, | |
| name: "TLS13-HRR-InvalidCompressionMethod", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| CurvePreferences: []CurveID{CurveP384}, | |
| Bugs: ProtocolBugs{ | |
| SendCompressionMethod: 1, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":DECODE_ERROR:", | |
| expectedLocalError: "remote error: error decoding message", | |
| }, | |
| { | |
| name: "GREASE-Client-TLS12", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| ExpectGREASE: true, | |
| }, | |
| }, | |
| flags: []string{"-enable-grease"}, | |
| }, | |
| { | |
| name: "GREASE-Client-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| ExpectGREASE: true, | |
| }, | |
| }, | |
| flags: []string{"-enable-grease"}, | |
| }, | |
| { | |
| testType: serverTest, | |
| name: "GREASE-Server-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| // TLS 1.3 servers are expected to | |
| // always enable GREASE. TLS 1.3 is new, | |
| // so there is no existing ecosystem to | |
| // worry about. | |
| ExpectGREASE: true, | |
| }, | |
| }, | |
| }, | |
| { | |
| // Test the TLS 1.2 server so there is a large | |
| // unencrypted certificate as well as application data. | |
| testType: serverTest, | |
| name: "MaxSendFragment-TLS12", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| MaxReceivePlaintext: 512, | |
| }, | |
| }, | |
| messageLen: 1024, | |
| flags: []string{ | |
| "-max-send-fragment", "512", | |
| "-read-size", "1024", | |
| }, | |
| }, | |
| { | |
| // Test the TLS 1.2 server so there is a large | |
| // unencrypted certificate as well as application data. | |
| testType: serverTest, | |
| name: "MaxSendFragment-TLS12-TooLarge", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| // Ensure that some of the records are | |
| // 512. | |
| MaxReceivePlaintext: 511, | |
| }, | |
| }, | |
| messageLen: 1024, | |
| flags: []string{ | |
| "-max-send-fragment", "512", | |
| "-read-size", "1024", | |
| }, | |
| shouldFail: true, | |
| expectedLocalError: "local error: record overflow", | |
| }, | |
| { | |
| // Test the TLS 1.3 server so there is a large encrypted | |
| // certificate as well as application data. | |
| testType: serverTest, | |
| name: "MaxSendFragment-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| MaxReceivePlaintext: 512, | |
| ExpectPackedEncryptedHandshake: 512, | |
| }, | |
| }, | |
| messageLen: 1024, | |
| flags: []string{ | |
| "-max-send-fragment", "512", | |
| "-read-size", "1024", | |
| }, | |
| }, | |
| { | |
| // Test the TLS 1.3 server so there is a large encrypted | |
| // certificate as well as application data. | |
| testType: serverTest, | |
| name: "MaxSendFragment-TLS13-TooLarge", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| // Ensure that some of the records are | |
| // 512. | |
| MaxReceivePlaintext: 511, | |
| }, | |
| }, | |
| messageLen: 1024, | |
| flags: []string{ | |
| "-max-send-fragment", "512", | |
| "-read-size", "1024", | |
| }, | |
| shouldFail: true, | |
| expectedLocalError: "local error: record overflow", | |
| }, | |
| { | |
| // Test that handshake data is tightly packed in TLS 1.3. | |
| testType: serverTest, | |
| name: "PackedEncryptedHandshake-TLS13", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| ExpectPackedEncryptedHandshake: 16384, | |
| }, | |
| }, | |
| }, | |
| { | |
| // Test that DTLS can handle multiple application data | |
| // records in a single packet. | |
| protocol: dtls, | |
| name: "SplitAndPackAppData-DTLS", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SplitAndPackAppData: true, | |
| }, | |
| }, | |
| }, | |
| { | |
| protocol: dtls, | |
| name: "SplitAndPackAppData-DTLS-Async", | |
| config: Config{ | |
| Bugs: ProtocolBugs{ | |
| SplitAndPackAppData: true, | |
| }, | |
| }, | |
| flags: []string{"-async"}, | |
| }, | |
| { | |
| // DTLS 1.2 allows up to a 255-byte HelloVerifyRequest cookie, which | |
| // is the largest encodable value. | |
| protocol: dtls, | |
| name: "DTLS-HelloVerifyRequest-255", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| HelloVerifyRequestCookieLength: 255, | |
| }, | |
| }, | |
| }, | |
| { | |
| // DTLS 1.2 allows up to a 0-byte HelloVerifyRequest cookie, which | |
| // was probably a mistake in the spec but test that it works | |
| // nonetheless. | |
| protocol: dtls, | |
| name: "DTLS-HelloVerifyRequest-0", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| EmptyHelloVerifyRequestCookie: true, | |
| }, | |
| }, | |
| }, | |
| } | |
| testCases = append(testCases, basicTests...) | |
| // Test that very large messages can be received. | |
| cert := rsaCertificate | |
| for range 50 { | |
| cert.Certificate = append(cert.Certificate, cert.Certificate[0]) | |
| } | |
| testCases = append(testCases, testCase{ | |
| name: "LargeMessage", | |
| config: Config{ | |
| Credential: &cert, | |
| }, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| protocol: dtls, | |
| name: "LargeMessage-DTLS", | |
| config: Config{ | |
| Credential: &cert, | |
| }, | |
| }) | |
| // They are rejected if the maximum certificate chain length is capped. | |
| testCases = append(testCases, testCase{ | |
| name: "LargeMessage-Reject", | |
| config: Config{ | |
| Credential: &cert, | |
| }, | |
| flags: []string{"-max-cert-list", "16384"}, | |
| shouldFail: true, | |
| expectedError: ":EXCESSIVE_MESSAGE_SIZE:", | |
| }) | |
| testCases = append(testCases, testCase{ | |
| protocol: dtls, | |
| name: "LargeMessage-Reject-DTLS", | |
| config: Config{ | |
| Credential: &cert, | |
| }, | |
| flags: []string{"-max-cert-list", "16384"}, | |
| shouldFail: true, | |
| expectedError: ":EXCESSIVE_MESSAGE_SIZE:", | |
| }) | |
| // Servers echoing the TLS 1.3 compatibility mode session ID should be | |
| // rejected. | |
| testCases = append(testCases, testCase{ | |
| name: "EchoTLS13CompatibilitySessionID", | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Bugs: ProtocolBugs{ | |
| EchoSessionIDInFullHandshake: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":SERVER_ECHOED_INVALID_SESSION_ID:", | |
| expectedLocalError: "remote error: illegal parameter", | |
| }) | |
| // Servers should reject QUIC client hellos that have a legacy | |
| // session ID. | |
| testCases = append(testCases, testCase{ | |
| name: "QUICCompatibilityMode", | |
| testType: serverTest, | |
| protocol: quic, | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| CompatModeWithQUIC: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":UNEXPECTED_COMPATIBILITY_MODE:", | |
| }) | |
| // Clients should reject DTLS 1.3 ServerHellos that echo the legacy | |
| // session ID. | |
| testCases = append(testCases, testCase{ | |
| protocol: dtls, | |
| name: "DTLS13CompatibilityMode-EchoSessionID", | |
| resumeSession: true, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| resumeConfig: &Config{ | |
| MinVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| DTLS13EchoSessionID: true, | |
| }, | |
| }, | |
| shouldFail: true, | |
| expectedError: ":DECODE_ERROR:", | |
| }) | |
| // DTLS 1.3 should work with record headers that don't set the | |
| // length bit or that use the short sequence number format. | |
| testCases = append(testCases, testCase{ | |
| testType: clientTest, | |
| protocol: dtls, | |
| name: "DTLS13RecordHeader-NoLength-Client", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| DTLSRecordHeaderOmitLength: true, | |
| }, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: dtls, | |
| name: "DTLS13RecordHeader-NoLength-Server", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| DTLSRecordHeaderOmitLength: true, | |
| }, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| testType: clientTest, | |
| protocol: dtls, | |
| name: "DTLS13RecordHeader-ShortSeqNums-Client", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| DTLSUseShortSeqNums: true, | |
| }, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: dtls, | |
| name: "DTLS13RecordHeader-ShortSeqNums-Server", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| DTLSUseShortSeqNums: true, | |
| }, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| protocol: dtls, | |
| name: "DTLS13RecordHeader-OldHeader", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| DTLSUsePlaintextRecordHeader: true, | |
| }, | |
| }, | |
| expectMessageDropped: true, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| protocol: dtls, | |
| name: "DTLS13RecordHeader-CIDBit", | |
| config: Config{ | |
| MinVersion: VersionTLS13, | |
| Bugs: ProtocolBugs{ | |
| DTLS13RecordHeaderSetCIDBit: true, | |
| }, | |
| }, | |
| expectMessageDropped: true, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| protocol: dtls, | |
| name: "DTLS13-MessageCallback-Client", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| MinVersion: VersionTLS13, | |
| }, | |
| flags: []string{ | |
| "-expect-msg-callback", | |
| `write hs 1 | |
| read hs 2 | |
| read hs 8 | |
| read hs 11 | |
| read hs 15 | |
| read hs 20 | |
| write hs 20 | |
| read ack | |
| read hs 4 | |
| read hs 4 | |
| read alert 1 0 | |
| `, | |
| }, | |
| }) | |
| testCases = append(testCases, testCase{ | |
| testType: serverTest, | |
| protocol: dtls, | |
| name: "DTLS13-MessageCallback-Server", | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| MinVersion: VersionTLS13, | |
| }, | |
| flags: []string{ | |
| // Exact message trace of the handshake depends on selected curves, | |
| // as MLKEM causes messages to be split due to its handshake size | |
| // and DTLS trying to respect a MTU here. | |
| "-curves", strconv.Itoa(int(CurveX25519)), | |
| "-expect-msg-callback", | |
| `read hs 1 | |
| write hs 2 | |
| write hs 8 | |
| write hs 11 | |
| write hs 15 | |
| write hs 20 | |
| read hs 20 | |
| write ack | |
| write hs 4 | |
| write hs 4 | |
| read ack | |
| read ack | |
| read alert 1 0 | |
| `, | |
| }, | |
| }) | |
| } |