feat(provider): support pfx encoder in local/ssh/ftp/s3 deployers

This commit is contained in:
Fu Diwei
2026-05-20 17:43:34 +08:00
committed by RHQYZ
parent 89fb3dc99d
commit 99f9aed324
28 changed files with 293 additions and 75 deletions
+1 -1
View File
@@ -118,7 +118,7 @@ func (s *CertificateService) DownloadCertificate(ctx context.Context, req *dtos.
{
const pfxPassword = "certimate"
certPFX, err := xcert.TransformCertificateFromPEMToPFX(certificate.Certificate, certificate.PrivateKey, pfxPassword)
certPFX, err := xcert.TransformCertificateFromPEMToPFX(certificate.Certificate, certificate.PrivateKey, pfxPassword, nil)
if err != nil {
return nil, err
}
+1
View File
@@ -27,6 +27,7 @@ func init() {
FilePathForCrtOnlyServer: xmaps.GetString(options.ProviderExtendedConfig, "filePathForCrtOnlyServer"),
FilePathForCrtOnlyIntermedia: xmaps.GetString(options.ProviderExtendedConfig, "filePathForCrtOnlyIntermedia"),
PfxPassword: xmaps.GetString(options.ProviderExtendedConfig, "pfxPassword"),
PfxEncoder: xmaps.GetString(options.ProviderExtendedConfig, "pfxEncoder"),
JksAlias: xmaps.GetString(options.ProviderExtendedConfig, "jksAlias"),
JksKeypass: xmaps.GetString(options.ProviderExtendedConfig, "jksKeypass"),
JksStorepass: xmaps.GetString(options.ProviderExtendedConfig, "jksStorepass"),
+1
View File
@@ -19,6 +19,7 @@ func init() {
FilePathForCrtOnlyServer: xmaps.GetString(options.ProviderExtendedConfig, "filePathForCrtOnlyServer"),
FilePathForCrtOnlyIntermedia: xmaps.GetString(options.ProviderExtendedConfig, "filePathForCrtOnlyIntermedia"),
PfxPassword: xmaps.GetString(options.ProviderExtendedConfig, "pfxPassword"),
PfxEncoder: xmaps.GetString(options.ProviderExtendedConfig, "pfxEncoder"),
JksAlias: xmaps.GetString(options.ProviderExtendedConfig, "jksAlias"),
JksKeypass: xmaps.GetString(options.ProviderExtendedConfig, "jksKeypass"),
JksStorepass: xmaps.GetString(options.ProviderExtendedConfig, "jksStorepass"),
+1
View File
@@ -31,6 +31,7 @@ func init() {
ObjectKeyForCrtOnlyServer: xmaps.GetString(options.ProviderExtendedConfig, "objectKeyForCrtOnlyServer"),
ObjectKeyForCrtOnlyIntermedia: xmaps.GetString(options.ProviderExtendedConfig, "objectKeyForCrtOnlyIntermedia"),
PfxPassword: xmaps.GetString(options.ProviderExtendedConfig, "pfxPassword"),
PfxEncoder: xmaps.GetString(options.ProviderExtendedConfig, "pfxEncoder"),
JksAlias: xmaps.GetString(options.ProviderExtendedConfig, "jksAlias"),
JksKeypass: xmaps.GetString(options.ProviderExtendedConfig, "jksKeypass"),
JksStorepass: xmaps.GetString(options.ProviderExtendedConfig, "jksStorepass"),
+1
View File
@@ -49,6 +49,7 @@ func init() {
FilePathForCrtOnlyServer: xmaps.GetString(options.ProviderExtendedConfig, "filePathForCrtOnlyServer"),
FilePathForCrtOnlyIntermedia: xmaps.GetString(options.ProviderExtendedConfig, "filePathForCrtOnlyIntermedia"),
PfxPassword: xmaps.GetString(options.ProviderExtendedConfig, "pfxPassword"),
PfxEncoder: xmaps.GetString(options.ProviderExtendedConfig, "pfxEncoder"),
JksAlias: xmaps.GetString(options.ProviderExtendedConfig, "jksAlias"),
JksKeypass: xmaps.GetString(options.ProviderExtendedConfig, "jksKeypass"),
JksStorepass: xmaps.GetString(options.ProviderExtendedConfig, "jksStorepass"),
@@ -136,7 +136,7 @@ func (c *Certmgr) Upload(ctx context.Context, certPEM, privkeyPEM string) (*cert
// Azure Key Vault 不支持导入带有 Certificate Chain 的 PEM 证书。
// Issue Link: https://github.com/Azure/azure-cli/issues/19017
// 暂时的解决方法是,将 PEM 证书转换成 PFX 格式,然后再导入。
certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, "")
certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, "", nil)
if err != nil {
return nil, fmt.Errorf("failed to transform certificate from PEM to PFX: %w", err)
}
@@ -175,7 +175,7 @@ func (c *Certmgr) Replace(ctx context.Context, certIdOrName string, certPEM, pri
}
// 转换证书格式
certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, "")
certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, "", nil)
if err != nil {
return nil, fmt.Errorf("failed to transform certificate from PEM to PFX: %w", err)
}
@@ -198,7 +198,7 @@ func (d *Deployer) updateSiteCertificate(ctx context.Context, siteType, siteName
if pfxRequried {
// 转换证书格式
certPFXPassword := "certimate"
certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, certPFXPassword)
certPFX, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, certPFXPassword, nil)
if err != nil {
return fmt.Errorf("failed to transform certificate from PEM to PFX: %w", err)
}
+11 -4
View File
@@ -1,11 +1,18 @@
package ftp
import (
"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core/deployer/providers/local/shared"
)
const (
FILE_FORMAT_PEM = string(domain.CertificateFormatTypePEM)
FILE_FORMAT_PFX = string(domain.CertificateFormatTypePFX)
FILE_FORMAT_JKS = string(domain.CertificateFormatTypeJKS)
FILE_FORMAT_PEM = shared.FILE_FORMAT_PEM
FILE_FORMAT_PFX = shared.FILE_FORMAT_PFX
FILE_FORMAT_JKS = shared.FILE_FORMAT_JKS
)
const (
PFX_ENCODER_LEGACYRC2 = shared.PFX_ENCODER_LEGACYRC2
PFX_ENCODER_LEGACYDES = shared.PFX_ENCODER_LEGACYDES
PFX_ENCODER_MODERN2023 = shared.PFX_ENCODER_MODERN2023
PFX_ENCODER_MODERN2026 = shared.PFX_ENCODER_MODERN2026
)
+10 -1
View File
@@ -8,6 +8,7 @@ import (
"github.com/certimate-go/certimate/internal/tools/ftp"
"github.com/certimate-go/certimate/pkg/core/deployer"
shared "github.com/certimate-go/certimate/pkg/core/deployer/providers/local/shared"
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
)
@@ -36,6 +37,9 @@ type DeployerConfig struct {
// PFX 导出密码。
// 证书格式为 [FILE_FORMAT_PFX] 时必填。
PfxPassword string `json:"pfxPassword,omitempty"`
// PFX 编码器。
// 证书格式为 [FILE_FORMAT_PFX] 时可选。
PfxEncoder string `json:"pfxEncoder,omitempty"`
// JKS 别名。
// 证书格式为 [FILE_FORMAT_JKS] 时必填。
JksAlias string `json:"jksAlias,omitempty"`
@@ -151,7 +155,12 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*dep
return nil, fmt.Errorf("config `pfxPassword` is required")
}
pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword)
pfxEncoder, err := shared.ResolvePfxEncoder(d.config.PfxEncoder)
if err != nil {
return nil, fmt.Errorf("config `pfxEncoder` is invalid: %w", err)
}
pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword, pfxEncoder)
if err != nil {
return nil, fmt.Errorf("failed to transform certificate to PFX: %w", err)
}
+4 -4
View File
@@ -26,8 +26,8 @@ func init() {
fp.DefineInt64(&fFtpPort, "FTPPORT")
fp.DefineString(&fFtpUsername, "FTPUSERNAME")
fp.DefineString(&fFtpPassword, "FTPPASSWORD")
fp.DefineString(&fFilePathForCrt, "OUTPUTCERTPATH")
fp.DefineString(&fFilePathForKey, "OUTPUTKEYPATH")
fp.DefineString(&fFilePathForCrt, "FILEPATHFORCRT")
fp.DefineString(&fFilePathForKey, "FILEPATHFORKEY")
}
/*
@@ -40,8 +40,8 @@ Shell command to run this test:
--FTP_FTPPORT=21 \
--FTP_FTPUSERNAME="USER" \
--FTP_FTPPASSWORD="PASS" \
--FTP_OUTPUTCERTPATH="/path/to/your-output-cert.pem" \
--FTP_OUTPUTKEYPATH="/path/to/your-output-key.pem"
--FTP_FILEPATHFORCRT="/path/to/your-output-cert.pem" \
--FTP_FILEPATHFORKEY="/path/to/your-output-key.pem"
*/
func TestProvider(t *testing.T) {
fp.Parse()
@@ -15,3 +15,10 @@ const (
FILE_FORMAT_PFX = string(domain.CertificateFormatTypePFX)
FILE_FORMAT_JKS = string(domain.CertificateFormatTypeJKS)
)
const (
PFX_ENCODER_LEGACYRC2 = "LegacyRC2"
PFX_ENCODER_LEGACYDES = "LegacyDES"
PFX_ENCODER_MODERN2023 = "Modern2023"
PFX_ENCODER_MODERN2026 = "Modern2026"
)
+9 -1
View File
@@ -37,6 +37,9 @@ type DeployerConfig struct {
// PFX 导出密码。
// 证书格式为 [FILE_FORMAT_PFX] 时必填。
PfxPassword string `json:"pfxPassword,omitempty"`
// PFX 编码器。
// 证书格式为 [FILE_FORMAT_PFX] 时可选。
PfxEncoder string `json:"pfxEncoder,omitempty"`
// JKS 别名。
// 证书格式为 [FILE_FORMAT_JKS] 时必填。
JksAlias string `json:"jksAlias,omitempty"`
@@ -139,7 +142,12 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*dep
return nil, fmt.Errorf("config `pfxPassword` is required")
}
pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword)
pfxEncoder, err := ResolvePfxEncoder(d.config.PfxEncoder)
if err != nil {
return nil, fmt.Errorf("config `pfxEncoder` is invalid: %w", err)
}
pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword, pfxEncoder)
if err != nil {
return nil, fmt.Errorf("failed to transform certificate to PFX: %w", err)
}
@@ -14,6 +14,7 @@ var (
fFilePathForCrt string
fFilePathForKey string
fPfxPassword string
fPfxEncoder string
fJksAlias string
fJksKeypass string
fJksStorepass string
@@ -25,9 +26,10 @@ var (
func init() {
fp.DefineString(&fTestCertPath, "TESTCERTPATH")
fp.DefineString(&fTestKeyPath, "TESTKEYPATH")
fp.DefineString(&fFilePathForCrt, "OUTPUTCERTPATH")
fp.DefineString(&fFilePathForKey, "OUTPUTKEYPATH")
fp.DefineString(&fFilePathForCrt, "FILEPATHFORCRT")
fp.DefineString(&fFilePathForKey, "FILEPATHFORKEY")
fp.DefineString(&fPfxPassword, "PFXPASSWORD")
fp.DefineString(&fPfxEncoder, "PFXENCODER")
fp.DefineString(&fJksAlias, "JKSALIAS")
fp.DefineString(&fJksKeypass, "JKSKEYPASS")
fp.DefineString(&fJksStorepass, "JKSSTOREPASS")
@@ -42,9 +44,10 @@ Shell command to run this test:
go test -v ./local_test.go -args \
--LOCAL_TESTCERTPATH="/path/to/your-test-cert.pem" \
--LOCAL_TESTKEYPATH="/path/to/your-test-key.pem" \
--LOCAL_OUTPUTCERTPATH="/path/to/your-output-cert" \
--LOCAL_OUTPUTKEYPATH="/path/to/your-output-key" \
--LOCAL_FILEPATHFORCRT="/path/to/your-output-cert" \
--LOCAL_FILEPATHFORKEY="/path/to/your-output-key" \
--LOCAL_PFXPASSWORD="your-pfx-password" \
--LOCAL_PFXENCODER="modern2023" \
--LOCAL_JKSALIAS="your-jks-alias" \
--LOCAL_JKSKEYPASS="your-jks-keypass" \
--LOCAL_JKSSTOREPASS="your-jks-storepass" \
@@ -77,6 +80,7 @@ func TestProvider(t *testing.T) {
FileFormat: impl.FILE_FORMAT_PFX,
FilePathForCrt: fFilePathForCrt + ".pfx",
PfxPassword: fPfxPassword,
PfxEncoder: fPfxEncoder,
})
if err != nil {
t.Errorf("err: %+v", err)
@@ -0,0 +1,24 @@
package shared
import (
"software.sslmate.com/src/go-pkcs12"
"github.com/certimate-go/certimate/pkg/core/deployer/providers/local"
)
const (
FILE_FORMAT_PEM = local.FILE_FORMAT_PEM
FILE_FORMAT_PFX = local.FILE_FORMAT_PFX
FILE_FORMAT_JKS = local.FILE_FORMAT_JKS
)
const (
PFX_ENCODER_LEGACYRC2 = local.PFX_ENCODER_LEGACYRC2
PFX_ENCODER_LEGACYDES = local.PFX_ENCODER_LEGACYDES
PFX_ENCODER_MODERN2023 = local.PFX_ENCODER_MODERN2023
PFX_ENCODER_MODERN2026 = local.PFX_ENCODER_MODERN2026
)
func ResolvePfxEncoder(encoderName string) (*pkcs12.Encoder, error) {
return local.ResolvePfxEncoder(encoderName)
}
@@ -0,0 +1,28 @@
package local
import (
"fmt"
"strings"
"software.sslmate.com/src/go-pkcs12"
)
func ResolvePfxEncoder(encoderName string) (*pkcs12.Encoder, error) {
var encoder *pkcs12.Encoder
if encoderName != "" {
if strings.EqualFold(encoderName, PFX_ENCODER_LEGACYRC2) {
encoder = pkcs12.LegacyRC2
} else if strings.EqualFold(encoderName, PFX_ENCODER_LEGACYDES) {
encoder = pkcs12.LegacyDES
} else if strings.EqualFold(encoderName, PFX_ENCODER_MODERN2023) {
encoder = pkcs12.Modern2023
} else if strings.EqualFold(encoderName, PFX_ENCODER_MODERN2026) {
encoder = pkcs12.Modern2026
} else {
return nil, fmt.Errorf("unsupported encoder name: '%s'", encoderName)
}
}
return encoder, nil
}
+11 -4
View File
@@ -1,11 +1,18 @@
package s3
import (
"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core/deployer/providers/local/shared"
)
const (
FILE_FORMAT_PEM = string(domain.CertificateFormatTypePEM)
FILE_FORMAT_PFX = string(domain.CertificateFormatTypePFX)
FILE_FORMAT_JKS = string(domain.CertificateFormatTypeJKS)
FILE_FORMAT_PEM = shared.FILE_FORMAT_PEM
FILE_FORMAT_PFX = shared.FILE_FORMAT_PFX
FILE_FORMAT_JKS = shared.FILE_FORMAT_JKS
)
const (
PFX_ENCODER_LEGACYRC2 = shared.PFX_ENCODER_LEGACYRC2
PFX_ENCODER_LEGACYDES = shared.PFX_ENCODER_LEGACYDES
PFX_ENCODER_MODERN2023 = shared.PFX_ENCODER_MODERN2023
PFX_ENCODER_MODERN2026 = shared.PFX_ENCODER_MODERN2026
)
+10 -1
View File
@@ -7,6 +7,7 @@ import (
"github.com/certimate-go/certimate/internal/tools/s3"
"github.com/certimate-go/certimate/pkg/core/deployer"
"github.com/certimate-go/certimate/pkg/core/deployer/providers/local/shared"
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
)
@@ -44,6 +45,9 @@ type DeployerConfig struct {
// PFX 导出密码。
// 证书格式为 [FILE_FORMAT_PFX] 时必填。
PfxPassword string `json:"pfxPassword,omitempty"`
// PFX 编码器。
// 证书格式为 [FILE_FORMAT_PFX] 时可选。
PfxEncoder string `json:"pfxEncoder,omitempty"`
// JKS 别名。
// 证书格式为 [FILE_FORMAT_JKS] 时必填。
JksAlias string `json:"jksAlias,omitempty"`
@@ -133,7 +137,12 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*dep
return nil, fmt.Errorf("config `pfxPassword` is required")
}
pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword)
pfxEncoder, err := shared.ResolvePfxEncoder(d.config.PfxEncoder)
if err != nil {
return nil, fmt.Errorf("config `pfxEncoder` is invalid: %w", err)
}
pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword, pfxEncoder)
if err != nil {
return nil, fmt.Errorf("failed to transform certificate to PFX: %w", err)
}
+16 -16
View File
@@ -8,16 +8,16 @@ import (
)
var (
fp = tester.Args("S3_")
fTestCertPath string
fTestKeyPath string
fSshHost string
fAccessKey string
fSecretKey string
fRegion string
fBucket string
fFilePathForCrt string
fFilePathForKey string
fp = tester.Args("S3_")
fTestCertPath string
fTestKeyPath string
fSshHost string
fAccessKey string
fSecretKey string
fRegion string
fBucket string
fObjectKeyForCrt string
fObjectKeyForKey string
)
func init() {
@@ -28,8 +28,8 @@ func init() {
fp.DefineString(&fSecretKey, "SECRETKEY")
fp.DefineString(&fRegion, "REGION")
fp.DefineString(&fBucket, "BUCKET")
fp.DefineString(&fFilePathForCrt, "OUTPUTCERTPATH")
fp.DefineString(&fFilePathForKey, "OUTPUTKEYPATH")
fp.DefineString(&fObjectKeyForCrt, "OBJECTKEYFORCRT")
fp.DefineString(&fObjectKeyForKey, "OBJECTKEYFORKEY")
}
/*
@@ -43,8 +43,8 @@ Shell command to run this test:
--S3_SECRETKEY="your-secret-key" \
--S3_REGION="your-region" \
--S3_BUCKET="your-bucket" \
--S3_OUTPUTCERTPATH="/path/to/your-output-cert.pem" \
--S3_OUTPUTKEYPATH="/path/to/your-output-key.pem"
--S3_OBJECTKEYFORCRT="/path/to/your-output-cert.pem" \
--S3_OBJECTKEYFORKEY="/path/to/your-output-key.pem"
*/
func TestProvider(t *testing.T) {
fp.Parse()
@@ -57,8 +57,8 @@ func TestProvider(t *testing.T) {
Region: fRegion,
Bucket: fBucket,
FileFormat: impl.FILE_FORMAT_PEM,
ObjectKeyForCrt: fFilePathForCrt + ".pem",
ObjectKeyForKey: fFilePathForKey + ".pem",
ObjectKeyForCrt: fObjectKeyForCrt + ".pem",
ObjectKeyForKey: fObjectKeyForKey + ".pem",
})
if err != nil {
t.Errorf("err: %+v", err)
+11 -4
View File
@@ -1,11 +1,18 @@
package ssh
import (
"github.com/certimate-go/certimate/internal/domain"
"github.com/certimate-go/certimate/pkg/core/deployer/providers/local/shared"
)
const (
FILE_FORMAT_PEM = string(domain.CertificateFormatTypePEM)
FILE_FORMAT_PFX = string(domain.CertificateFormatTypePFX)
FILE_FORMAT_JKS = string(domain.CertificateFormatTypeJKS)
FILE_FORMAT_PEM = shared.FILE_FORMAT_PEM
FILE_FORMAT_PFX = shared.FILE_FORMAT_PFX
FILE_FORMAT_JKS = shared.FILE_FORMAT_JKS
)
const (
PFX_ENCODER_LEGACYRC2 = shared.PFX_ENCODER_LEGACYRC2
PFX_ENCODER_LEGACYDES = shared.PFX_ENCODER_LEGACYDES
PFX_ENCODER_MODERN2023 = shared.PFX_ENCODER_MODERN2023
PFX_ENCODER_MODERN2026 = shared.PFX_ENCODER_MODERN2026
)
+14 -5
View File
@@ -8,6 +8,7 @@ import (
"github.com/certimate-go/certimate/internal/tools/ssh"
"github.com/certimate-go/certimate/pkg/core/deployer"
"github.com/certimate-go/certimate/pkg/core/deployer/providers/local/shared"
xcert "github.com/certimate-go/certimate/pkg/utils/cert"
xssh "github.com/certimate-go/certimate/pkg/utils/ssh"
)
@@ -59,6 +60,9 @@ type DeployerConfig struct {
// PFX 导出密码。
// 证书格式为 [FILE_FORMAT_PFX] 时必填。
PfxPassword string `json:"pfxPassword,omitempty"`
// PFX 编码器。
// 证书格式为 [FILE_FORMAT_PFX] 时可选。
PfxEncoder string `json:"pfxEncoder,omitempty"`
// JKS 别名。
// 证书格式为 [FILE_FORMAT_JKS] 时必填。
JksAlias string `json:"jksAlias,omitempty"`
@@ -134,10 +138,6 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*dep
switch d.config.FileFormat {
case FILE_FORMAT_PEM:
{
if d.config.PfxPassword == "" {
return nil, fmt.Errorf("config `pfxPassword` is required")
}
if d.config.FilePathForKey != "" {
if err := xssh.WriteRemoteString(sshClient.RawClient(), d.config.FilePathForKey, privkeyPEM, d.config.UseSCP); err != nil {
return nil, fmt.Errorf("failed to upload private key file: %w", err)
@@ -169,7 +169,16 @@ func (d *Deployer) Deploy(ctx context.Context, certPEM, privkeyPEM string) (*dep
case FILE_FORMAT_PFX:
{
pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword)
if d.config.PfxPassword == "" {
return nil, fmt.Errorf("config `pfxPassword` is required")
}
pfxEncoder, err := shared.ResolvePfxEncoder(d.config.PfxEncoder)
if err != nil {
return nil, fmt.Errorf("config `pfxEncoder` is invalid: %w", err)
}
pfxData, err := xcert.TransformCertificateFromPEMToPFX(certPEM, privkeyPEM, d.config.PfxPassword, pfxEncoder)
if err != nil {
return nil, fmt.Errorf("failed to transform certificate to PFX: %w", err)
}
+4 -4
View File
@@ -26,8 +26,8 @@ func init() {
fp.DefineInt64(&fSshPort, "SSHPORT")
fp.DefineString(&fSshUsername, "SSHUSERNAME")
fp.DefineString(&fSshPassword, "SSHPASSWORD")
fp.DefineString(&fFilePathForCrt, "OUTPUTCERTPATH")
fp.DefineString(&fFilePathForKey, "OUTPUTKEYPATH")
fp.DefineString(&fFilePathForCrt, "FILEPATHFORCRT")
fp.DefineString(&fFilePathForKey, "FILEPATHFORKEY")
}
/*
@@ -40,8 +40,8 @@ Shell command to run this test:
--SSH_SSHPORT=22 \
--SSH_SSHUSERNAME="root" \
--SSH_SSHPASSWORD="password" \
--SSH_OUTPUTCERTPATH="/path/to/your-output-cert.pem" \
--SSH_OUTPUTKEYPATH="/path/to/your-output-key.pem"
--SSH_FILEPATHFORCRT="/path/to/your-output-cert.pem" \
--SSH_FILEPATHFORKEY="/path/to/your-output-key.pem"
*/
func TestProvider(t *testing.T) {
fp.Parse()
+8 -3
View File
@@ -20,7 +20,7 @@ import (
// 出参:
// - data: PFX 格式的证书数据。
// - err: 错误。
func TransformCertificateFromPEMToPFX(certPEM string, privkeyPEM string, pfxPassword string) ([]byte, error) {
func TransformCertificateFromPEMToPFX(certPEM string, privkeyPEM string, pfxPassword string, pfxEncoder *pkcs12.Encoder) ([]byte, error) {
blocks := decodePEMBlocks([]byte(certPEM))
certs := make([]*x509.Certificate, 0, len(blocks))
@@ -41,13 +41,18 @@ func TransformCertificateFromPEMToPFX(certPEM string, privkeyPEM string, pfxPass
return nil, err
}
encoder := pfxEncoder
if encoder == nil {
encoder = pkcs12.Legacy
}
var pfxData []byte
if len(certs) == 0 {
return nil, fmt.Errorf("failed to decode certificate PEM")
} else if len(certs) == 1 {
pfxData, err = pkcs12.Legacy.Encode(privkey, certs[0], nil, pfxPassword)
pfxData, err = encoder.Encode(privkey, certs[0], nil, pfxPassword)
} else {
pfxData, err = pkcs12.Legacy.Encode(privkey, certs[0], certs[1:], pfxPassword)
pfxData, err = encoder.Encode(privkey, certs[0], certs[1:], pfxPassword)
}
return pfxData, err
@@ -98,10 +98,7 @@ const BizDeployNodeConfigFieldsProviderFTP = () => {
</Show>
<Show when={fieldFileFormat === FORMAT_PFX}>
<Form.Item
label={t("workflow_node.deploy.form.shared_pfx_password.label")}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.shared_pfx_password.tooltip") }}></span>}
>
<Form.Item label={t("workflow_node.deploy.form.shared_pfx_password.label")}>
<Space.Compact className="w-full">
<Form.Item name={[parentNamePath, "pfxPassword"]} initialValue={initialValues.pfxPassword} rules={[formRule]} noStyle>
<Input placeholder={t("workflow_node.deploy.form.shared_pfx_password.placeholder")} />
@@ -113,6 +110,22 @@ const BizDeployNodeConfigFieldsProviderFTP = () => {
</Tooltip>
</Space.Compact>
</Form.Item>
<Form.Item
name={[parentNamePath, "pfxEncoder"]}
initialValue={initialValues.pfxEncoder}
label={t("workflow_node.deploy.form.shared_pfx_encoder.label")}
rules={[formRule]}
>
<Select
options={["LegacyRC2", "LegacyDES", "Modern2023", "Modern2026"].map((s) => ({
key: s,
label: t(`workflow_node.deploy.form.shared_pfx_encoder.option.${s.toLowerCase()}.label`),
value: s,
}))}
placeholder={t("workflow_node.deploy.form.shared_pfx_encoder.placeholder")}
/>
</Form.Item>
</Show>
<Show when={fieldFileFormat === FORMAT_JKS}>
@@ -187,6 +200,7 @@ const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> })
filePathForCrtOnlyServer: z.string().max(256).nullish(),
filePathForCrtOnlyIntermedia: z.string().max(256).nullish(),
pfxPassword: z.string().nullish(),
pfxEncoder: z.string().nullish(),
jksAlias: z.string().nullish(),
jksKeypass: z.string().nullish(),
jksStorepass: z.string().nullish(),
@@ -343,10 +343,7 @@ const BizDeployNodeConfigFieldsProviderLocal = () => {
</Show>
<Show when={fieldFileFormat === FORMAT_PFX}>
<Form.Item
label={t("workflow_node.deploy.form.shared_pfx_password.label")}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.shared_pfx_password.tooltip") }}></span>}
>
<Form.Item label={t("workflow_node.deploy.form.shared_pfx_password.label")}>
<Space.Compact className="w-full">
<Form.Item name={[parentNamePath, "pfxPassword"]} initialValue={initialValues.pfxPassword} rules={[formRule]} noStyle>
<Input placeholder={t("workflow_node.deploy.form.shared_pfx_password.placeholder")} />
@@ -358,6 +355,22 @@ const BizDeployNodeConfigFieldsProviderLocal = () => {
</Tooltip>
</Space.Compact>
</Form.Item>
<Form.Item
name={[parentNamePath, "pfxEncoder"]}
initialValue={initialValues.pfxEncoder}
label={t("workflow_node.deploy.form.shared_pfx_encoder.label")}
rules={[formRule]}
>
<Select
options={["LegacyRC2", "LegacyDES", "Modern2023", "Modern2026"].map((s) => ({
key: s,
label: t(`workflow_node.deploy.form.shared_pfx_encoder.option.${s.toLowerCase()}.label`),
value: s,
}))}
placeholder={t("workflow_node.deploy.form.shared_pfx_encoder.placeholder")}
/>
</Form.Item>
</Show>
<Show when={fieldFileFormat === FORMAT_JKS}>
@@ -522,6 +535,7 @@ const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> })
filePathForCrtOnlyServer: z.string().max(256).nullish(),
filePathForCrtOnlyIntermedia: z.string().max(256).nullish(),
pfxPassword: z.string().nullish(),
pfxEncoder: z.string().nullish(),
jksAlias: z.string().nullish(),
jksKeypass: z.string().nullish(),
jksStorepass: z.string().nullish(),
@@ -114,10 +114,7 @@ const BizDeployNodeConfigFieldsProviderS3 = () => {
</Show>
<Show when={fieldFileFormat === FORMAT_PFX}>
<Form.Item
label={t("workflow_node.deploy.form.shared_pfx_password.label")}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.shared_pfx_password.tooltip") }}></span>}
>
<Form.Item label={t("workflow_node.deploy.form.shared_pfx_password.label")}>
<Space.Compact className="w-full">
<Form.Item name={[parentNamePath, "pfxPassword"]} initialValue={initialValues.pfxPassword} rules={[formRule]} noStyle>
<Input placeholder={t("workflow_node.deploy.form.shared_pfx_password.placeholder")} />
@@ -129,6 +126,22 @@ const BizDeployNodeConfigFieldsProviderS3 = () => {
</Tooltip>
</Space.Compact>
</Form.Item>
<Form.Item
name={[parentNamePath, "pfxEncoder"]}
initialValue={initialValues.pfxEncoder}
label={t("workflow_node.deploy.form.shared_pfx_encoder.label")}
rules={[formRule]}
>
<Select
options={["LegacyRC2", "LegacyDES", "Modern2023", "Modern2026"].map((s) => ({
key: s,
label: t(`workflow_node.deploy.form.shared_pfx_encoder.option.${s.toLowerCase()}.label`),
value: s,
}))}
placeholder={t("workflow_node.deploy.form.shared_pfx_encoder.placeholder")}
/>
</Form.Item>
</Show>
<Show when={fieldFileFormat === FORMAT_JKS}>
@@ -207,6 +220,7 @@ const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> })
objectKeyForCrtOnlyServer: z.string().max(256).nullish(),
objectKeyForCrtOnlyIntermedia: z.string().max(256).nullish(),
pfxPassword: z.string().nullish(),
pfxEncoder: z.string().nullish(),
jksAlias: z.string().nullish(),
jksKeypass: z.string().nullish(),
jksStorepass: z.string().nullish(),
@@ -309,10 +309,7 @@ const BizDeployNodeConfigFieldsProviderSSH = () => {
</Show>
<Show when={fieldFileFormat === FORMAT_PFX}>
<Form.Item
label={t("workflow_node.deploy.form.shared_pfx_password.label")}
tooltip={<span dangerouslySetInnerHTML={{ __html: t("workflow_node.deploy.form.shared_pfx_password.tooltip") }}></span>}
>
<Form.Item label={t("workflow_node.deploy.form.shared_pfx_password.label")}>
<Space.Compact className="w-full">
<Form.Item name={[parentNamePath, "pfxPassword"]} initialValue={initialValues.pfxPassword} rules={[formRule]} noStyle>
<Input placeholder={t("workflow_node.deploy.form.shared_pfx_password.placeholder")} />
@@ -324,6 +321,22 @@ const BizDeployNodeConfigFieldsProviderSSH = () => {
</Tooltip>
</Space.Compact>
</Form.Item>
<Form.Item
name={[parentNamePath, "pfxEncoder"]}
initialValue={initialValues.pfxEncoder}
label={t("workflow_node.deploy.form.shared_pfx_encoder.label")}
rules={[formRule]}
>
<Select
options={["LegacyRC2", "LegacyDES", "Modern2023", "Modern2026"].map((s) => ({
key: s,
label: t(`workflow_node.deploy.form.shared_pfx_encoder.option.${s.toLowerCase()}.label`),
value: s,
}))}
placeholder={t("workflow_node.deploy.form.shared_pfx_encoder.placeholder")}
/>
</Form.Item>
</Show>
<Show when={fieldFileFormat === FORMAT_JKS}>
@@ -480,6 +493,7 @@ const getSchema = ({ i18n = getI18n() }: { i18n?: ReturnType<typeof getI18n> })
filePathForCrtOnlyServer: z.string().max(256).nullish(),
filePathForCrtOnlyIntermedia: z.string().max(256).nullish(),
pfxPassword: z.string().nullish(),
pfxEncoder: z.string().nullish(),
jksAlias: z.string().nullish(),
jksKeypass: z.string().nullish(),
jksStorepass: z.string().nullish(),
@@ -534,8 +534,25 @@
},
"shared_pfx_password": {
"label": "PFX password",
"placeholder": "Please enter PFX password",
"tooltip": "For more information, see <a href=\"https://learn.microsoft.com/en-us/windows-hardware/drivers/install/personal-information-exchange---pfx--files\" target=\"_blank\">https://learn.microsoft.com/en-us/windows-hardware/drivers/install/personal-information-exchange---pfx--files</a>"
"placeholder": "Please enter PFX password"
},
"shared_pfx_encoder": {
"label": "PFX encoder (Optional)",
"placeholder": "Please select PFX encoder",
"option": {
"legacyrc2": {
"label": "LegacyRC2 (RC2, compatible with older systems, but less secure)"
},
"legacydes": {
"label": "LegacyDES (3DES + SHA-1, default)"
},
"modern2023": {
"label": "Modern2023 (AES-256-CBC + SHA-256 MAC, compatible with OpenSSL v1.1.1+)"
},
"modern2026": {
"label": "Modern2026 (AES-256-CBC + PBMAC1 MAC, compatible with OpenSSL v3.4.0+)"
}
}
},
"shared_jks_alias": {
"label": "JKS alias",
@@ -533,8 +533,25 @@
},
"shared_pfx_password": {
"label": "PFX 导出密码",
"placeholder": "请输入 PFX 导出密码",
"tooltip": "这是什么?请参阅 <a href=\"https://learn.microsoft.com/zh-cn/windows-hardware/drivers/install/personal-information-exchange---pfx--files\" target=\"_blank\">https://learn.microsoft.com/zh-cn/windows-hardware/drivers/install/personal-information-exchange---pfx--files</a>"
"placeholder": "请输入 PFX 导出密码"
},
"shared_pfx_encoder": {
"label": "PFX 编码器(可选)",
"placeholder": "请选择 PFX 编码器",
"option": {
"legacyrc2": {
"label": "LegacyRC2(RC2,兼容旧系统,但安全性较低)"
},
"legacydes": {
"label": "LegacyDES(3DES + SHA-1,默认值)"
},
"modern2023": {
"label": "Modern2023(AES-256-CBC + SHA-256 MAC,适配 OpenSSL v1.1.1+)"
},
"modern2026": {
"label": "Modern2026(AES-256-CBC + PBMAC1 MAC,适配 OpenSSL v3.4.0+)"
}
}
},
"shared_jks_alias": {
"label": "JKS 别名",