feat: support tls config.

This commit is contained in:
tx7do
2024-11-13 11:27:13 +08:00
parent e755b6cfc8
commit 9e051505a1
19 changed files with 1749 additions and 700 deletions

190
utils/tls.go Normal file
View File

@@ -0,0 +1,190 @@
package utils
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"fmt"
"log"
"os"
)
// 双向验证server端提供证书(cert和key)还必须配置cerfiles即CA根证书因为需要验证client端提供的证书。另外client也端必须提供一样的内容即client端的证书(cert/key)以供server端验证并且提供CA根证书验证server端提供的证书。
// 单向验证server端提供证书(cert和key)不需要配置certfiles即CA根证书而在客户端必须提供CA根证书用来验证server端的证书是否有效。另外client端也不需要自己的证书因为它不需要想server端提供验证。
// LoadServerTlsConfigFile 创建服务端TLS证书认证配置
// keyFile 服务端私钥文件路径,必须提供
// certFile 服务端证书文件路径,必须提供
// caFile CA根证书如果提供则为双向认证否则为单向认证
// insecureSkipVerify 用来控制客户端是否证书和服务器主机名。如果设置为true,则不会校验证书以及证书中的主机名和服务器主机名是否一致。
func LoadServerTlsConfigFile(keyFile, certFile, caFile string, insecureSkipVerify bool) (*tls.Config, error) {
if keyFile == "" || certFile == "" {
return nil, fmt.Errorf("KeyFile and CertFile must both be present[key: %v, cert: %v]", keyFile, certFile)
}
var cfg tls.Config
cfg.InsecureSkipVerify = insecureSkipVerify
//cfg.ServerName = "host.docker.internal"
//cfg.MinVersion = tls.VersionTLS13
tlsCert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Println("tls.LoadX509KeyPair error:", err)
return nil, err
}
cfg.Certificates = []tls.Certificate{tlsCert}
if caFile != "" {
cfg.ClientAuth = tls.RequireAndVerifyClientCert
cp, err := newCertPoolWithCaFile(caFile)
if err != nil {
log.Fatalln("read cert file error:", err)
return nil, err
}
cfg.RootCAs = cp
cfg.ClientCAs = cp
} else {
cfg.ClientAuth = tls.NoClientCert
}
return &cfg, nil
}
func LoadServerTlsConfig(keyPEMBlock, certPEMBlock, caPEMBlock []byte, insecureSkipVerify bool) (*tls.Config, error) {
if len(keyPEMBlock) == 0 || len(certPEMBlock) == 0 {
return nil, fmt.Errorf("KeyPEMBlock and CertPEMBlock must both be present[key: %v, cert: %v]", keyPEMBlock, certPEMBlock)
}
var cfg tls.Config
cfg.InsecureSkipVerify = insecureSkipVerify
//cfg.ServerName = "host.docker.internal"
//cfg.MinVersion = tls.VersionTLS13
tlsCert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
if err != nil {
log.Println("tls.X509KeyPair error:", err)
return nil, err
}
cfg.Certificates = []tls.Certificate{tlsCert}
if len(caPEMBlock) != 0 {
cfg.ClientAuth = tls.RequireAndVerifyClientCert
cp, err := newCertPool(caPEMBlock)
if err != nil {
log.Fatalln("read cert PEM error:", err)
return nil, err
}
cfg.RootCAs = cp
cfg.ClientCAs = cp
} else {
cfg.ClientAuth = tls.NoClientCert
}
return &cfg, nil
}
// LoadClientTlsConfigFile 创建客户端端TLS证书认证配置
// keyFile 客户端私钥文件路径
// certFile 客户端证书文件路径
// caFile CA根证书
func LoadClientTlsConfigFile(keyFile, certFile, caFile string) (*tls.Config, error) {
var cfg tls.Config
//cfg.InsecureSkipVerify = info.InsecureSkipVerify
//cfg.ServerName = "host.docker.internal"
//cfg.MinVersion = tls.VersionTLS13
if keyFile == "" || certFile == "" {
return &cfg, nil
}
tlsCert, err := tls.LoadX509KeyPair(certFile, keyFile)
if err != nil {
log.Fatalln("read pair file error:", err)
return nil, err
}
cfg.Certificates = []tls.Certificate{tlsCert}
if caFile != "" {
cp, err := newCertPoolWithCaFile(caFile)
if err != nil {
log.Fatalln("read cert file error:", err)
return nil, err
}
cfg.RootCAs = cp
}
return &cfg, nil
}
func LoadClientTlsConfig(keyPEMBlock, certPEMBlock, caPEMBlock []byte) (*tls.Config, error) {
if len(keyPEMBlock) == 0 || len(certPEMBlock) == 0 {
return nil, fmt.Errorf("KeyPEMBlock and CertPEMBlock must both be present[key: %v, cert: %v]", keyPEMBlock, certPEMBlock)
}
var cfg tls.Config
//cfg.InsecureSkipVerify = info.InsecureSkipVerify
//cfg.ServerName = "host.docker.internal"
//cfg.MinVersion = tls.VersionTLS13
tlsCert, err := tls.X509KeyPair(certPEMBlock, keyPEMBlock)
if err != nil {
log.Fatalln("read pair PEM error:", err)
return nil, err
}
cfg.Certificates = []tls.Certificate{tlsCert}
if len(caPEMBlock) != 0 {
cp, err := newCertPool(caPEMBlock)
if err != nil {
log.Fatalln("read cert PEM error:", err)
return nil, err
}
cfg.RootCAs = cp
}
return &cfg, nil
}
// newCertPool creates x509 certPool with provided CA file
func newCertPoolWithCaFile(caFile string) (*x509.CertPool, error) {
pemByte, err := os.ReadFile(caFile)
if err != nil {
return nil, err
}
return newCertPool(pemByte)
}
func newCertPool(caPEMBlock []byte) (*x509.CertPool, error) {
certPool := x509.NewCertPool()
var block *pem.Block
var cert *x509.Certificate
var err error
for {
block, caPEMBlock = pem.Decode(caPEMBlock)
if block == nil {
return certPool, nil
}
cert, err = x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, err
}
certPool.AddCert(cert)
}
//if !certPool.AppendCertsFromPEM(caPEMBlock) {
// return nil, fmt.Errorf("can't add CA cert")
//}
//return certPool, nil
}