mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-02-26 16:57:08 +00:00
chore: fingerprint verifier handle non-leaf certificate will check the SNI matches the certificate's DNS name
This commit is contained in:
@@ -98,10 +98,13 @@ func GetTLSConfig(opt Option) (tlsConfig *tls.Config, err error) {
|
||||
}
|
||||
|
||||
if len(opt.Fingerprint) > 0 {
|
||||
tlsConfig.VerifyPeerCertificate, err = NewFingerprintVerifier(opt.Fingerprint, tlsConfig.Time)
|
||||
verifier, err := NewFingerprintVerifier(opt.Fingerprint, tlsConfig.Time)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.VerifyConnection = func(state tls.ConnectionState) error {
|
||||
return verifier(state.PeerCertificates, state.ServerName)
|
||||
}
|
||||
tlsConfig.InsecureSkipVerify = true
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
)
|
||||
|
||||
// NewFingerprintVerifier returns a function that verifies whether a certificate's SHA-256 fingerprint matches the given one.
|
||||
func NewFingerprintVerifier(fingerprint string, time func() time.Time) (func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error, error) {
|
||||
func NewFingerprintVerifier(fingerprint string, time func() time.Time) (func(certs []*x509.Certificate, serverName string) error, error) {
|
||||
switch fingerprint {
|
||||
case "chrome", "firefox", "safari", "ios", "android", "edge", "360", "qq", "random", "randomized": // WTF???
|
||||
return nil, fmt.Errorf("`fingerprint` is used for TLS certificate pinning. If you need to specify the browser fingerprint, use `client-fingerprint`")
|
||||
@@ -26,37 +26,24 @@ func NewFingerprintVerifier(fingerprint string, time func() time.Time) (func(raw
|
||||
return nil, fmt.Errorf("fingerprint string length error,need sha256 fingerprint")
|
||||
}
|
||||
|
||||
return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
||||
return func(certs []*x509.Certificate, serverName string) error {
|
||||
// ssl pining
|
||||
for i, rawCert := range rawCerts {
|
||||
hash := sha256.Sum256(rawCert)
|
||||
for i, cert := range certs {
|
||||
hash := sha256.Sum256(cert.Raw)
|
||||
if bytes.Equal(fpByte, hash[:]) {
|
||||
if i > 0 {
|
||||
|
||||
// When the fingerprint matches a non-leaf certificate,
|
||||
// the certificate chain validity is verified using the certificate as the trusted root certificate.
|
||||
//
|
||||
// Currently, we do not verify that the SNI matches the certificate's DNS name,
|
||||
// but we do verify the validity of the child certificate,
|
||||
// including the issuance time and whether the child certificate was issued by the parent certificate.
|
||||
|
||||
certs := make([]*x509.Certificate, i+1) // stop at i
|
||||
for j := range certs {
|
||||
cert, err := x509.ParseCertificate(rawCerts[j])
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
certs[j] = cert
|
||||
}
|
||||
opts := x509.VerifyOptions{
|
||||
Roots: x509.NewCertPool(),
|
||||
Intermediates: x509.NewCertPool(),
|
||||
DNSName: serverName,
|
||||
}
|
||||
if time != nil {
|
||||
opts.CurrentTime = time()
|
||||
}
|
||||
opts.Roots.AddCert(certs[i])
|
||||
for _, cert := range certs[1:] {
|
||||
for _, cert := range certs[1 : i+1] { // stop at i
|
||||
opts.Intermediates.AddCert(cert)
|
||||
}
|
||||
_, err := certs[0].Verify(opts)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package ca
|
||||
|
||||
import (
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"testing"
|
||||
"time"
|
||||
@@ -10,90 +11,203 @@ import (
|
||||
)
|
||||
|
||||
func TestFingerprintVerifierLeaf(t *testing.T) {
|
||||
leafFingerprint := CalculateFingerprint(leafPEM.Bytes)
|
||||
verifier, err := NewFingerprintVerifier(leafFingerprint, func() time.Time {
|
||||
return time.Unix(1677615892, 0)
|
||||
})
|
||||
leafFingerprint := CalculateFingerprint(leafCert.Raw)
|
||||
verifier, err := NewFingerprintVerifier(leafFingerprint, certTime)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = verifier([][]byte{leafPEM.Bytes, intermediatePEM.Bytes, rootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, rootCert}, "")
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([][]byte{leafPEM.Bytes, smimeIntermediatePEM.Bytes, rootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, rootCert}, leafServerName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([][]byte{leafPEM.Bytes, intermediatePEM.Bytes, smimeRootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, rootCert}, wrongLeafServerName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([][]byte{leafWithInvalidHashPEM.Bytes, intermediatePEM.Bytes, rootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, smimeIntermediateCert, rootCert}, "")
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafCert, smimeIntermediateCert, rootCert}, leafServerName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafCert, smimeIntermediateCert, rootCert}, wrongLeafServerName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, smimeRootCert}, "")
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, smimeRootCert}, leafServerName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, smimeRootCert}, wrongLeafServerName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafWithInvalidHashCert, intermediateCert, rootCert}, "")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([][]byte{smimeLeafPEM.Bytes, intermediatePEM.Bytes, rootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafWithInvalidHashCert, intermediateCert, rootCert}, leafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([][]byte{smimeLeafPEM.Bytes, intermediatePEM.Bytes, smimeRootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafWithInvalidHashCert, intermediateCert, rootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, rootCert}, "")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, rootCert}, leafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, rootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, smimeRootCert}, "")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, smimeRootCert}, leafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, smimeRootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestFingerprintVerifierIntermediate(t *testing.T) {
|
||||
intermediateFingerprint := CalculateFingerprint(intermediatePEM.Bytes)
|
||||
verifier, err := NewFingerprintVerifier(intermediateFingerprint, func() time.Time {
|
||||
return time.Unix(1677615892, 0)
|
||||
})
|
||||
intermediateFingerprint := CalculateFingerprint(intermediateCert.Raw)
|
||||
verifier, err := NewFingerprintVerifier(intermediateFingerprint, certTime)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = verifier([][]byte{leafPEM.Bytes, intermediatePEM.Bytes, rootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, rootCert}, "")
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([][]byte{leafPEM.Bytes, smimeIntermediatePEM.Bytes, rootPEM.Bytes}, nil)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([][]byte{leafPEM.Bytes, intermediatePEM.Bytes, smimeRootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, rootCert}, leafServerName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([][]byte{leafWithInvalidHashPEM.Bytes, intermediatePEM.Bytes, rootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, rootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([][]byte{smimeLeafPEM.Bytes, intermediatePEM.Bytes, rootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, smimeIntermediateCert, rootCert}, "")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([][]byte{smimeLeafPEM.Bytes, intermediatePEM.Bytes, smimeRootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, smimeIntermediateCert, rootCert}, leafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafCert, smimeIntermediateCert, rootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, smimeRootCert}, "")
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, smimeRootCert}, leafServerName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, smimeRootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafWithInvalidHashCert, intermediateCert, rootCert}, "")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafWithInvalidHashCert, intermediateCert, rootCert}, leafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafWithInvalidHashCert, intermediateCert, rootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, rootCert}, "")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, rootCert}, leafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, rootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, smimeRootCert}, "")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, smimeRootCert}, leafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, smimeRootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestFingerprintVerifierRoot(t *testing.T) {
|
||||
rootFingerprint := CalculateFingerprint(rootPEM.Bytes)
|
||||
verifier, err := NewFingerprintVerifier(rootFingerprint, func() time.Time {
|
||||
return time.Unix(1677615892, 0)
|
||||
})
|
||||
rootFingerprint := CalculateFingerprint(rootCert.Raw)
|
||||
verifier, err := NewFingerprintVerifier(rootFingerprint, certTime)
|
||||
require.NoError(t, err)
|
||||
|
||||
err = verifier([][]byte{leafPEM.Bytes, intermediatePEM.Bytes, rootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, rootCert}, "")
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([][]byte{leafPEM.Bytes, smimeIntermediatePEM.Bytes, rootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, rootCert}, leafServerName)
|
||||
assert.NoError(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, rootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([][]byte{leafPEM.Bytes, intermediatePEM.Bytes, smimeRootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, smimeIntermediateCert, rootCert}, "")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([][]byte{leafWithInvalidHashPEM.Bytes, intermediatePEM.Bytes, rootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, smimeIntermediateCert, rootCert}, leafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([][]byte{smimeLeafPEM.Bytes, intermediatePEM.Bytes, rootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, smimeIntermediateCert, rootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([][]byte{smimeLeafPEM.Bytes, intermediatePEM.Bytes, smimeRootPEM.Bytes}, nil)
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, smimeRootCert}, "")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, smimeRootCert}, leafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafCert, intermediateCert, smimeRootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafWithInvalidHashCert, intermediateCert, rootCert}, "")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafWithInvalidHashCert, intermediateCert, rootCert}, leafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{leafWithInvalidHashCert, intermediateCert, rootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, rootCert}, "")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, rootCert}, leafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, rootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, smimeRootCert}, "")
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, smimeRootCert}, leafServerName)
|
||||
assert.Error(t, err)
|
||||
|
||||
err = verifier([]*x509.Certificate{smimeLeafCert, intermediateCert, smimeRootCert}, wrongLeafServerName)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
var rootPEM, _ = pem.Decode([]byte(gtsRoot))
|
||||
var rootCert, _ = x509.ParseCertificate(rootPEM.Bytes)
|
||||
var intermediatePEM, _ = pem.Decode([]byte(gtsIntermediate))
|
||||
var intermediateCert, _ = x509.ParseCertificate(intermediatePEM.Bytes)
|
||||
var leafPEM, _ = pem.Decode([]byte(googleLeaf))
|
||||
var leafCert, _ = x509.ParseCertificate(leafPEM.Bytes)
|
||||
var leafWithInvalidHashPEM, _ = pem.Decode([]byte(googleLeafWithInvalidHash))
|
||||
var leafWithInvalidHashCert, _ = x509.ParseCertificate(leafWithInvalidHashPEM.Bytes)
|
||||
var smimeRootPEM, _ = pem.Decode([]byte(smimeRoot))
|
||||
var smimeRootCert, _ = x509.ParseCertificate(smimeRootPEM.Bytes)
|
||||
var smimeIntermediatePEM, _ = pem.Decode([]byte(smimeIntermediate))
|
||||
var smimeIntermediateCert, _ = x509.ParseCertificate(smimeIntermediatePEM.Bytes)
|
||||
var smimeLeafPEM, _ = pem.Decode([]byte(smimeLeaf))
|
||||
var smimeLeafCert, _ = x509.ParseCertificate(smimeLeafPEM.Bytes)
|
||||
var certTime = func() time.Time { return time.Unix(1677615892, 0) }
|
||||
|
||||
const leafServerName = "www.google.com"
|
||||
const wrongLeafServerName = "www.google.com.cn"
|
||||
|
||||
const gtsIntermediate = `-----BEGIN CERTIFICATE-----
|
||||
MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw
|
||||
|
||||
Reference in New Issue
Block a user