Based on Nekogram. Key additions: - Rebrand to FoxiGram (app name, APK name, applicationId com.foxigram.app) - Embedded Xray (VLESS+Reality) proxy client via JNI libxray.so - Bundled hidden one-tap proxies (LTE + WiFi), read-only in UI - Auto-restore proxy on restart, rebind to active network (LTE/WiFi) - Server credentials externalized to git-ignored XrayServers.java (+ template) - libxray Go source included; compiled .so, keystore, google-services.json ignored
513 lines
17 KiB
Go
513 lines
17 KiB
Go
// Copyright 2025 The BoringSSL Authors
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// https://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
package runner
|
|
|
|
import "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:",
|
|
})
|
|
}
|