blob: ddd2eb343d30a88ec5ebe4cd31e7a8e916d0bc10 [file] [log] [blame]
// 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:",
})
}