MAGIC - implement MarshalPKIXPublicKey

This commit is contained in:
Emman 2021-01-20 15:05:24 +08:00
parent 8b0741fed9
commit cd8d60fc16
2 changed files with 58 additions and 5 deletions

View File

@ -3,12 +3,20 @@ package sm2
import ( import (
"crypto/ecdsa" "crypto/ecdsa"
"crypto/elliptic" "crypto/elliptic"
"crypto/x509"
"crypto/x509/pkix" "crypto/x509/pkix"
"encoding/asn1" "encoding/asn1"
"errors" "errors"
"math/big" "math/big"
) )
// pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo
// in RFC 3280.
type pkixPublicKey struct {
Algo pkix.AlgorithmIdentifier
BitString asn1.BitString
}
type publicKeyInfo struct { type publicKeyInfo struct {
Raw asn1.RawContent Raw asn1.RawContent
Algorithm pkix.AlgorithmIdentifier Algorithm pkix.AlgorithmIdentifier
@ -45,13 +53,12 @@ func ParsePKIXPublicKey(derBytes []byte) (interface{}, error) {
} }
if !pki.Algorithm.Algorithm.Equal(oidPublicKeyECDSA) { if !pki.Algorithm.Algorithm.Equal(oidPublicKeyECDSA) {
return nil, errors.New("x509: invalid public key algorithm") return x509.ParsePKIXPublicKey(derBytes)
} }
keyData := &pki keyData := &pki
asn1Data := keyData.PublicKey.RightAlign() asn1Data := keyData.PublicKey.RightAlign()
paramsData := keyData.Algorithm.Parameters.FullBytes paramsData := keyData.Algorithm.Parameters.FullBytes
namedCurveOID := new(asn1.ObjectIdentifier) namedCurveOID := new(asn1.ObjectIdentifier)
namedCurve := P256()
rest, err := asn1.Unmarshal(paramsData, namedCurveOID) rest, err := asn1.Unmarshal(paramsData, namedCurveOID)
if err != nil { if err != nil {
return nil, errors.New("x509: failed to parse ECDSA parameters as named curve") return nil, errors.New("x509: failed to parse ECDSA parameters as named curve")
@ -60,8 +67,9 @@ func ParsePKIXPublicKey(derBytes []byte) (interface{}, error) {
return nil, errors.New("x509: trailing data after ECDSA parameters") return nil, errors.New("x509: trailing data after ECDSA parameters")
} }
if !namedCurveOID.Equal(oidNamedCurveP256SM2) { if !namedCurveOID.Equal(oidNamedCurveP256SM2) {
return nil, errors.New("x509: it's not SM2 elliptic curve") return x509.ParsePKIXPublicKey(derBytes)
} }
namedCurve := P256()
x, y := elliptic.Unmarshal(namedCurve, asn1Data) x, y := elliptic.Unmarshal(namedCurve, asn1Data)
if x == nil { if x == nil {
return nil, errors.New("x509: failed to unmarshal elliptic curve point") return nil, errors.New("x509: failed to unmarshal elliptic curve point")
@ -73,3 +81,32 @@ func ParsePKIXPublicKey(derBytes []byte) (interface{}, error) {
} }
return pub, nil return pub, nil
} }
// MarshalPKIXPublicKey converts a public key to PKIX, ASN.1 DER form.
//
// The following key types are currently supported: *rsa.PublicKey, *ecdsa.PublicKey
// and ed25519.PublicKey. Unsupported key types result in an error.
//
// This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY".
func MarshalPKIXPublicKey(pub interface{}) ([]byte, error) {
ecdPub, ok := pub.(*ecdsa.PublicKey)
if !ok || ecdPub.Curve != P256() {
return x509.MarshalPKIXPublicKey(pub)
}
publicKeyAlgorithm := pkix.AlgorithmIdentifier{Algorithm: oidPublicKeyECDSA}
publicKeyBytes := elliptic.Marshal(ecdPub.Curve, ecdPub.X, ecdPub.Y)
paramBytes, _ := asn1.Marshal(oidNamedCurveP256SM2)
publicKeyAlgorithm.Parameters.FullBytes = paramBytes
pkix := pkixPublicKey{
Algo: publicKeyAlgorithm,
BitString: asn1.BitString{
Bytes: publicKeyBytes,
BitLength: 8 * len(publicKeyBytes),
},
}
ret, _ := asn1.Marshal(pkix)
return ret, nil
}

View File

@ -5,11 +5,11 @@ import (
"crypto/rand" "crypto/rand"
"encoding/pem" "encoding/pem"
"errors" "errors"
"strings"
"testing" "testing"
) )
const publicKeyPemFromAliKms = ` const publicKeyPemFromAliKms = `-----BEGIN PUBLIC KEY-----
-----BEGIN PUBLIC KEY-----
MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAELfjZP28bYfGSvbODYlXiB5bcoXE+ MFkwEwYHKoZIzj0CAQYIKoEcz1UBgi0DQgAELfjZP28bYfGSvbODYlXiB5bcoXE+
2LRjjpIH3DcCCct9FuVhi9cm60nDFrbW49k2D3GJco2iWPlr0+5LV+t4AQ== 2LRjjpIH3DcCCct9FuVhi9cm60nDFrbW49k2D3GJco2iWPlr0+5LV+t4AQ==
-----END PUBLIC KEY----- -----END PUBLIC KEY-----
@ -34,3 +34,19 @@ func TestParsePKIXPublicKey(t *testing.T) {
t.Fatal(err) t.Fatal(err)
} }
} }
func TestMarshalPKIXPublicKey(t *testing.T) {
pub, err := getPublicKey([]byte(publicKeyPemFromAliKms))
if err != nil {
t.Fatal(err)
}
result, err := MarshalPKIXPublicKey(pub)
if err != nil {
t.Fatal(err)
}
block := &pem.Block{Bytes: result, Type: "PUBLIC KEY"}
pemContent := string(pem.EncodeToMemory(block))
if !strings.EqualFold(publicKeyPemFromAliKms, pemContent) {
t.Errorf("expected=%s, result=%s", publicKeyPemFromAliKms, pemContent)
}
}