mihomo/component/tls/config.go
3andero 804cff8c55
fix: skip-cert-verify is true by default (#333)
* fix: skip-cert-verify is true by default

* fix: format

* fix: typo

Co-authored-by: 3andero <3andero@github.com>
Co-authored-by: Hellojack <106379370+H1JK@users.noreply.github.com>
2023-01-13 09:55:01 +08:00

146 lines
4.2 KiB
Go

package tls
import (
"bytes"
"crypto/sha256"
"crypto/tls"
"crypto/x509"
"encoding/hex"
"fmt"
"sync"
"time"
xtls "github.com/xtls/go"
)
var globalFingerprints = make([][32]byte, 0)
var mutex sync.Mutex
func verifyPeerCertificateAndFingerprints(fingerprints *[][32]byte, insecureSkipVerify bool) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
if insecureSkipVerify {
return nil
}
var preErr error
for i := range rawCerts {
rawCert := rawCerts[i]
cert, err := x509.ParseCertificate(rawCert)
if err == nil {
opts := x509.VerifyOptions{
CurrentTime: time.Now(),
}
if _, err := cert.Verify(opts); err == nil {
return nil
} else {
fingerprint := sha256.Sum256(cert.Raw)
for _, fp := range *fingerprints {
if bytes.Equal(fingerprint[:], fp[:]) {
return nil
}
}
preErr = err
}
}
}
return preErr
}
}
func AddCertFingerprint(fingerprint string) error {
fpByte, err2 := convertFingerprint(fingerprint)
if err2 != nil {
return err2
}
mutex.Lock()
globalFingerprints = append(globalFingerprints, *fpByte)
mutex.Unlock()
return nil
}
func convertFingerprint(fingerprint string) (*[32]byte, error) {
fpByte, err := hex.DecodeString(fingerprint)
if err != nil {
return nil, err
}
if len(fpByte) != 32 {
return nil, fmt.Errorf("fingerprint string length error,need sha25 fingerprint")
}
return (*[32]byte)(fpByte), nil
}
func GetDefaultTLSConfig() *tls.Config {
return GetGlobalFingerprintTLSConfig(nil)
}
// GetSpecifiedFingerprintTLSConfig specified fingerprint
func GetSpecifiedFingerprintTLSConfig(tlsConfig *tls.Config, fingerprint string) (*tls.Config, error) {
if fingerprintBytes, err := convertFingerprint(fingerprint); err != nil {
return nil, err
} else {
if tlsConfig == nil {
return &tls.Config{
InsecureSkipVerify: true,
VerifyPeerCertificate: verifyPeerCertificateAndFingerprints(&[][32]byte{*fingerprintBytes}, false),
}, nil
} else {
tlsConfig.VerifyPeerCertificate = verifyPeerCertificateAndFingerprints(&[][32]byte{*fingerprintBytes}, tlsConfig.InsecureSkipVerify)
tlsConfig.InsecureSkipVerify = true
return tlsConfig, nil
}
}
}
func GetGlobalFingerprintTLSConfig(tlsConfig *tls.Config) *tls.Config {
// If there's at least one fingerprint then we could skip the general check
// If there's no fingerprints but the config insists then we should skip.
// Otherwise we should do a general verification.
shouldSkipVerify := len(globalFingerprints) != 0 || tlsConfig != nil && tlsConfig.InsecureSkipVerify
if tlsConfig == nil {
return &tls.Config{
InsecureSkipVerify: shouldSkipVerify,
VerifyPeerCertificate: verifyPeerCertificateAndFingerprints(&globalFingerprints, false),
}
}
tlsConfig.VerifyPeerCertificate = verifyPeerCertificateAndFingerprints(&globalFingerprints, tlsConfig.InsecureSkipVerify)
tlsConfig.InsecureSkipVerify = shouldSkipVerify
return tlsConfig
}
// GetSpecifiedFingerprintXTLSConfig specified fingerprint
func GetSpecifiedFingerprintXTLSConfig(tlsConfig *xtls.Config, fingerprint string) (*xtls.Config, error) {
if fingerprintBytes, err := convertFingerprint(fingerprint); err != nil {
return nil, err
} else {
if tlsConfig == nil {
return &xtls.Config{
InsecureSkipVerify: true,
VerifyPeerCertificate: verifyPeerCertificateAndFingerprints(&[][32]byte{*fingerprintBytes}, false),
}, nil
} else {
tlsConfig.VerifyPeerCertificate = verifyPeerCertificateAndFingerprints(&[][32]byte{*fingerprintBytes}, tlsConfig.InsecureSkipVerify)
tlsConfig.InsecureSkipVerify = true
return tlsConfig, nil
}
}
}
func GetGlobalFingerprintXTLSConfig(tlsConfig *xtls.Config) *xtls.Config {
shouldSkipVerify := len(globalFingerprints) != 0 || tlsConfig != nil && tlsConfig.InsecureSkipVerify
if tlsConfig == nil {
return &xtls.Config{
InsecureSkipVerify: shouldSkipVerify,
VerifyPeerCertificate: verifyPeerCertificateAndFingerprints(&globalFingerprints, false),
}
}
tlsConfig.VerifyPeerCertificate = verifyPeerCertificateAndFingerprints(&globalFingerprints, tlsConfig.InsecureSkipVerify)
tlsConfig.InsecureSkipVerify = shouldSkipVerify
return tlsConfig
}