【Golang】用go解析国密pfx文件

1、背景

go的官方库已经支持标密rsa证书相关的功能,对于国密证书也是能在github上找到对应的库:https://github.com/tjfoc/gmsm,下面会给出一个如何解析国密pfx文件的例子。

2、代码示例

【1】解析国密pfx

import (
	"encoding/pem"

	"GoTest/comm/logger"

	gmpkcs12 "github.com/tjfoc/gmsm/pkcs12"
	"go.uber.org/zap"
)

// Sm2PfxToPem
//
//	@Description: 将国密SM2算法的pfx文件解析成pem格式的证书和私钥
//	@param pfxFile 要解析的国密pfx文件
//	@param pwd pfx文件密码
//	@return certPem pem格式的证书
//	@return priKeyPem pem格式的私钥
//	@return err
func Sm2PfxToPem(pfxFile, pwd string) (certPem, priKeyPem string, err error) {
	cert, priKey, err := gmpkcs12.SM2P12Decrypt(pfxFile, pwd)
	if err != nil {
		logger.Error("sm2 p12 decrypt error", zap.Error(err))
		return
	}

	//证书转换成PEM
	certPem = string(pem.EncodeToMemory(&pem.Block{
		Type:  "CERTIFICATE",
		Bytes: cert.Raw,
	}))

	//私钥转换为Pem
	PriKeyBytes, err := gmpkcs12.MarshalECPrivateKey(priKey)
	if err != nil {
		logger.Error("marshal ec private key error", zap.Error(err))
		return
	}

	priKeyPem = string(pem.EncodeToMemory(&pem.Block{
		Type:  "EC PRIVATE KEY",
		Bytes: PriKeyBytes,
	}))

	return
}

【2】单元测试

import "testing"

var pfxFile = "D:\\GoTest\\certs_demo\\gm_cert\\gm_test.pfx"

func TestSm2PfxToPem(t *testing.T) {
	certPem, priKeyPem, err := Sm2PfxToPem(pfxFile, "123456")
	if err != nil {
		t.Error("sm2 pfx to pem error", err)
		return
	}

	t.Log("cert:", certPem, "\nkey:", priKeyPem)
}

【3】执行结果

$ go test -v -run TestSm2PfxToPem
=== RUN   TestSm2PfxToPem
    gm_test.go:14: cert: -----BEGIN CERTIFICATE-----
        MIICoDCCAkSgAwIBAgIQahCmCRXqRbvlycjsKT90hzAMBggqgRzPVQGDdQUAMHMx
        CzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdKaWFuZ1hpMREwDwYDVQQHDAhOYW5DaGFu
        ZzENMAsGA1UECgwESlhDQTEcMBoGA1UECwwTSmlhbmdYaSBST09UIENBIFNNMjES
        MBAGA1UEAwwJSlhDQV9URVNUMB4XDTIxMTEyMjA5MjQxM1oXDTIyMTEyMjA5MjQx
        M1owgZExCzAJBgNVBAYTAkNOMRAwDgYDVQQIDAdCZWlKaW5nMRAwDgYDVQQHDAdC
        ZWlKaW5nMRAwDgYDVQQKDAdxaWFueGluMRAwDgYDVQQLDAdxaWFueGluMSIwIAYJ
        KoZIhvcNAQkBFhNxaWFueGluQFFJQU5YSU4uY29tMRYwFAYDVQQDDA1sZWdlbmRz
        ZWMuY29tMFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAEyAV//1n86fjrh/KaYTqM
        c3DzBXZvpczXlfFXQAypONe1NZ58+Fla543r1aw/f4MQU4uQvuPSYdvVehB4Eeqf
        36OBmDCBlTAfBgNVHSMEGDAWgBQIaDOhbxNSRPXR6AR5mzFzpUBCRDARBglghkgB
        hvhCAQEEBAMCBkAwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovLzExMS43NS4xOTgu
        MjQzL2NybDMwLmNybDAOBgNVHQ8BAf8EBAMCBsAwHQYDVR0OBBYEFLsQOV9YrYxc
        YgbFspkIQkBo2o0qMAwGCCqBHM9VAYN1BQADSAAwRQIhAOMIVDyXYBuu5pocBBWr
        czZMBskLU4Lf4qsYvmhY/La7AiB+CSGkZsgS9GMySU5Kn1E+KD114rBquYJ7EgBX
        cZAugg==
        -----END CERTIFICATE-----

        key: -----BEGIN EC PRIVATE KEY-----
        MHcCAQEEIJp5iN8Jb1PiUQC98+Ffp5on2LdeX4yl128YctbFfofxoAoGCCqBHM9V
        AYItoUQDQgAEyAV//1n86fjrh/KaYTqMc3DzBXZvpczXlfFXQAypONe1NZ58+Fla
        543r1aw/f4MQU4uQvuPSYdvVehB4Eeqf3w==
        -----END EC PRIVATE KEY-----

--- PASS: TestSm2PfxToPem (0.00s)
PASS
ok      GoTest/certs_demo/gm_cert/gm    1.709s

3、注意事项

对于包含多个证书和一个私钥的国密pfx文件,SM2P12Decrypt函数返回的证书是取解析到的第一个,可能并不是我们想要的证书,源码如下:

func SM2P12Decrypt(fileName string, pwd string) (*x.Certificate, *sm2.PrivateKey, error) {
	pfxData, _ := ioutil.ReadFile(fileName)
	pv, cer, err := DecodeAll(pfxData, pwd) //直接使用这个函数获取所有证书
	if err != nil {
		return nil, nil, err
	}
	switch k := pv.(type) {
	case *ecdsa.PrivateKey:
		switch k.Curve {
		case sm2.P256Sm2():
			sm2pub := &sm2.PublicKey{
				Curve: k.Curve,
				X:     k.X,
				Y:     k.Y,
			}
			sm2Pri := &sm2.PrivateKey{
				PublicKey: *sm2pub,
				D:         k.D,
			}
			if !k.IsOnCurve(k.X,k.Y) {
				return nil, nil, errors.New("error while validating SM2 private key: %v")
			}
			return cer[0], sm2Pri, nil  //返回第一个证书
		}
	default:
		return nil, nil, errors.New("unexpected type for p12 private key")
	}
	return nil,nil,nil
}

因此我们也可以直接使用DecodeAll函数来获取私钥和所有的证书,再通过证书里的颁发者和主题名等其它字段来获取我们想要的业务证书和ca证书。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值