mirror of
https://github.com/MetaCubeX/mihomo.git
synced 2026-02-27 01:07:10 +00:00
chore: using tls.Config.GetCertificate/GetClientCertificate to load TLS certificates
This commit is contained in:
@@ -107,12 +107,13 @@ func GetTLSConfig(opt Option) (tlsConfig *tls.Config, err error) {
|
||||
}
|
||||
|
||||
if len(opt.Certificate) > 0 || len(opt.PrivateKey) > 0 {
|
||||
var cert tls.Certificate
|
||||
cert, err = LoadTLSKeyPair(opt.Certificate, opt.PrivateKey, C.Path)
|
||||
certLoader, err := NewTLSKeyPairLoader(opt.Certificate, opt.PrivateKey, C.Path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
tlsConfig.Certificates = []tls.Certificate{cert}
|
||||
tlsConfig.GetClientCertificate = func(*tls.CertificateRequestInfo) (*tls.Certificate, error) {
|
||||
return certLoader()
|
||||
}
|
||||
}
|
||||
return tlsConfig, nil
|
||||
}
|
||||
|
||||
@@ -23,24 +23,25 @@ type Path interface {
|
||||
ErrNotSafePath(path string) error
|
||||
}
|
||||
|
||||
// LoadTLSKeyPair loads a TLS key pair from the provided certificate and private key data or file paths, supporting fallback resolution.
|
||||
// Returns a tls.Certificate and an error, where the error indicates issues during parsing or file loading.
|
||||
// NewTLSKeyPairLoader creates a loader function for TLS key pairs from the provided certificate and private key data or file paths.
|
||||
// If both certificate and privateKey are empty, generates a random TLS RSA key pair.
|
||||
// Accepts a Path interface for resolving file paths when necessary.
|
||||
func LoadTLSKeyPair(certificate, privateKey string, path Path) (tls.Certificate, error) {
|
||||
func NewTLSKeyPairLoader(certificate, privateKey string, path Path) (func() (*tls.Certificate, error), error) {
|
||||
if certificate == "" && privateKey == "" {
|
||||
var err error
|
||||
certificate, privateKey, _, err = NewRandomTLSKeyPair(KeyPairTypeRSA)
|
||||
if err != nil {
|
||||
return tls.Certificate{}, err
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
cert, painTextErr := tls.X509KeyPair([]byte(certificate), []byte(privateKey))
|
||||
if painTextErr == nil {
|
||||
return cert, nil
|
||||
return func() (*tls.Certificate, error) {
|
||||
return &cert, nil
|
||||
}, nil
|
||||
}
|
||||
if path == nil {
|
||||
return tls.Certificate{}, painTextErr
|
||||
return nil, painTextErr
|
||||
}
|
||||
|
||||
certificate = path.Resolve(certificate)
|
||||
@@ -54,9 +55,11 @@ func LoadTLSKeyPair(certificate, privateKey string, path Path) (tls.Certificate,
|
||||
cert, loadErr = tls.LoadX509KeyPair(certificate, privateKey)
|
||||
}
|
||||
if loadErr != nil {
|
||||
return tls.Certificate{}, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error())
|
||||
return nil, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error())
|
||||
}
|
||||
return cert, nil
|
||||
return func() (*tls.Certificate, error) {
|
||||
return &cert, nil
|
||||
}, nil
|
||||
}
|
||||
|
||||
func LoadCertificates(certificate string, path Path) (*x509.CertPool, error) {
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package tls
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net"
|
||||
"reflect"
|
||||
"unsafe"
|
||||
|
||||
"github.com/metacubex/mihomo/common/once"
|
||||
"github.com/metacubex/mihomo/common/utils"
|
||||
@@ -126,8 +129,11 @@ type EncryptedClientHelloKey = utls.EncryptedClientHelloKey
|
||||
|
||||
type Config = utls.Config
|
||||
|
||||
var tlsCertificateRequestInfoCtxOffset = utils.MustOK(reflect.TypeOf((*tls.CertificateRequestInfo)(nil)).Elem().FieldByName("ctx")).Offset
|
||||
var tlsClientHelloInfoCtxOffset = utils.MustOK(reflect.TypeOf((*tls.ClientHelloInfo)(nil)).Elem().FieldByName("ctx")).Offset
|
||||
|
||||
func UConfig(config *tls.Config) *utls.Config {
|
||||
return &utls.Config{
|
||||
cfg := &utls.Config{
|
||||
Rand: config.Rand,
|
||||
Time: config.Time,
|
||||
Certificates: utils.Map(config.Certificates, UCertificate),
|
||||
@@ -147,6 +153,52 @@ func UConfig(config *tls.Config) *utls.Config {
|
||||
SessionTicketsDisabled: config.SessionTicketsDisabled,
|
||||
Renegotiation: utls.RenegotiationSupport(config.Renegotiation),
|
||||
}
|
||||
if config.GetClientCertificate != nil {
|
||||
cfg.GetClientCertificate = func(info *utls.CertificateRequestInfo) (*utls.Certificate, error) {
|
||||
tlsInfo := &tls.CertificateRequestInfo{
|
||||
AcceptableCAs: info.AcceptableCAs,
|
||||
SignatureSchemes: utils.Map(info.SignatureSchemes, func(it utls.SignatureScheme) tls.SignatureScheme {
|
||||
return tls.SignatureScheme(it)
|
||||
}),
|
||||
Version: info.Version,
|
||||
}
|
||||
*(*context.Context)(unsafe.Add(unsafe.Pointer(tlsInfo), tlsCertificateRequestInfoCtxOffset)) = info.Context() // for tlsInfo.ctx
|
||||
cert, err := config.GetClientCertificate(tlsInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uCert := UCertificate(*cert)
|
||||
return &uCert, err
|
||||
}
|
||||
}
|
||||
if config.GetCertificate != nil {
|
||||
cfg.GetCertificate = func(info *utls.ClientHelloInfo) (*utls.Certificate, error) {
|
||||
tlsInfo := &tls.ClientHelloInfo{
|
||||
CipherSuites: info.CipherSuites,
|
||||
ServerName: info.ServerName,
|
||||
SupportedCurves: utils.Map(info.SupportedCurves, func(it utls.CurveID) tls.CurveID {
|
||||
return tls.CurveID(it)
|
||||
}),
|
||||
SupportedPoints: info.SupportedPoints,
|
||||
SignatureSchemes: utils.Map(info.SignatureSchemes, func(it utls.SignatureScheme) tls.SignatureScheme {
|
||||
return tls.SignatureScheme(it)
|
||||
}),
|
||||
SupportedProtos: info.SupportedProtos,
|
||||
SupportedVersions: info.SupportedVersions,
|
||||
Extensions: info.Extensions,
|
||||
Conn: info.Conn,
|
||||
//HelloRetryRequest: info.HelloRetryRequest,
|
||||
}
|
||||
*(*context.Context)(unsafe.Add(unsafe.Pointer(tlsInfo), tlsClientHelloInfoCtxOffset)) = info.Context() // for tlsInfo.ctx
|
||||
cert, err := config.GetCertificate(tlsInfo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
uCert := UCertificate(*cert)
|
||||
return &uCert, err
|
||||
}
|
||||
}
|
||||
return cfg
|
||||
}
|
||||
|
||||
// BuildWebsocketHandshakeState it will only send http/1.1 in its ALPN.
|
||||
|
||||
Reference in New Issue
Block a user