2022-07-10 12:44:24 +00:00
|
|
|
package tls
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bytes"
|
|
|
|
"crypto/sha256"
|
|
|
|
"crypto/tls"
|
|
|
|
"crypto/x509"
|
|
|
|
"encoding/hex"
|
2023-01-14 13:08:06 +00:00
|
|
|
"errors"
|
2022-07-10 12:44:24 +00:00
|
|
|
"fmt"
|
2023-01-14 13:08:06 +00:00
|
|
|
"strings"
|
2022-07-10 12:44:24 +00:00
|
|
|
"sync"
|
|
|
|
)
|
|
|
|
|
2023-03-27 14:27:59 +00:00
|
|
|
var trustCerts []*x509.Certificate
|
2023-04-01 03:53:39 +00:00
|
|
|
var certPool *x509.CertPool
|
2023-01-14 13:08:06 +00:00
|
|
|
var mutex sync.RWMutex
|
2023-06-04 03:51:30 +00:00
|
|
|
var errNotMatch = errors.New("certificate fingerprints do not match")
|
2022-07-10 12:44:24 +00:00
|
|
|
|
2023-02-25 14:01:20 +00:00
|
|
|
func AddCertificate(certificate string) error {
|
2023-01-14 13:08:06 +00:00
|
|
|
mutex.Lock()
|
|
|
|
defer mutex.Unlock()
|
2023-02-25 14:01:20 +00:00
|
|
|
if certificate == "" {
|
|
|
|
return fmt.Errorf("certificate is empty")
|
|
|
|
}
|
2023-03-27 14:27:59 +00:00
|
|
|
if cert, err := x509.ParseCertificate([]byte(certificate)); err == nil {
|
|
|
|
trustCerts = append(trustCerts, cert)
|
|
|
|
return nil
|
|
|
|
} else {
|
2023-02-25 14:01:20 +00:00
|
|
|
return fmt.Errorf("add certificate failed")
|
2023-01-14 13:08:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-05-13 16:21:59 +00:00
|
|
|
func initializeCertPool() {
|
|
|
|
var err error
|
|
|
|
certPool, err = x509.SystemCertPool()
|
|
|
|
if err != nil {
|
|
|
|
certPool = x509.NewCertPool()
|
|
|
|
}
|
|
|
|
for _, cert := range trustCerts {
|
|
|
|
certPool.AddCert(cert)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-26 12:38:32 +00:00
|
|
|
func ResetCertificate() {
|
2023-02-25 14:01:20 +00:00
|
|
|
mutex.Lock()
|
|
|
|
defer mutex.Unlock()
|
2023-03-27 14:27:59 +00:00
|
|
|
trustCerts = nil
|
2023-05-13 16:21:59 +00:00
|
|
|
initializeCertPool()
|
2023-03-27 14:27:59 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func getCertPool() *x509.CertPool {
|
2023-04-01 03:53:39 +00:00
|
|
|
if len(trustCerts) == 0 {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
if certPool == nil {
|
|
|
|
mutex.Lock()
|
|
|
|
defer mutex.Unlock()
|
|
|
|
if certPool != nil {
|
|
|
|
return certPool
|
|
|
|
}
|
2023-05-13 16:21:59 +00:00
|
|
|
initializeCertPool()
|
2023-03-27 14:27:59 +00:00
|
|
|
}
|
|
|
|
return certPool
|
2023-01-14 13:08:06 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func verifyFingerprint(fingerprint *[32]byte) func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
|
|
|
return func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
|
|
|
|
// ssl pining
|
2022-07-10 13:56:33 +00:00
|
|
|
for i := range rawCerts {
|
|
|
|
rawCert := rawCerts[i]
|
|
|
|
cert, err := x509.ParseCertificate(rawCert)
|
|
|
|
if err == nil {
|
2023-01-14 13:08:06 +00:00
|
|
|
hash := sha256.Sum256(cert.Raw)
|
|
|
|
if bytes.Equal(fingerprint[:], hash[:]) {
|
2022-07-10 13:56:33 +00:00
|
|
|
return nil
|
|
|
|
}
|
2022-07-10 12:44:24 +00:00
|
|
|
}
|
|
|
|
}
|
2023-06-04 03:51:30 +00:00
|
|
|
return errNotMatch
|
2022-07-10 13:56:33 +00:00
|
|
|
}
|
2022-07-10 12:44:24 +00:00
|
|
|
}
|
|
|
|
|
2022-07-10 13:56:33 +00:00
|
|
|
func convertFingerprint(fingerprint string) (*[32]byte, error) {
|
2023-01-14 13:08:06 +00:00
|
|
|
fingerprint = strings.TrimSpace(strings.Replace(fingerprint, ":", "", -1))
|
2022-07-11 05:44:27 +00:00
|
|
|
fpByte, err := hex.DecodeString(fingerprint)
|
2022-07-10 12:44:24 +00:00
|
|
|
if err != nil {
|
2022-07-10 13:56:33 +00:00
|
|
|
return nil, err
|
2022-07-10 12:44:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if len(fpByte) != 32 {
|
2023-01-31 07:26:18 +00:00
|
|
|
return nil, fmt.Errorf("fingerprint string length error,need sha256 fingerprint")
|
2022-07-10 12:44:24 +00:00
|
|
|
}
|
2022-07-10 13:56:33 +00:00
|
|
|
return (*[32]byte)(fpByte), nil
|
2022-07-10 12:44:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func GetDefaultTLSConfig() *tls.Config {
|
2023-01-14 13:08:06 +00:00
|
|
|
return GetGlobalTLSConfig(nil)
|
2022-07-10 13:56:33 +00:00
|
|
|
}
|
|
|
|
|
2022-07-11 05:42:28 +00:00
|
|
|
// GetSpecifiedFingerprintTLSConfig specified fingerprint
|
|
|
|
func GetSpecifiedFingerprintTLSConfig(tlsConfig *tls.Config, fingerprint string) (*tls.Config, error) {
|
2022-07-10 13:56:33 +00:00
|
|
|
if fingerprintBytes, err := convertFingerprint(fingerprint); err != nil {
|
|
|
|
return nil, err
|
|
|
|
} else {
|
2023-01-14 13:08:06 +00:00
|
|
|
tlsConfig = GetGlobalTLSConfig(tlsConfig)
|
|
|
|
tlsConfig.VerifyPeerCertificate = verifyFingerprint(fingerprintBytes)
|
|
|
|
tlsConfig.InsecureSkipVerify = true
|
|
|
|
return tlsConfig, nil
|
2022-07-10 13:56:33 +00:00
|
|
|
}
|
2022-07-10 12:44:24 +00:00
|
|
|
}
|
|
|
|
|
2023-01-14 13:08:06 +00:00
|
|
|
func GetGlobalTLSConfig(tlsConfig *tls.Config) *tls.Config {
|
2023-03-27 14:27:59 +00:00
|
|
|
certPool := getCertPool()
|
2022-07-10 12:44:24 +00:00
|
|
|
if tlsConfig == nil {
|
2022-07-11 04:37:27 +00:00
|
|
|
return &tls.Config{
|
2023-03-27 14:27:59 +00:00
|
|
|
RootCAs: certPool,
|
2022-07-11 04:37:27 +00:00
|
|
|
}
|
2022-07-10 12:44:24 +00:00
|
|
|
}
|
2023-03-27 14:27:59 +00:00
|
|
|
tlsConfig.RootCAs = certPool
|
2022-07-10 12:44:24 +00:00
|
|
|
return tlsConfig
|
|
|
|
}
|