Clash.Meta/component/ca/config.go

135 lines
3.1 KiB
Go
Raw Normal View History

2023-09-22 14:45:34 +08:00
package ca
2022-07-10 20:44:24 +08:00
import (
"crypto/tls"
"crypto/x509"
2024-03-28 19:26:41 +08:00
_ "embed"
"errors"
2022-07-10 20:44:24 +08:00
"fmt"
2023-09-22 14:45:34 +08:00
"os"
2024-03-28 19:26:41 +08:00
"strconv"
2022-07-10 20:44:24 +08:00
"sync"
2024-04-20 22:22:17 +08:00
C "github.com/metacubex/mihomo/constant"
2022-07-10 20:44:24 +08:00
)
2023-09-22 14:45:34 +08:00
var globalCertPool *x509.CertPool
var mutex sync.RWMutex
var errNotMatch = errors.New("certificate fingerprints do not match")
2022-07-10 20:44:24 +08:00
2024-03-28 19:26:41 +08:00
//go:embed ca-certificates.crt
var _CaCertificates []byte
var DisableEmbedCa, _ = strconv.ParseBool(os.Getenv("DISABLE_EMBED_CA"))
var DisableSystemCa, _ = strconv.ParseBool(os.Getenv("DISABLE_SYSTEM_CA"))
2023-02-25 22:01:20 +08:00
func AddCertificate(certificate string) error {
mutex.Lock()
defer mutex.Unlock()
2023-02-25 22:01:20 +08:00
if certificate == "" {
return fmt.Errorf("certificate is empty")
}
if globalCertPool == nil {
initializeCertPool()
}
if globalCertPool.AppendCertsFromPEM([]byte(certificate)) {
return nil
} else if cert, err := x509.ParseCertificate([]byte(certificate)); err == nil {
globalCertPool.AddCert(cert)
2023-03-27 22:27:59 +08:00
return nil
} else {
2023-02-25 22:01:20 +08:00
return fmt.Errorf("add certificate failed")
}
}
func initializeCertPool() {
var err error
2024-03-28 19:26:41 +08:00
if DisableSystemCa {
2023-09-22 14:45:34 +08:00
globalCertPool = x509.NewCertPool()
2024-03-28 19:26:41 +08:00
} else {
globalCertPool, err = x509.SystemCertPool()
if err != nil {
globalCertPool = x509.NewCertPool()
}
}
2024-03-28 19:26:41 +08:00
if !DisableEmbedCa {
globalCertPool.AppendCertsFromPEM(_CaCertificates)
}
}
2023-02-26 20:38:32 +08:00
func ResetCertificate() {
2023-02-25 22:01:20 +08:00
mutex.Lock()
defer mutex.Unlock()
initializeCertPool()
2023-03-27 22:27:59 +08:00
}
func getCertPool() *x509.CertPool {
2023-09-22 14:45:34 +08:00
if globalCertPool == nil {
mutex.Lock()
defer mutex.Unlock()
2023-09-22 14:45:34 +08:00
if globalCertPool != nil {
return globalCertPool
}
initializeCertPool()
2023-03-27 22:27:59 +08:00
}
2023-09-22 14:45:34 +08:00
return globalCertPool
}
2025-04-21 12:07:33 +08:00
func GetCertPool(customCA string, customCAString string) (*x509.CertPool, error) {
2023-09-22 14:45:34 +08:00
var certificate []byte
var err error
if len(customCA) > 0 {
2025-04-30 23:21:13 +08:00
path := C.Path.Resolve(customCA)
if !C.Path.IsSafePath(path) {
return nil, fmt.Errorf("path is not subpath of home directory: %s", path)
}
certificate, err = os.ReadFile(path)
2023-09-22 14:45:34 +08:00
if err != nil {
return nil, fmt.Errorf("load ca error: %w", err)
}
} else if customCAString != "" {
certificate = []byte(customCAString)
}
if len(certificate) > 0 {
certPool := x509.NewCertPool()
if !certPool.AppendCertsFromPEM(certificate) {
return nil, fmt.Errorf("failed to parse certificate:\n\n %s", certificate)
}
2025-04-21 12:07:33 +08:00
return certPool, nil
} else {
2025-04-21 12:07:33 +08:00
return getCertPool(), nil
}
}
// GetTLSConfig specified fingerprint, customCA and customCAString
func GetTLSConfig(tlsConfig *tls.Config, fingerprint string, customCA string, customCAString string) (_ *tls.Config, err error) {
if tlsConfig == nil {
tlsConfig = &tls.Config{}
}
tlsConfig.RootCAs, err = GetCertPool(customCA, customCAString)
if err != nil {
return nil, err
}
2023-09-22 14:45:34 +08:00
if len(fingerprint) > 0 {
2025-04-21 12:07:33 +08:00
tlsConfig.VerifyPeerCertificate, err = NewFingerprintVerifier(fingerprint)
2023-09-22 14:45:34 +08:00
if err != nil {
return nil, err
}
tlsConfig.InsecureSkipVerify = true
}
2023-09-22 14:45:34 +08:00
return tlsConfig, nil
}
// GetSpecifiedFingerprintTLSConfig specified fingerprint
func GetSpecifiedFingerprintTLSConfig(tlsConfig *tls.Config, fingerprint string) (*tls.Config, error) {
return GetTLSConfig(tlsConfig, fingerprint, "", "")
2022-07-10 20:44:24 +08:00
}
func GetGlobalTLSConfig(tlsConfig *tls.Config) *tls.Config {
2023-09-22 14:45:34 +08:00
tlsConfig, _ = GetTLSConfig(tlsConfig, "", "", "")
2022-07-10 20:44:24 +08:00
return tlsConfig
}