mirror of https://github.com/allinssl/allinssl
241 lines
6.2 KiB
Go
241 lines
6.2 KiB
Go
package public
|
||
|
||
import (
|
||
"bytes"
|
||
"crypto"
|
||
"crypto/ecdsa"
|
||
"crypto/ed25519"
|
||
"crypto/rand"
|
||
"crypto/rsa"
|
||
"crypto/sha256"
|
||
"crypto/x509"
|
||
"encoding/hex"
|
||
"encoding/pem"
|
||
"errors"
|
||
"fmt"
|
||
"github.com/pavlo-v-chernykh/keystore-go/v4"
|
||
"software.sslmate.com/src/go-pkcs12"
|
||
"strings"
|
||
"time"
|
||
)
|
||
|
||
// **解析 PEM 格式的证书**
|
||
func ParseCertificate(certPEM []byte) (*x509.Certificate, error) {
|
||
block, _ := pem.Decode(certPEM)
|
||
if block == nil {
|
||
return nil, fmt.Errorf("无法解析证书 PEM")
|
||
}
|
||
return x509.ParseCertificate(block.Bytes)
|
||
}
|
||
|
||
// **解析 PEM 格式的私钥**
|
||
func ParsePrivateKey(keyPEM []byte) (crypto.PrivateKey, error) {
|
||
block, _ := pem.Decode(keyPEM)
|
||
if block == nil {
|
||
return nil, fmt.Errorf("无法解析私钥 PEM")
|
||
}
|
||
|
||
// **尝试解析不同类型的私钥**
|
||
if key, err := x509.ParsePKCS1PrivateKey(block.Bytes); err == nil {
|
||
return key, nil
|
||
}
|
||
if key, err := x509.ParseECPrivateKey(block.Bytes); err == nil {
|
||
return key, nil
|
||
}
|
||
if key, err := x509.ParsePKCS8PrivateKey(block.Bytes); err == nil {
|
||
return key, nil
|
||
}
|
||
return nil, fmt.Errorf("无法识别的私钥格式")
|
||
}
|
||
|
||
// **检查证书是否过期**
|
||
func CheckCertificateExpiration(cert *x509.Certificate) error {
|
||
now := time.Now()
|
||
if now.Before(cert.NotBefore) {
|
||
return fmt.Errorf("证书尚未生效,有效期开始于: %v", cert.NotBefore)
|
||
}
|
||
if now.After(cert.NotAfter) {
|
||
return fmt.Errorf("证书已过期,有效期截止到: %v", cert.NotAfter)
|
||
}
|
||
return nil
|
||
}
|
||
|
||
// **检查证书是否与私钥匹配**
|
||
func VerifyCertificateAndKey(cert *x509.Certificate, privateKey crypto.PrivateKey) error {
|
||
messageARR := sha256.Sum256([]byte("test message"))
|
||
message := messageARR[:]
|
||
var signature []byte
|
||
var err error
|
||
|
||
// **用私钥签名数据**
|
||
switch key := privateKey.(type) {
|
||
case *rsa.PrivateKey:
|
||
signature, err = rsa.SignPKCS1v15(nil, key, crypto.SHA256, message)
|
||
case *ecdsa.PrivateKey:
|
||
signature, err = key.Sign(rand.Reader, message, crypto.SHA256)
|
||
case ed25519.PrivateKey:
|
||
signature = ed25519.Sign(key, message)
|
||
default:
|
||
err = errors.New("不支持的私钥类型")
|
||
}
|
||
if err != nil {
|
||
return fmt.Errorf("签名失败: %v", err)
|
||
}
|
||
|
||
// **使用公钥验证签名**
|
||
switch pub := cert.PublicKey.(type) {
|
||
case *rsa.PublicKey:
|
||
err = rsa.VerifyPKCS1v15(pub, crypto.SHA256, message, signature)
|
||
case *ecdsa.PublicKey:
|
||
ok := ecdsa.VerifyASN1(pub, message, signature)
|
||
if !ok {
|
||
err = fmt.Errorf("ECDSA 签名验证失败")
|
||
}
|
||
case ed25519.PublicKey:
|
||
if !ed25519.Verify(pub, message, signature) {
|
||
err = fmt.Errorf("Ed25519 签名验证失败")
|
||
}
|
||
default:
|
||
err = fmt.Errorf("不支持的公钥类型: %T", pub)
|
||
}
|
||
return err
|
||
}
|
||
|
||
// **主验证函数**
|
||
func ValidateSSLCertificate(certStr, keyStr string) error {
|
||
certPEM, keyPEM := []byte(certStr), []byte(keyStr)
|
||
// **解析证书和私钥**
|
||
cert, err := ParseCertificate(certPEM)
|
||
if err != nil {
|
||
return fmt.Errorf("解析证书失败: %v", err)
|
||
}
|
||
privateKey, err := ParsePrivateKey(keyPEM)
|
||
if err != nil {
|
||
return fmt.Errorf("解析私钥失败: %v", err)
|
||
}
|
||
|
||
// **检查证书有效期**
|
||
if err := CheckCertificateExpiration(cert); err != nil {
|
||
return err
|
||
}
|
||
|
||
// **检查证书和私钥是否匹配**
|
||
if err := VerifyCertificateAndKey(cert, privateKey); err != nil {
|
||
return fmt.Errorf("证书与私钥不匹配: %v", err)
|
||
}
|
||
|
||
return nil
|
||
}
|
||
|
||
// 获取sha256
|
||
func GetSHA256(certStr string) (string, error) {
|
||
certPEM := []byte(certStr)
|
||
block, _ := pem.Decode(certPEM)
|
||
if block == nil {
|
||
return "", fmt.Errorf("无法解析证书 PEM")
|
||
}
|
||
cert, err := x509.ParseCertificate(block.Bytes)
|
||
if err != nil {
|
||
return "", fmt.Errorf("解析证书失败: %v", err)
|
||
}
|
||
|
||
sha256Hash := sha256.Sum256(cert.Raw)
|
||
return hex.EncodeToString(sha256Hash[:]), nil
|
||
}
|
||
|
||
// PEMToPFX 将PEM格式的证书和私钥转换为PFX格式
|
||
func PEMToPFX(certPEM, keyPEM, pfxPassword string) ([]byte, error) {
|
||
// 使用默认密码如果未提供
|
||
if pfxPassword == "" {
|
||
pfxPassword = "allinssl"
|
||
}
|
||
|
||
// 解析证书PEM
|
||
certBlock, _ := pem.Decode([]byte(certPEM))
|
||
if certBlock == nil || certBlock.Type != "CERTIFICATE" {
|
||
return nil, fmt.Errorf("无效的证书PEM格式")
|
||
}
|
||
|
||
// 解析私钥PEM
|
||
keyBlock, _ := pem.Decode([]byte(keyPEM))
|
||
if keyBlock == nil || (!strings.Contains(keyBlock.Type, "PRIVATE KEY")) {
|
||
return nil, fmt.Errorf("无效的私钥PEM格式")
|
||
}
|
||
|
||
// 解析X.509证书
|
||
cert, err := x509.ParseCertificate(certBlock.Bytes)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("解析证书失败: %v", err)
|
||
}
|
||
|
||
// 尝试解析私钥(PKCS8或PKCS1格式)
|
||
var privKey interface{}
|
||
privKey, err = x509.ParsePKCS8PrivateKey(keyBlock.Bytes)
|
||
if err != nil {
|
||
privKey, err = x509.ParsePKCS1PrivateKey(keyBlock.Bytes)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("解析私钥失败: %v", err)
|
||
}
|
||
}
|
||
|
||
// 编码为PFX格式
|
||
pfxData, err := pkcs12.Encode(rand.Reader, privKey, cert, nil, pfxPassword)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("编码PFX失败: %v", err)
|
||
}
|
||
|
||
return pfxData, nil
|
||
}
|
||
|
||
// PfxToJks 将PFX格式证书转换为JKS格式
|
||
func PfxToJks(pfxData []byte, pfxPassword, jksPassword, alias string) (*bytes.Buffer, error) {
|
||
if pfxPassword == "" {
|
||
return nil, fmt.Errorf("PFX 密码不能为空")
|
||
}
|
||
if jksPassword == "" {
|
||
jksPassword = pfxPassword
|
||
}
|
||
if alias == "" {
|
||
alias = "mycert"
|
||
}
|
||
// 解析 PFX,提取私钥、证书链
|
||
priv, cert, caCerts, err := pkcs12.DecodeChain(pfxData, pfxPassword)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("解析 PFX 失败: %w", err)
|
||
}
|
||
|
||
// 序列化私钥,兼容多种类型
|
||
pkBytes, err := x509.MarshalPKCS8PrivateKey(priv)
|
||
if err != nil {
|
||
return nil, fmt.Errorf("私钥序列化失败: %w", err)
|
||
}
|
||
|
||
// 构建证书链
|
||
certChain := make([]keystore.Certificate, 0, len(caCerts)+1)
|
||
certChain = append(certChain, keystore.Certificate{
|
||
Type: "X.509",
|
||
Content: cert.Raw,
|
||
})
|
||
for _, c := range caCerts {
|
||
certChain = append(certChain, keystore.Certificate{
|
||
Type: "X.509",
|
||
Content: c.Raw,
|
||
})
|
||
}
|
||
|
||
// 创建 JKS 并写入条目
|
||
ks := keystore.New()
|
||
ks.SetPrivateKeyEntry(alias, keystore.PrivateKeyEntry{
|
||
PrivateKey: pkBytes,
|
||
CertificateChain: certChain,
|
||
}, []byte(jksPassword))
|
||
|
||
// 写入到 Buffer
|
||
var buf bytes.Buffer
|
||
if err := ks.Store(&buf, []byte(jksPassword)); err != nil {
|
||
return nil, fmt.Errorf("生成 JKS 失败: %w", err)
|
||
}
|
||
|
||
return &buf, nil
|
||
}
|