| // 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 | |
| type perMessageTest struct { | |
| messageType uint8 | |
| test testCase | |
| } | |
| // makePerMessageTests returns a series of test templates which cover each | |
| // message in the TLS handshake. These may be used with bugs like | |
| // WrongMessageType to fully test a per-message bug. | |
| func makePerMessageTests() []perMessageTest { | |
| var ret []perMessageTest | |
| // The following tests are limited to TLS 1.2, so QUIC is not tested. | |
| for _, protocol := range []protocol{tls, dtls} { | |
| suffix := "-" + protocol.String() | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeClientHello, | |
| test: testCase{ | |
| protocol: protocol, | |
| testType: serverTest, | |
| name: "ClientHello" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| }, | |
| }) | |
| if protocol == dtls { | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeHelloVerifyRequest, | |
| test: testCase{ | |
| protocol: protocol, | |
| name: "HelloVerifyRequest" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| }, | |
| }) | |
| } | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeServerHello, | |
| test: testCase{ | |
| protocol: protocol, | |
| name: "ServerHello" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeCertificate, | |
| test: testCase{ | |
| protocol: protocol, | |
| name: "ServerCertificate" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeCertificateStatus, | |
| test: testCase{ | |
| protocol: protocol, | |
| name: "CertificateStatus" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| Credential: rsaCertificate.WithOCSP(testOCSPResponse), | |
| }, | |
| flags: []string{"-enable-ocsp-stapling"}, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeServerKeyExchange, | |
| test: testCase{ | |
| protocol: protocol, | |
| name: "ServerKeyExchange" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeCertificateRequest, | |
| test: testCase{ | |
| protocol: protocol, | |
| name: "CertificateRequest" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| ClientAuth: RequireAnyClientCert, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeServerHelloDone, | |
| test: testCase{ | |
| protocol: protocol, | |
| name: "ServerHelloDone" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeCertificate, | |
| test: testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "ClientCertificate" + suffix, | |
| config: Config{ | |
| Credential: &rsaCertificate, | |
| MaxVersion: VersionTLS12, | |
| }, | |
| flags: []string{"-require-any-client-certificate"}, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeCertificateVerify, | |
| test: testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "CertificateVerify" + suffix, | |
| config: Config{ | |
| Credential: &rsaCertificate, | |
| MaxVersion: VersionTLS12, | |
| }, | |
| flags: []string{"-require-any-client-certificate"}, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeClientKeyExchange, | |
| test: testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "ClientKeyExchange" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| }, | |
| }) | |
| if protocol != dtls { | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeNextProtocol, | |
| test: testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "NextProtocol" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| NextProtos: []string{"bar"}, | |
| }, | |
| flags: []string{"-advertise-npn", "\x03foo\x03bar\x03baz"}, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeChannelID, | |
| test: testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "ChannelID" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| ChannelID: &channelIDKey, | |
| }, | |
| flags: []string{ | |
| "-expect-channel-id", | |
| base64FlagValue(channelIDBytes), | |
| }, | |
| }, | |
| }) | |
| } | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeFinished, | |
| test: testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "ClientFinished" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeNewSessionTicket, | |
| test: testCase{ | |
| protocol: protocol, | |
| name: "NewSessionTicket" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeFinished, | |
| test: testCase{ | |
| protocol: protocol, | |
| name: "ServerFinished" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS12, | |
| }, | |
| }, | |
| }) | |
| } | |
| for _, protocol := range []protocol{tls, quic, dtls} { | |
| suffix := "-" + protocol.String() | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeClientHello, | |
| test: testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "TLS13-ClientHello" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeServerHello, | |
| test: testCase{ | |
| name: "TLS13-ServerHello" + suffix, | |
| protocol: protocol, | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeEncryptedExtensions, | |
| test: testCase{ | |
| name: "TLS13-EncryptedExtensions" + suffix, | |
| protocol: protocol, | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeCertificateRequest, | |
| test: testCase{ | |
| name: "TLS13-CertificateRequest" + suffix, | |
| protocol: protocol, | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| ClientAuth: RequireAnyClientCert, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeCertificate, | |
| test: testCase{ | |
| name: "TLS13-ServerCertificate" + suffix, | |
| protocol: protocol, | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeCertificateVerify, | |
| test: testCase{ | |
| name: "TLS13-ServerCertificateVerify" + suffix, | |
| protocol: protocol, | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeFinished, | |
| test: testCase{ | |
| name: "TLS13-ServerFinished" + suffix, | |
| protocol: protocol, | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeCertificate, | |
| test: testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "TLS13-ClientCertificate" + suffix, | |
| config: Config{ | |
| Credential: &rsaCertificate, | |
| MaxVersion: VersionTLS13, | |
| }, | |
| flags: []string{"-require-any-client-certificate"}, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeCertificateVerify, | |
| test: testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "TLS13-ClientCertificateVerify" + suffix, | |
| config: Config{ | |
| Credential: &rsaCertificate, | |
| MaxVersion: VersionTLS13, | |
| }, | |
| flags: []string{"-require-any-client-certificate"}, | |
| }, | |
| }) | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeFinished, | |
| test: testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "TLS13-ClientFinished" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| }, | |
| }) | |
| // Only TLS uses EndOfEarlyData. | |
| if protocol == tls { | |
| ret = append(ret, perMessageTest{ | |
| messageType: typeEndOfEarlyData, | |
| test: testCase{ | |
| testType: serverTest, | |
| protocol: protocol, | |
| name: "TLS13-EndOfEarlyData" + suffix, | |
| config: Config{ | |
| MaxVersion: VersionTLS13, | |
| }, | |
| resumeSession: true, | |
| earlyData: true, | |
| }, | |
| }) | |
| } | |
| } | |
| return ret | |
| } | |
| func addWrongMessageTypeTests() { | |
| for _, t := range makePerMessageTests() { | |
| t.test.name = "WrongMessageType-" + t.test.name | |
| if t.test.resumeConfig != nil { | |
| t.test.resumeConfig.Bugs.SendWrongMessageType = t.messageType | |
| } else { | |
| t.test.config.Bugs.SendWrongMessageType = t.messageType | |
| } | |
| t.test.shouldFail = true | |
| t.test.expectedError = ":UNEXPECTED_MESSAGE:" | |
| t.test.expectedLocalError = "remote error: unexpected message" | |
| if t.test.config.MaxVersion >= VersionTLS13 && t.messageType == typeServerHello { | |
| // In TLS 1.3, if the server believes it has sent ServerHello, | |
| // but the client cannot process it, the client will send an | |
| // unencrypted alert while the server expects encryption. This | |
| // decryption failure is reported differently for each protocol, so | |
| // leave it unchecked. | |
| t.test.expectedLocalError = "" | |
| } | |
| testCases = append(testCases, t.test) | |
| } | |
| } | |
| func addTrailingMessageDataTests() { | |
| for _, t := range makePerMessageTests() { | |
| t.test.name = "TrailingMessageData-" + t.test.name | |
| if t.test.resumeConfig != nil { | |
| t.test.resumeConfig.Bugs.SendTrailingMessageData = t.messageType | |
| } else { | |
| t.test.config.Bugs.SendTrailingMessageData = t.messageType | |
| } | |
| t.test.shouldFail = true | |
| t.test.expectedError = ":DECODE_ERROR:" | |
| t.test.expectedLocalError = "remote error: error decoding message" | |
| if t.test.config.MaxVersion >= VersionTLS13 && t.messageType == typeServerHello { | |
| // In TLS 1.3, if the server believes it has sent ServerHello, | |
| // but the client cannot process it, the client will send an | |
| // unencrypted alert while the server expects encryption. This | |
| // decryption failure is reported differently for each protocol, so | |
| // leave it unchecked. | |
| t.test.expectedLocalError = "" | |
| } | |
| if t.messageType == typeClientHello { | |
| // We have a different error for ClientHello parsing. | |
| t.test.expectedError = ":CLIENTHELLO_PARSE_FAILED:" | |
| } | |
| if t.messageType == typeFinished { | |
| // Bad Finished messages read as the verify data having | |
| // the wrong length. | |
| t.test.expectedError = ":DIGEST_CHECK_FAILED:" | |
| t.test.expectedLocalError = "remote error: error decrypting message" | |
| } | |
| testCases = append(testCases, t.test) | |
| } | |
| } |