smx509: refactor p8 parse and pkix public key parse

This commit is contained in:
Sun Yimin 2024-01-11 17:45:55 +08:00 committed by GitHub
parent 7db8067549
commit 25ead7dc1f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 88 additions and 18 deletions

View File

@ -7,6 +7,7 @@
* 《GB/T 32918.4-2016 信息安全技术 SM2椭圆曲线公钥密码算法 第4部分公钥加密算法》
* 《GB/T 32918.5-2016 信息安全技术 SM2椭圆曲线公钥密码算法 第5部分参数定义》
* 《GB/T 35276-2017 信息安全技术 SM2密码算法使用规范》
* 《GB/T 33560-2017 信息安全技术 密码应用标识规范》
* 《GB/T 35275-2017 信息安全技术 SM2密码算法加密签名消息语法规范》(对应PKCS#7)
您可以从[国家标准全文公开系统](https://openstd.samr.gov.cn/)在线阅读这些标准。

View File

@ -21,6 +21,7 @@ import (
"unicode/utf16"
"unicode/utf8"
"github.com/emmansun/gmsm/sm2"
"golang.org/x/crypto/cryptobyte"
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
)
@ -288,6 +289,27 @@ func parsePublicKey(keyData *publicKeyInfo) (any, error) {
Y: y,
}
return pub, nil
case oid.Equal(oidPublicKeySM2):
paramsDer := cryptobyte.String(params.FullBytes)
namedCurveOID := new(asn1.ObjectIdentifier)
if !paramsDer.ReadASN1ObjectIdentifier(namedCurveOID) {
return nil, errors.New("x509: invalid SM2 parameters")
}
namedCurve := namedCurveFromOID(*namedCurveOID)
if namedCurve != sm2.P256() {
return nil, errors.New("x509: unsupported SM2 curve")
}
x, y := elliptic.Unmarshal(namedCurve, der)
if x == nil {
return nil, errors.New("x509: failed to unmarshal SM2 curve point")
}
pub := &ecdsa.PublicKey{
Curve: namedCurve,
X: x,
Y: y,
}
return pub, nil
case oid.Equal(oidPublicKeyEd25519):
// RFC 8410, Section 3
// > For all of the OIDs, the parameters MUST be absent.

View File

@ -2,6 +2,7 @@ package smx509
import (
"encoding/asn1"
"encoding/hex"
"testing"
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
@ -97,3 +98,31 @@ func TestParseASN1String(t *testing.T) {
})
}
}
// The SM2 public key with alg = oidPublicKeySM2 and SM2 curve
var sm2PublicKeyHex = "305a301406082a811ccf5501822d06082a811ccf5501822d0342000409586fff35c1f805b5c74f7281c3ade8fe211ffa70bf0ddd1c7268f62ae664331410e3039eeb03209afdc7fa834235c7b3ef528d32bf8b401eb98d32f498b4b7"
// The SM2 public key with alg = oidPublicKeySM2 and NIST P256 curve
var sm2NistP256PubulicKeyHex = "305a301406082a811ccf5501822d06082a8648ce3d0301070342000476110a45e7e86c1e96ba3c3300da61049a529c20a7ea7f026e50a2dbed60558087346bcb04cb0f0f8dcab8cca9967b8c7cc5aa0c874f024b73208b28f408bfca"
func TestParseSM2PublicKey(t *testing.T) {
der, err := hex.DecodeString(sm2PublicKeyHex)
if err != nil {
t.Fatal(err)
}
_, err = ParsePKIXPublicKey(der)
if err != nil {
t.Fatal(err)
}
}
func TestParseSM2PublicKeyWithNistP256(t *testing.T) {
der, err := hex.DecodeString(sm2NistP256PubulicKeyHex)
if err != nil {
t.Fatal(err)
}
_, err = ParsePKIXPublicKey(der)
if err == nil || err.Error() != "x509: unsupported SM2 curve" {
t.Fatal("should throw x509: unsupported SM2 curve")
}
}

View File

@ -46,12 +46,24 @@ func ParsePKCS8PrivateKey(der []byte) (key any, err error) {
}
return nil, err
}
if privKey.Algo.Algorithm.Equal(oidSM9) || privKey.Algo.Algorithm.Equal(oidSM9Sign) || privKey.Algo.Algorithm.Equal(oidSM9Enc) {
switch {
case privKey.Algo.Algorithm.Equal(oidPublicKeySM2):
bytes := privKey.Algo.Parameters.FullBytes
namedCurveOID := new(asn1.ObjectIdentifier)
if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil {
namedCurveOID = nil
}
ecKey, err := parseECPrivateKey(namedCurveOID, privKey.PrivateKey)
if err != nil {
return nil, errors.New("x509: failed to parse SM2 private key embedded in PKCS#8: " + err.Error())
}
if ecKey.Curve != sm2.P256() {
return nil, errors.New("x509: unsupported SM2 curve")
}
return new(sm2.PrivateKey).FromECPrivateKey(ecKey)
case privKey.Algo.Algorithm.Equal(oidSM9), privKey.Algo.Algorithm.Equal(oidSM9Sign), privKey.Algo.Algorithm.Equal(oidSM9Enc):
return parseSM9PrivateKey(privKey)
}
if !privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA) && !privKey.Algo.Algorithm.Equal(oidNamedCurveP256SM2) {
return x509.ParsePKCS8PrivateKey(der)
}
case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA):
bytes := privKey.Algo.Parameters.FullBytes
namedCurveOID := new(asn1.ObjectIdentifier)
if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil {
@ -61,12 +73,15 @@ func ParsePKCS8PrivateKey(der []byte) (key any, err error) {
if err != nil {
return nil, errors.New("x509: failed to parse EC private key embedded in PKCS#8: " + err.Error())
}
if namedCurveOID.Equal(oidNamedCurveP256SM2) {
key, err = new(sm2.PrivateKey).FromECPrivateKey(ecKey)
} else {
key = ecKey
// convert *ecdsa.PrivateKey to *sm2.PrivateKey
if ecKey.Curve == sm2.P256() {
return new(sm2.PrivateKey).FromECPrivateKey(ecKey)
}
return ecKey, err
default:
// fallback to golang sdk
return x509.ParsePKCS8PrivateKey(der)
}
return key, err
}
func parseSM9PrivateKey(privKey pkcs8) (key any, err error) {

View File

@ -462,6 +462,9 @@ var (
// id-ecPublicKey OBJECT IDENTIFIER ::= {
// iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
// GB/T 33560-2017 信息安全技术 密码应用标识规范
// 附录A规范性附录商用密码领域中的相关OID定义
oidPublicKeySM2 = asn1.ObjectIdentifier{1, 2, 156, 10197, 1, 301}
// RFC 8410, Section 3
//
// id-X25519 OBJECT IDENTIFIER ::= { 1 3 101 110 }