// 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 "errors" func addPAKETests() { spakeCredential := Credential{ Type: CredentialTypeSPAKE2PlusV1, PAKEContext: []byte("context"), PAKEClientID: []byte("client"), PAKEServerID: []byte("server"), PAKEPassword: []byte("password"), } spakeWrongClientID := spakeCredential spakeWrongClientID.PAKEClientID = []byte("wrong") spakeWrongServerID := spakeCredential spakeWrongServerID.PAKEServerID = []byte("wrong") spakeWrongPassword := spakeCredential spakeWrongPassword.PAKEPassword = []byte("wrong") spakeWrongRole := spakeCredential spakeWrongRole.WrongPAKERole = true spakeWrongCodepoint := spakeCredential spakeWrongCodepoint.OverridePAKECodepoint = 1234 testCases = append(testCases, testCase{ name: "PAKE-No-Server-Support", testType: serverTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, }, shouldFail: true, expectedError: ":MISSING_KEY_SHARE:", }) testCases = append(testCases, testCase{ name: "PAKE-Server", testType: serverTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, Bugs: ProtocolBugs{ // We do not currently support resumption with PAKE, so PAKE // servers should not issue session tickets. ExpectNoNewSessionTicket: true, }, }, shimCredentials: []*Credential{&spakeCredential}, }) testCases = append(testCases, testCase{ // Send a ClientHello with the wrong PAKE client ID. name: "PAKE-Server-WrongClientID", testType: serverTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeWrongClientID, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":PEER_PAKE_MISMATCH:", expectedLocalError: "remote error: handshake failure", }) testCases = append(testCases, testCase{ // Send a ClientHello with the wrong PAKE server ID. name: "PAKE-Server-WrongServerID", testType: serverTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeWrongServerID, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":PEER_PAKE_MISMATCH:", expectedLocalError: "remote error: handshake failure", }) testCases = append(testCases, testCase{ // Send a ClientHello with the wrong PAKE codepoint. name: "PAKE-Server-WrongCodepoint", testType: serverTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeWrongCodepoint, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":PEER_PAKE_MISMATCH:", expectedLocalError: "remote error: handshake failure", }) testCases = append(testCases, testCase{ // A server configured with a mix of PAKE and non-PAKE // credentials will select the first that matches what the // client offered. In doing so, it should skip unsupported // PAKE algorithms. name: "PAKE-Server-MultiplePAKEs", testType: serverTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, Bugs: ProtocolBugs{ OfferExtraPAKEs: []uint16{1, 2, 3, 4, 5}, }, }, shimCredentials: []*Credential{&spakeWrongClientID, &spakeWrongServerID, &spakeWrongRole, &spakeCredential, &rsaCertificate}, flags: []string{"-expect-selected-credential", "3"}, }) testCases = append(testCases, testCase{ // A server configured with a certificate credential before a // PAKE credential will consider the certificate credential first. name: "PAKE-Server-CertificateBeforePAKE", testType: serverTest, config: Config{ MinVersion: VersionTLS13, Bugs: ProtocolBugs{ // Pretend to offer a matching PAKE share, but expect the // shim to select the credential first and negotiate a // normal handshake. OfferExtraPAKEClientID: spakeCredential.PAKEClientID, OfferExtraPAKEServerID: spakeCredential.PAKEServerID, OfferExtraPAKEs: []uint16{spakeID}, }, }, shimCredentials: []*Credential{&rsaCertificate, &spakeCredential}, flags: []string{"-expect-selected-credential", "0"}, }) testCases = append(testCases, testCase{ // A server configured with just a PAKE credential should reject normal // clients. name: "PAKE-Server-NormalClient", testType: serverTest, config: Config{ MinVersion: VersionTLS13, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":PEER_PAKE_MISMATCH:", expectedLocalError: "remote error: handshake failure", }) testCases = append(testCases, testCase{ // ... and TLS 1.2 clients. name: "PAKE-Server-NormalTLS12Client", testType: serverTest, config: Config{ MinVersion: VersionTLS12, MaxVersion: VersionTLS12, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":NO_SHARED_CIPHER:", expectedLocalError: "remote error: handshake failure", }) testCases = append(testCases, testCase{ // ... but you can configure a server with both PAKE and certificate-based // SSL_CREDENTIALs and that works. name: "PAKE-ServerWithCertsToo-NormalClient", testType: serverTest, config: Config{ MinVersion: VersionTLS13, }, shimCredentials: []*Credential{&spakeCredential, &rsaCertificate}, flags: []string{"-expect-selected-credential", "1"}, }) testCases = append(testCases, testCase{ // ... and for older clients. name: "PAKE-ServerWithCertsToo-NormalTLS12Client", testType: serverTest, config: Config{ MinVersion: VersionTLS12, MaxVersion: VersionTLS12, }, shimCredentials: []*Credential{&spakeCredential, &rsaCertificate}, flags: []string{"-expect-selected-credential", "1"}, }) testCases = append(testCases, testCase{ name: "PAKE-Client", testType: clientTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, Bugs: ProtocolBugs{ CheckClientHello: func(c *clientHelloMsg) error { // PAKE connections don't use the key_share / supported_groups mechanism. if c.hasKeyShares { return errors.New("unexpected key_share extension") } if len(c.supportedCurves) != 0 { return errors.New("unexpected supported_groups extension") } // PAKE connections don't use signature algorithms. if len(c.signatureAlgorithms) != 0 { return errors.New("unexpected signature_algorithms extension") } // We don't support resumption with PAKEs. if len(c.pskKEModes) != 0 { return errors.New("unexpected psk_key_exchange_modes extension") } return nil }, }, }, shimCredentials: []*Credential{&spakeCredential}, }) testCases = append(testCases, testCase{ // Although there is no reason to request new key shares, the PAKE // client should handle cookie requests. name: "PAKE-Client-HRRCookie", testType: clientTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, Bugs: ProtocolBugs{ SendHelloRetryRequestCookie: []byte("cookie"), }, }, shimCredentials: []*Credential{&spakeCredential}, }) testCases = append(testCases, testCase{ // A PAKE client will not offer key shares, so the client should // reject a HelloRetryRequest requesting a different key share. name: "PAKE-Client-HRRKeyShare", testType: clientTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, Bugs: ProtocolBugs{ SendHelloRetryRequestCurve: CurveX25519, }, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":UNEXPECTED_EXTENSION:", expectedLocalError: "remote error: unsupported extension", }) testCases = append(testCases, testCase{ // A server cannot reply with an HRR asking for a PAKE if the client didn't // offer a PAKE in the ClientHello. name: "PAKE-NormalClient-PAKEInHRR", testType: clientTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, Bugs: ProtocolBugs{ AlwaysSendHelloRetryRequest: true, SendPAKEInHelloRetryRequest: true, }, }, shouldFail: true, expectedError: ":UNEXPECTED_EXTENSION:", }) testCases = append(testCases, testCase{ // A PAKE client should not accept an empty ServerHello. name: "PAKE-Client-EmptyServerHello", testType: clientTest, config: Config{ MinVersion: VersionTLS13, Bugs: ProtocolBugs{ // Trigger an empty ServerHello by making a normal server skip // the key_share extension. MissingKeyShare: true, }, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":MISSING_EXTENSION:", }) testCases = append(testCases, testCase{ // A PAKE client should not accept a key_share ServerHello. name: "PAKE-Client-KeyShareServerHello", testType: clientTest, config: Config{ MinVersion: VersionTLS13, Bugs: ProtocolBugs{ // Trigger a key_share ServerHello by making a normal server // skip the HelloRetryRequest it would otherwise send in // response to the shim's key_share-less ClientHello. SkipHelloRetryRequest: true, // Ignore the client's lack of supported_groups. IgnorePeerCurvePreferences: true, }, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":UNEXPECTED_EXTENSION:", }) testCases = append(testCases, testCase{ // A PAKE client should not accept a TLS 1.2 ServerHello. name: "PAKE-Client-TLS12ServerHello", testType: clientTest, config: Config{ MinVersion: VersionTLS12, MaxVersion: VersionTLS12, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":UNSUPPORTED_PROTOCOL:", }) testCases = append(testCases, testCase{ // A server cannot send the PAKE extension to a non-PAKE client. name: "PAKE-NormalClient-UnsolicitedPAKEInServerHello", testType: clientTest, config: Config{ Bugs: ProtocolBugs{ UnsolicitedPAKE: spakeID, }, }, shouldFail: true, expectedError: ":UNEXPECTED_EXTENSION:", }) testCases = append(testCases, testCase{ // A server cannot reply with a PAKE that the client did not offer. name: "PAKE-Client-WrongPAKEInServerHello", testType: clientTest, config: Config{ Bugs: ProtocolBugs{ UnsolicitedPAKE: 1234, }, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":DECODE_ERROR:", }) testCases = append(testCases, testCase{ name: "PAKE-Extension-Duplicate", testType: serverTest, config: Config{ MinVersion: VersionTLS13, Bugs: ProtocolBugs{ OfferExtraPAKEClientID: []byte("client"), OfferExtraPAKEServerID: []byte("server"), OfferExtraPAKEs: []uint16{1234, 1234}, }, }, shouldFail: true, expectedError: ":ERROR_PARSING_EXTENSION:", }) testCases = append(testCases, testCase{ // If the client sees a server with a wrong password, it should // reject the confirmV value in the ServerHello. name: "PAKE-Client-WrongPassword", testType: clientTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeWrongPassword, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":DECODE_ERROR:", }) testCases = append(testCases, testCase{ name: "PAKE-Client-Truncate", testType: clientTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, Bugs: ProtocolBugs{ TruncatePAKEMessage: true, }, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":DECODE_ERROR:", }) testCases = append(testCases, testCase{ name: "PAKE-Server-Truncate", testType: serverTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, Bugs: ProtocolBugs{ TruncatePAKEMessage: true, }, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":DECODE_ERROR:", expectedLocalError: "remote error: illegal parameter", }) testCases = append(testCases, testCase{ // Servers may not send CertificateRequest in a PAKE handshake. name: "PAKE-Client-UnexpectedCertificateRequest", testType: clientTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, ClientAuth: RequireAnyClientCert, Bugs: ProtocolBugs{ AlwaysSendCertificateRequest: true, }, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":UNEXPECTED_MESSAGE:", expectedLocalError: "remote error: unexpected message", }) testCases = append(testCases, testCase{ // Servers may not send Certificate in a PAKE handshake. name: "PAKE-Client-UnexpectedCertificate", testType: clientTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, Bugs: ProtocolBugs{ AlwaysSendCertificate: true, UseCertificateCredential: &rsaCertificate, // Ignore the client's lack of signature_algorithms. IgnorePeerSignatureAlgorithmPreferences: true, }, }, shimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":UNEXPECTED_MESSAGE:", expectedLocalError: "remote error: unexpected message", }) testCases = append(testCases, testCase{ // If a server is configured to request client certificates, it should // still not do so when negotiating a PAKE. name: "PAKE-Server-DoNotRequestClientCertificate", testType: serverTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, }, shimCredentials: []*Credential{&spakeCredential, &rsaCertificate}, flags: []string{"-require-any-client-certificate"}, }) testCases = append(testCases, testCase{ // Clients should ignore server PAKE credentials. name: "PAKE-Client-WrongRole", testType: clientTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, }, shimCredentials: []*Credential{&spakeWrongRole}, shouldFail: true, // The shim will send a non-PAKE ClientHello. expectedLocalError: "tls: client not configured with PAKE", }) testCases = append(testCases, testCase{ // Servers should ignore client PAKE credentials. name: "PAKE-Server-WrongRole", testType: serverTest, config: Config{ MinVersion: VersionTLS13, Credential: &spakeCredential, }, shimCredentials: []*Credential{&spakeWrongRole}, shouldFail: true, // The shim will fail the handshake because it has no usable credentials // available. expectedError: ":UNKNOWN_CERTIFICATE_TYPE:", expectedLocalError: "remote error: handshake failure", }) testCases = append(testCases, testCase{ // On the client, we only support a single PAKE credential. name: "PAKE-Client-MultiplePAKEs", testType: clientTest, shimCredentials: []*Credential{&spakeCredential, &spakeWrongPassword}, shouldFail: true, expectedError: ":UNSUPPORTED_CREDENTIAL_LIST:", }) testCases = append(testCases, testCase{ // On the client, we only support a single PAKE credential. name: "PAKE-Client-PAKEAndCertificate", testType: clientTest, shimCredentials: []*Credential{&spakeCredential, &rsaCertificate}, shouldFail: true, expectedError: ":UNSUPPORTED_CREDENTIAL_LIST:", }) testCases = append(testCases, testCase{ // We currently do not support resumption with PAKE. Even if configured // with a session, the client should not offer the session with PAKEs. name: "PAKE-Client-NoResume", testType: clientTest, // Make two connections. For the first connection, just establish a // session without PAKE, to pick up a session. config: Config{ Credential: &rsaCertificate, }, // For the second connection, use SPAKE. resumeSession: true, resumeConfig: &Config{ Credential: &spakeCredential, Bugs: ProtocolBugs{ // Check that the ClientHello does not offer a session, even // though one was configured. ExpectNoTLS13PSK: true, // Respond with an unsolicted PSK extension in ServerHello, to // check that the client rejects it. AlwaysSelectPSKIdentity: true, }, }, resumeShimCredentials: []*Credential{&spakeCredential}, shouldFail: true, expectedError: ":UNEXPECTED_EXTENSION:", }) }