Skip to content

Commit

Permalink
smx509: refactor p8 parse and pkix public key parse
Browse files Browse the repository at this point in the history
  • Loading branch information
emmansun authored Jan 11, 2024
1 parent 7db8067 commit 25ead7d
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 18 deletions.
1 change: 1 addition & 0 deletions docs/sm2.md
Original file line number Diff line number Diff line change
Expand Up @@ -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/)在线阅读这些标准。
Expand Down
22 changes: 22 additions & 0 deletions smx509/parser.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)
Expand Down Expand Up @@ -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.
Expand Down
29 changes: 29 additions & 0 deletions smx509/parser_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package smx509

import (
"encoding/asn1"
"encoding/hex"
"testing"

cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
Expand Down Expand Up @@ -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")
}
}
51 changes: 33 additions & 18 deletions smx509/pkcs8.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,27 +46,42 @@ 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) {
case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA):
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 EC private key embedded in PKCS#8: " + err.Error())
}
// 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)
}
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 EC private key embedded in PKCS#8: " + err.Error())
}
if namedCurveOID.Equal(oidNamedCurveP256SM2) {
key, err = new(sm2.PrivateKey).FromECPrivateKey(ecKey)
} else {
key = ecKey
}
return key, err
}

func parseSM9PrivateKey(privKey pkcs8) (key any, err error) {
Expand Down
3 changes: 3 additions & 0 deletions smx509/x509.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down

1 comment on commit 25ead7d

@emmansun
Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

support openssl3(till openssl 3.2.0) generated sm2 keys whose alg oid is 1.2.156.10197.1.301

Please sign in to comment.