feat: add mTLS support for client & server

`certificate` and `private-key` for proxies
`client-auth-type` and `client-auth-cert` for listeners
This commit is contained in:
wwqgtxx
2025-09-20 00:19:07 +08:00
parent 40b2cde2b2
commit 0dc5e3051d
54 changed files with 763 additions and 323 deletions

View File

@@ -11,6 +11,7 @@ import (
"sync"
"github.com/metacubex/mihomo/common/once"
C "github.com/metacubex/mihomo/constant"
"github.com/metacubex/mihomo/ntp"
)
@@ -79,6 +80,8 @@ type Option struct {
TLSConfig *tls.Config
Fingerprint string
ZeroTrust bool
Certificate string
PrivateKey string
}
func GetTLSConfig(opt Option) (tlsConfig *tls.Config, err error) {
@@ -101,6 +104,15 @@ func GetTLSConfig(opt Option) (tlsConfig *tls.Config, err error) {
}
tlsConfig.InsecureSkipVerify = true
}
if len(opt.Certificate) > 0 || len(opt.PrivateKey) > 0 {
var cert tls.Certificate
cert, err = LoadTLSKeyPair(opt.Certificate, opt.PrivateKey, C.Path)
if err != nil {
return nil, err
}
tlsConfig.Certificates = []tls.Certificate{cert}
}
return tlsConfig, nil
}

View File

@@ -12,6 +12,8 @@ import (
"encoding/pem"
"fmt"
"math/big"
"os"
"time"
)
type Path interface {
@@ -56,6 +58,33 @@ func LoadTLSKeyPair(certificate, privateKey string, path Path) (tls.Certificate,
return cert, nil
}
func LoadCertificates(certificate string, path Path) (*x509.CertPool, error) {
pool := x509.NewCertPool()
if pool.AppendCertsFromPEM([]byte(certificate)) {
return pool, nil
}
painTextErr := fmt.Errorf("invalid certificate: %s", certificate)
if path == nil {
return nil, painTextErr
}
certificate = path.Resolve(certificate)
var loadErr error
if !path.IsSafePath(certificate) {
loadErr = path.ErrNotSafePath(certificate)
} else {
certPEMBlock, err := os.ReadFile(certificate)
if pool.AppendCertsFromPEM(certPEMBlock) {
return pool, nil
}
loadErr = err
}
if loadErr != nil {
return nil, fmt.Errorf("parse certificate failed, maybe format error:%s, or path error: %s", painTextErr.Error(), loadErr.Error())
}
return pool, nil
}
type KeyPairType string
const (
@@ -85,7 +114,11 @@ func NewRandomTLSKeyPair(keyPairType KeyPairType) (certificate string, privateKe
return
}
template := x509.Certificate{SerialNumber: big.NewInt(1)}
template := x509.Certificate{
SerialNumber: big.NewInt(1),
NotBefore: time.Now().Add(-time.Hour * 24 * 365),
NotAfter: time.Now().Add(time.Hour * 24 * 365),
}
certDER, err := x509.CreateCertificate(rand.Reader, &template, &template, key.Public(), key)
if err != nil {
return