mirror of
https://github.com/emmansun/gmsm.git
synced 2025-04-26 20:26:19 +08:00
provide convient methods to parse pkcs8 sm9 keys
This commit is contained in:
parent
a7c36d7f30
commit
5db7e63360
@ -18,6 +18,7 @@ import (
|
||||
|
||||
"github.com/emmansun/gmsm/sm2"
|
||||
"github.com/emmansun/gmsm/sm3"
|
||||
"github.com/emmansun/gmsm/sm9"
|
||||
"github.com/emmansun/gmsm/smx509"
|
||||
)
|
||||
|
||||
@ -219,7 +220,7 @@ func ParsePrivateKey(der []byte, password []byte) (interface{}, KDFParameters, e
|
||||
|
||||
key, err := smx509.ParsePKCS8PrivateKey(decryptedKey)
|
||||
if err != nil {
|
||||
return nil, nil, errors.New("pkcs8: failed to parse private key while ParsePKCS8PrivateKey: " + err.Error())
|
||||
return nil, nil, errors.New("pkcs8: incorrect password? failed to parse private key while ParsePKCS8PrivateKey: " + err.Error())
|
||||
}
|
||||
return key, kdfParams, nil
|
||||
}
|
||||
@ -327,7 +328,7 @@ func ParsePKCS8PrivateKeyECDSA(der []byte, v ...[]byte) (*ecdsa.PrivateKey, erro
|
||||
return typedKey, nil
|
||||
}
|
||||
|
||||
// ParsePKCS8PrivateKeySM2 parses encrypted/unencrypted private keys in PKCS#8 format.
|
||||
// ParsePKCS8PrivateKeySM2 parses encrypted/unencrypted SM2 private key in PKCS#8 format.
|
||||
// To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter.
|
||||
func ParsePKCS8PrivateKeySM2(der []byte, v ...[]byte) (*sm2.PrivateKey, error) {
|
||||
key, err := ParsePKCS8PrivateKey(der, v...)
|
||||
@ -341,6 +342,62 @@ func ParsePKCS8PrivateKeySM2(der []byte, v ...[]byte) (*sm2.PrivateKey, error) {
|
||||
return typedKey, nil
|
||||
}
|
||||
|
||||
// ParseSM9SignMasterPrivateKey parses encrypted/unencrypted SM9 sign master private key in PKCS#8 format.
|
||||
// To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter.
|
||||
func ParseSM9SignMasterPrivateKey(der []byte, v ...[]byte) (*sm9.SignMasterPrivateKey, error) {
|
||||
key, err := ParsePKCS8PrivateKey(der, v...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
typedKey, ok := key.(*sm9.SignMasterPrivateKey)
|
||||
if !ok {
|
||||
return nil, errors.New("pkcs8: key block is not of type SM9 sign master private key")
|
||||
}
|
||||
return typedKey, nil
|
||||
}
|
||||
|
||||
// ParseSM9SignPrivateKey parses encrypted/unencrypted SM9 sign private key in PKCS#8 format.
|
||||
// To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter.
|
||||
func ParseSM9SignPrivateKey(der []byte, v ...[]byte) (*sm9.SignPrivateKey, error) {
|
||||
key, err := ParsePKCS8PrivateKey(der, v...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
typedKey, ok := key.(*sm9.SignPrivateKey)
|
||||
if !ok {
|
||||
return nil, errors.New("pkcs8: key block is not of type SM9 sign user private key")
|
||||
}
|
||||
return typedKey, nil
|
||||
}
|
||||
|
||||
// ParseSM9EncryptMasterPrivateKey parses encrypted/unencrypted SM9 encrypt master private key in PKCS#8 format.
|
||||
// To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter.
|
||||
func ParseSM9EncryptMasterPrivateKey(der []byte, v ...[]byte) (*sm9.EncryptMasterPrivateKey, error) {
|
||||
key, err := ParsePKCS8PrivateKey(der, v...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
typedKey, ok := key.(*sm9.EncryptMasterPrivateKey)
|
||||
if !ok {
|
||||
return nil, errors.New("pkcs8: key block is not of type SM9 encrypt master private key")
|
||||
}
|
||||
return typedKey, nil
|
||||
}
|
||||
|
||||
// ParseSM9EncryptPrivateKey parses encrypted/unencrypted SM9 encrypt private key in PKCS#8 format.
|
||||
// To parse encrypted private keys, a password of []byte type should be provided to the function as the second parameter.
|
||||
func ParseSM9EncryptPrivateKey(der []byte, v ...[]byte) (*sm9.EncryptPrivateKey, error) {
|
||||
key, err := ParsePKCS8PrivateKey(der, v...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
typedKey, ok := key.(*sm9.EncryptPrivateKey)
|
||||
if !ok {
|
||||
return nil, errors.New("pkcs8: key block is not of type SM9 encrypt user private key")
|
||||
}
|
||||
return typedKey, nil
|
||||
}
|
||||
|
||||
// ConvertPrivateKeyToPKCS8 converts the private key into PKCS#8 format.
|
||||
// To encrypt the private key, the password of []byte type should be provided as the second parameter.
|
||||
//
|
||||
|
@ -12,6 +12,7 @@ import (
|
||||
|
||||
"github.com/emmansun/gmsm/pkcs8"
|
||||
"github.com/emmansun/gmsm/sm2"
|
||||
"github.com/emmansun/gmsm/sm9"
|
||||
)
|
||||
|
||||
const rsa2048 = `-----BEGIN PRIVATE KEY-----
|
||||
@ -569,6 +570,90 @@ func TestMarshalPrivateKey(t *testing.T) {
|
||||
t.Fatalf("%d: Decoded key does not match original key", i)
|
||||
}
|
||||
|
||||
sm9SignMasterPrivateKey, err := sm9.GenerateSignMasterKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: GenerateKey returned: %s", i, err)
|
||||
}
|
||||
|
||||
der, err = pkcs8.MarshalPrivateKey(sm9SignMasterPrivateKey, tt.password, tt.opts)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: MarshalPrivateKey returned: %s", i, err)
|
||||
}
|
||||
decodedSM9SignMasterPrivateKey, err := pkcs8.ParseSM9SignMasterPrivateKey(der, tt.password)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: ParseSM9SignMasterPrivateKey returned: %s", i, err)
|
||||
}
|
||||
|
||||
_, err = pkcs8.ParseSM9SignPrivateKey(der, tt.password)
|
||||
if err == nil {
|
||||
t.Fatalf("%d: ParseSM9SignPrivateKey should return error", i)
|
||||
}
|
||||
|
||||
if sm9SignMasterPrivateKey.D.Cmp(decodedSM9SignMasterPrivateKey.D) != 0 {
|
||||
t.Fatalf("%d: Decoded key does not match original key", i)
|
||||
}
|
||||
|
||||
sm9SignPrivateKey, err := sm9SignMasterPrivateKey.GenerateUserKey([]byte("emmansun"), 0x01)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: GenerateUserKey returned: %s", i, err)
|
||||
}
|
||||
der, err = pkcs8.MarshalPrivateKey(sm9SignPrivateKey, tt.password, tt.opts)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: MarshalPrivateKey returned: %s", i, err)
|
||||
}
|
||||
decodedSM9SignPrivateKey, err := pkcs8.ParseSM9SignPrivateKey(der, tt.password)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: ParseSM9SignPrivateKey returned: %s", i, err)
|
||||
}
|
||||
_, err = pkcs8.ParseSM9SignMasterPrivateKey(der, tt.password)
|
||||
if err == nil {
|
||||
t.Fatalf("%d: ParseSM9SignMasterPrivateKey should return error", i)
|
||||
}
|
||||
if !sm9SignPrivateKey.PrivateKey.Equal(decodedSM9SignPrivateKey.PrivateKey) {
|
||||
t.Fatalf("%d: Decoded key does not match original key", i)
|
||||
}
|
||||
|
||||
sm9EncMasterPrivateKey, err := sm9.GenerateEncryptMasterKey(rand.Reader)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: GenerateKey returned: %s", i, err)
|
||||
}
|
||||
|
||||
der, err = pkcs8.MarshalPrivateKey(sm9EncMasterPrivateKey, tt.password, tt.opts)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: MarshalPrivateKey returned: %s", i, err)
|
||||
}
|
||||
decodedSM9EncMasterPrivateKey, err := pkcs8.ParseSM9EncryptMasterPrivateKey(der, tt.password)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: ParseSM9EncryptMasterPrivateKey returned: %s", i, err)
|
||||
}
|
||||
_, err = pkcs8.ParseSM9EncryptPrivateKey(der, tt.password)
|
||||
if err == nil {
|
||||
t.Fatalf("%d: ParseSM9EncryptPrivateKey should return error", i)
|
||||
}
|
||||
if sm9EncMasterPrivateKey.D.Cmp(decodedSM9EncMasterPrivateKey.D) != 0 {
|
||||
t.Fatalf("%d: Decoded key does not match original key", i)
|
||||
}
|
||||
|
||||
sm9EncPrivateKey, err := sm9EncMasterPrivateKey.GenerateUserKey([]byte("emmansun"), 0x02)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: GenerateUserKey returned: %s", i, err)
|
||||
}
|
||||
der, err = pkcs8.MarshalPrivateKey(sm9EncPrivateKey, tt.password, tt.opts)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: MarshalPrivateKey returned: %s", i, err)
|
||||
}
|
||||
decodedSM9EncPrivateKey, err := pkcs8.ParseSM9EncryptPrivateKey(der, tt.password)
|
||||
if err != nil {
|
||||
t.Fatalf("%d: ParseSM9EncryptPrivateKey returned: %s", i, err)
|
||||
}
|
||||
_, err = pkcs8.ParseSM9EncryptMasterPrivateKey(der, tt.password)
|
||||
if err == nil {
|
||||
t.Fatalf("%d: ParseSM9EncryptMasterPrivateKey should return error", i)
|
||||
}
|
||||
if !sm9EncPrivateKey.PrivateKey.Equal(decodedSM9EncPrivateKey.PrivateKey) {
|
||||
t.Fatalf("%d: Decoded key does not match original key", i)
|
||||
}
|
||||
|
||||
for _, curve := range []elliptic.Curve{
|
||||
elliptic.P224(), elliptic.P256(), elliptic.P384(), elliptic.P521(),
|
||||
} {
|
||||
|
@ -1,7 +1,6 @@
|
||||
package sm9
|
||||
|
||||
import (
|
||||
"encoding/asn1"
|
||||
"encoding/pem"
|
||||
|
||||
"errors"
|
||||
@ -209,33 +208,28 @@ func (pub *SignMasterPublicKey) UnmarshalRaw(bytes []byte) error {
|
||||
// UnmarshalASN1 unmarsal der data to sign master public key
|
||||
func (pub *SignMasterPublicKey) UnmarshalASN1(der []byte) error {
|
||||
var bytes []byte
|
||||
var inner cryptobyte.String
|
||||
input := cryptobyte.String(der)
|
||||
if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() {
|
||||
if der[0] == 0x30 {
|
||||
if !input.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) ||
|
||||
!input.Empty() ||
|
||||
!inner.ReadASN1BitStringAsBytes(&bytes) ||
|
||||
!inner.Empty() {
|
||||
return errors.New("sm9: invalid sign master public key asn1 data")
|
||||
}
|
||||
} else if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() {
|
||||
return errors.New("sm9: invalid sign master public key asn1 data")
|
||||
}
|
||||
return pub.UnmarshalRaw(bytes)
|
||||
}
|
||||
|
||||
type publicKeyInfo struct {
|
||||
Raw asn1.RawContent
|
||||
PublicKey asn1.BitString
|
||||
}
|
||||
|
||||
// ParseFromPEM just for GMSSL, there are no Algorithm pkix.AlgorithmIdentifier
|
||||
func (pub *SignMasterPublicKey) ParseFromPEM(data []byte) error {
|
||||
block, _ := pem.Decode([]byte(data))
|
||||
if block == nil {
|
||||
return errors.New("failed to parse PEM block")
|
||||
}
|
||||
|
||||
var pki publicKeyInfo
|
||||
if rest, err := asn1.Unmarshal(block.Bytes, &pki); err != nil {
|
||||
return err
|
||||
} else if len(rest) != 0 {
|
||||
return errors.New("trailing data after ASN.1 of public-key")
|
||||
}
|
||||
der := cryptobyte.String(pki.PublicKey.RightAlign())
|
||||
return pub.UnmarshalRaw(der)
|
||||
return pub.UnmarshalASN1(block.Bytes)
|
||||
}
|
||||
|
||||
// MasterPublic returns the master public key corresponding to priv.
|
||||
@ -467,22 +461,22 @@ func (pub *EncryptMasterPublicKey) ParseFromPEM(data []byte) error {
|
||||
if block == nil {
|
||||
return errors.New("failed to parse PEM block")
|
||||
}
|
||||
|
||||
var pki publicKeyInfo
|
||||
if rest, err := asn1.Unmarshal(block.Bytes, &pki); err != nil {
|
||||
return err
|
||||
} else if len(rest) != 0 {
|
||||
return errors.New("trailing data after ASN.1 of public-key")
|
||||
}
|
||||
der := cryptobyte.String(pki.PublicKey.RightAlign())
|
||||
return pub.UnmarshalRaw(der)
|
||||
return pub.UnmarshalASN1(block.Bytes)
|
||||
}
|
||||
|
||||
// UnmarshalASN1 unmarsal der data to encrypt master public key
|
||||
func (pub *EncryptMasterPublicKey) UnmarshalASN1(der []byte) error {
|
||||
var bytes []byte
|
||||
var inner cryptobyte.String
|
||||
input := cryptobyte.String(der)
|
||||
if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() {
|
||||
if der[0] == 0x30 {
|
||||
if !input.ReadASN1(&inner, cryptobyte_asn1.SEQUENCE) ||
|
||||
!input.Empty() ||
|
||||
!inner.ReadASN1BitStringAsBytes(&bytes) ||
|
||||
!inner.Empty() {
|
||||
return errors.New("sm9: invalid encrypt master public key asn1 data")
|
||||
}
|
||||
} else if !input.ReadASN1BitStringAsBytes(&bytes) || !input.Empty() {
|
||||
return errors.New("sm9: invalid encrypt master public key asn1 data")
|
||||
}
|
||||
return pub.UnmarshalRaw(bytes)
|
||||
|
@ -3,7 +3,11 @@ package sm9
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"encoding/pem"
|
||||
"testing"
|
||||
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
|
||||
)
|
||||
|
||||
func TestSignMasterPrivateKeyMarshalASN1(t *testing.T) {
|
||||
@ -270,6 +274,23 @@ func TestParseSM9SignMasterPublicKey(t *testing.T) {
|
||||
if key.MasterPublicKey == nil {
|
||||
t.Errorf("not expected nil")
|
||||
}
|
||||
|
||||
// create sign master public key PEM with cryptobyte
|
||||
var b cryptobyte.Builder
|
||||
bytes, _ := key.MarshalASN1()
|
||||
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
||||
b.AddBytes(bytes)
|
||||
})
|
||||
data, err := b.Bytes()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := &pem.Block{Bytes: data, Type: "SM9 SIGN MASTER PUBLIC KEY"}
|
||||
pemContent := string(pem.EncodeToMemory(block))
|
||||
|
||||
if pemContent != sm9SignMasterPublicKeyFromGMSSL {
|
||||
t.Fatalf("failed %s\n", pemContent)
|
||||
}
|
||||
}
|
||||
|
||||
const sm9EncMasterPublicKeyFromGMSSL = `-----BEGIN SM9 ENC MASTER PUBLIC KEY-----
|
||||
@ -287,4 +308,24 @@ func TestParseSM9EncryptMasterPublicKey(t *testing.T) {
|
||||
if key.MasterPublicKey == nil {
|
||||
t.Errorf("not expected nil")
|
||||
}
|
||||
|
||||
// create encrypt master public key PEM with asn1
|
||||
var b cryptobyte.Builder
|
||||
|
||||
b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
|
||||
b.AddASN1BitString(key.MasterPublicKey.MarshalUncompressed())
|
||||
})
|
||||
data, err := b.Bytes()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
block := &pem.Block{Bytes: data, Type: "SM9 ENC MASTER PUBLIC KEY"}
|
||||
pemContent := string(pem.EncodeToMemory(block))
|
||||
|
||||
if pemContent != sm9EncMasterPublicKeyFromGMSSL {
|
||||
t.Fatalf("failed %s\n", pemContent)
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user