mirror of
https://github.com/woodchen-ink/certimate.git
synced 2025-07-18 01:11:55 +08:00
fix: missing pfx certificiate chains
This commit is contained in:
parent
424e2e7710
commit
7d272a6c52
@ -2,6 +2,7 @@ package cert
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/pem"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 比较两个 x509.Certificate 对象,判断它们是否是同一张证书。
|
// 比较两个 x509.Certificate 对象,判断它们是否是同一张证书。
|
||||||
@ -24,3 +25,18 @@ func EqualCertificate(a, b *x509.Certificate) bool {
|
|||||||
a.Issuer.SerialNumber == b.Issuer.SerialNumber &&
|
a.Issuer.SerialNumber == b.Issuer.SerialNumber &&
|
||||||
a.Subject.SerialNumber == b.Subject.SerialNumber
|
a.Subject.SerialNumber == b.Subject.SerialNumber
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func decodePEM(data []byte) []*pem.Block {
|
||||||
|
blocks := make([]*pem.Block, 0)
|
||||||
|
for {
|
||||||
|
block, rest := pem.Decode(data)
|
||||||
|
if block == nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
|
||||||
|
blocks = append(blocks, block)
|
||||||
|
data = rest
|
||||||
|
}
|
||||||
|
|
||||||
|
return blocks
|
||||||
|
}
|
||||||
|
@ -3,6 +3,7 @@ package cert
|
|||||||
import (
|
import (
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
)
|
)
|
||||||
|
|
||||||
// 从 PEM 编码的证书字符串解析并提取服务器证书和中间证书。
|
// 从 PEM 编码的证书字符串解析并提取服务器证书和中间证书。
|
||||||
@ -15,32 +16,27 @@ import (
|
|||||||
// - intermediaCertPEM: 中间证书的 PEM 内容。
|
// - intermediaCertPEM: 中间证书的 PEM 内容。
|
||||||
// - err: 错误。
|
// - err: 错误。
|
||||||
func ExtractCertificatesFromPEM(certPEM string) (_serverCertPEM string, _intermediaCertPEM string, _err error) {
|
func ExtractCertificatesFromPEM(certPEM string) (_serverCertPEM string, _intermediaCertPEM string, _err error) {
|
||||||
pemBlocks := make([]*pem.Block, 0)
|
blocks := decodePEM([]byte(certPEM))
|
||||||
pemData := []byte(certPEM)
|
for i, block := range blocks {
|
||||||
for {
|
if block.Type != "CERTIFICATE" {
|
||||||
block, rest := pem.Decode(pemData)
|
return "", "", fmt.Errorf("invalid PEM block type at %d, expected 'CERTIFICATE', got '%s'", i, block.Type)
|
||||||
if block == nil || block.Type != "CERTIFICATE" {
|
|
||||||
break
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pemBlocks = append(pemBlocks, block)
|
|
||||||
pemData = rest
|
|
||||||
}
|
}
|
||||||
|
|
||||||
serverCertPEM := ""
|
serverCertPEM := ""
|
||||||
intermediaCertPEM := ""
|
intermediaCertPEM := ""
|
||||||
|
|
||||||
if len(pemBlocks) == 0 {
|
if len(blocks) == 0 {
|
||||||
return "", "", errors.New("failed to decode PEM block")
|
return "", "", errors.New("failed to decode PEM block")
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pemBlocks) > 0 {
|
if len(blocks) > 0 {
|
||||||
serverCertPEM = string(pem.EncodeToMemory(pemBlocks[0]))
|
serverCertPEM = string(pem.EncodeToMemory(blocks[0]))
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(pemBlocks) > 1 {
|
if len(blocks) > 1 {
|
||||||
for i := 1; i < len(pemBlocks); i++ {
|
for i := 1; i < len(blocks); i++ {
|
||||||
intermediaCertPEM += string(pem.EncodeToMemory(pemBlocks[i]))
|
intermediaCertPEM += string(pem.EncodeToMemory(blocks[i]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,8 +2,9 @@ package cert
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"encoding/pem"
|
"crypto/x509"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/pavlo-v-chernykh/keystore-go/v4"
|
"github.com/pavlo-v-chernykh/keystore-go/v4"
|
||||||
@ -21,9 +22,19 @@ import (
|
|||||||
// - data: PFX 格式的证书数据。
|
// - data: PFX 格式的证书数据。
|
||||||
// - err: 错误。
|
// - err: 错误。
|
||||||
func TransformCertificateFromPEMToPFX(certPEM string, privkeyPEM string, pfxPassword string) ([]byte, error) {
|
func TransformCertificateFromPEMToPFX(certPEM string, privkeyPEM string, pfxPassword string) ([]byte, error) {
|
||||||
cert, err := ParseCertificateFromPEM(certPEM)
|
blocks := decodePEM([]byte(certPEM))
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
certs := make([]*x509.Certificate, 0, len(blocks))
|
||||||
|
for i, block := range blocks {
|
||||||
|
if block.Type != "CERTIFICATE" {
|
||||||
|
return nil, fmt.Errorf("invalid PEM block type at %d, expected 'CERTIFICATE', got '%s'", i, block.Type)
|
||||||
|
}
|
||||||
|
|
||||||
|
cert, err := x509.ParseCertificate(block.Bytes)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
certs = append(certs, cert)
|
||||||
}
|
}
|
||||||
|
|
||||||
privkey, err := ParsePrivateKeyFromPEM(privkeyPEM)
|
privkey, err := ParsePrivateKeyFromPEM(privkeyPEM)
|
||||||
@ -31,12 +42,16 @@ func TransformCertificateFromPEMToPFX(certPEM string, privkeyPEM string, pfxPass
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
pfxData, err := pkcs12.LegacyRC2.Encode(privkey, cert, nil, pfxPassword)
|
var pfxData []byte
|
||||||
if err != nil {
|
if len(certs) == 0 {
|
||||||
return nil, err
|
return nil, errors.New("failed to decode certificate PEM")
|
||||||
|
} else if len(certs) == 1 {
|
||||||
|
pfxData, err = pkcs12.Legacy.Encode(privkey, certs[0], nil, pfxPassword)
|
||||||
|
} else {
|
||||||
|
pfxData, err = pkcs12.Legacy.Encode(privkey, certs[0], certs[1:], pfxPassword)
|
||||||
}
|
}
|
||||||
|
|
||||||
return pfxData, nil
|
return pfxData, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// 将 PEM 编码的证书字符串转换为 JKS 格式。
|
// 将 PEM 编码的证书字符串转换为 JKS 格式。
|
||||||
@ -52,28 +67,33 @@ func TransformCertificateFromPEMToPFX(certPEM string, privkeyPEM string, pfxPass
|
|||||||
// - data: JKS 格式的证书数据。
|
// - data: JKS 格式的证书数据。
|
||||||
// - err: 错误。
|
// - err: 错误。
|
||||||
func TransformCertificateFromPEMToJKS(certPEM string, privkeyPEM string, jksAlias string, jksKeypass string, jksStorepass string) ([]byte, error) {
|
func TransformCertificateFromPEMToJKS(certPEM string, privkeyPEM string, jksAlias string, jksKeypass string, jksStorepass string) ([]byte, error) {
|
||||||
certBlock, _ := pem.Decode([]byte(certPEM))
|
certBlocks := decodePEM([]byte(certPEM))
|
||||||
if certBlock == nil {
|
if len(certBlocks) == 0 {
|
||||||
return nil, errors.New("failed to decode certificate PEM")
|
return nil, errors.New("failed to decode certificate PEM")
|
||||||
}
|
}
|
||||||
|
|
||||||
privkeyBlock, _ := pem.Decode([]byte(privkeyPEM))
|
privkeyBlocks := decodePEM([]byte(privkeyPEM))
|
||||||
if privkeyBlock == nil {
|
if len(privkeyBlocks) == 0 {
|
||||||
return nil, errors.New("failed to decode private key PEM")
|
return nil, errors.New("failed to decode private key PEM")
|
||||||
}
|
}
|
||||||
|
|
||||||
ks := keystore.New()
|
|
||||||
entry := keystore.PrivateKeyEntry{
|
entry := keystore.PrivateKeyEntry{
|
||||||
CreationTime: time.Now(),
|
CreationTime: time.Now(),
|
||||||
PrivateKey: privkeyBlock.Bytes,
|
PrivateKey: privkeyBlocks[0].Bytes,
|
||||||
CertificateChain: []keystore.Certificate{
|
CertificateChain: make([]keystore.Certificate, len(certBlocks)),
|
||||||
{
|
}
|
||||||
Type: "X509",
|
for i, certBlock := range certBlocks {
|
||||||
Content: certBlock.Bytes,
|
if certBlock.Type != "CERTIFICATE" {
|
||||||
},
|
return nil, fmt.Errorf("invalid PEM block type at %d, expected 'CERTIFICATE', got '%s'", i, certBlock.Type)
|
||||||
},
|
}
|
||||||
|
|
||||||
|
entry.CertificateChain[i] = keystore.Certificate{
|
||||||
|
Type: "X509",
|
||||||
|
Content: certBlock.Bytes,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ks := keystore.New()
|
||||||
if err := ks.SetPrivateKeyEntry(jksAlias, entry, []byte(jksKeypass)); err != nil {
|
if err := ks.SetPrivateKeyEntry(jksAlias, entry, []byte(jksKeypass)); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user