mirror of
https://github.com/emmansun/gmsm.git
synced 2025-05-13 20:46:17 +08:00
smx509: add support for PKCS8/PKIX X25519 key encodings #210
This commit is contained in:
parent
3d4dd002a4
commit
2c0f5f68fc
@ -3,6 +3,7 @@ package smx509
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto/dsa"
|
"crypto/dsa"
|
||||||
|
sdkecdh "crypto/ecdh"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
@ -338,14 +339,13 @@ func parsePublicKey(keyData *publicKeyInfo) (any, error) {
|
|||||||
return nil, errors.New("x509: wrong Ed25519 public key size")
|
return nil, errors.New("x509: wrong Ed25519 public key size")
|
||||||
}
|
}
|
||||||
return ed25519.PublicKey(der), nil
|
return ed25519.PublicKey(der), nil
|
||||||
//TODO: will enable it since golang 1.19.x
|
case oid.Equal(oidPublicKeyX25519):
|
||||||
//case oid.Equal(oidPublicKeyX25519):
|
// RFC 8410, Section 3
|
||||||
// RFC 8410, Section 3
|
// > For all of the OIDs, the parameters MUST be absent.
|
||||||
// > For all of the OIDs, the parameters MUST be absent.
|
if len(params.FullBytes) != 0 {
|
||||||
// if len(params.FullBytes) != 0 {
|
return nil, errors.New("x509: X25519 key encoded with illegal parameters")
|
||||||
// return nil, errors.New("x509: X25519 key encoded with illegal parameters")
|
}
|
||||||
// }
|
return sdkecdh.X25519().NewPublicKey(der)
|
||||||
// return ecdh.X25519().NewPublicKey(der)
|
|
||||||
case oid.Equal(oidPublicKeyDSA):
|
case oid.Equal(oidPublicKeyDSA):
|
||||||
y := new(big.Int)
|
y := new(big.Int)
|
||||||
if !der.ReadASN1Integer(y) {
|
if !der.ReadASN1Integer(y) {
|
||||||
|
@ -61,8 +61,10 @@ func ParsePKCS8PrivateKey(der []byte) (key any, err error) {
|
|||||||
return nil, errors.New("x509: unsupported SM2 curve")
|
return nil, errors.New("x509: unsupported SM2 curve")
|
||||||
}
|
}
|
||||||
return new(sm2.PrivateKey).FromECPrivateKey(ecKey)
|
return new(sm2.PrivateKey).FromECPrivateKey(ecKey)
|
||||||
|
|
||||||
case privKey.Algo.Algorithm.Equal(oidSM9), privKey.Algo.Algorithm.Equal(oidSM9Sign), privKey.Algo.Algorithm.Equal(oidSM9Enc):
|
case privKey.Algo.Algorithm.Equal(oidSM9), privKey.Algo.Algorithm.Equal(oidSM9Sign), privKey.Algo.Algorithm.Equal(oidSM9Enc):
|
||||||
return parseSM9PrivateKey(privKey)
|
return parseSM9PrivateKey(privKey)
|
||||||
|
|
||||||
case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA):
|
case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA):
|
||||||
bytes := privKey.Algo.Parameters.FullBytes
|
bytes := privKey.Algo.Parameters.FullBytes
|
||||||
namedCurveOID := new(asn1.ObjectIdentifier)
|
namedCurveOID := new(asn1.ObjectIdentifier)
|
||||||
@ -78,6 +80,7 @@ func ParsePKCS8PrivateKey(der []byte) (key any, err error) {
|
|||||||
return new(sm2.PrivateKey).FromECPrivateKey(ecKey)
|
return new(sm2.PrivateKey).FromECPrivateKey(ecKey)
|
||||||
}
|
}
|
||||||
return ecKey, err
|
return ecKey, err
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// fallback to golang sdk
|
// fallback to golang sdk
|
||||||
return x509.ParsePKCS8PrivateKey(der)
|
return x509.ParsePKCS8PrivateKey(der)
|
||||||
|
@ -2,6 +2,7 @@ package smx509
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
|
sdkecdh "crypto/ecdh"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
@ -55,6 +56,11 @@ var pkcs8P521PrivateKeyHex = `3081ee020100301006072a8648ce3d020106052b8104002304
|
|||||||
// From RFC 8410, Section 7.
|
// From RFC 8410, Section 7.
|
||||||
var pkcs8Ed25519PrivateKeyHex = `302e020100300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842`
|
var pkcs8Ed25519PrivateKeyHex = `302e020100300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842`
|
||||||
|
|
||||||
|
// Generated using:
|
||||||
|
//
|
||||||
|
// openssl genpkey -algorithm x25519
|
||||||
|
var pkcs8X25519PrivateKeyHex = `302e020100300506032b656e0422042068ff93a73c5adefd6d498b24e588fd4daa10924d992afed01b43ca5725025a6b`
|
||||||
|
|
||||||
func TestPKCS8(t *testing.T) {
|
func TestPKCS8(t *testing.T) {
|
||||||
tests := []struct {
|
tests := []struct {
|
||||||
name string
|
name string
|
||||||
@ -108,6 +114,11 @@ func TestPKCS8(t *testing.T) {
|
|||||||
keyHex: pkcs8Ed25519PrivateKeyHex,
|
keyHex: pkcs8Ed25519PrivateKeyHex,
|
||||||
keyType: reflect.TypeOf(ed25519.PrivateKey{}),
|
keyType: reflect.TypeOf(ed25519.PrivateKey{}),
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "X25519 private key",
|
||||||
|
keyHex: pkcs8X25519PrivateKeyHex,
|
||||||
|
keyType: reflect.TypeOf(&sdkecdh.PrivateKey{}),
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, test := range tests {
|
for _, test := range tests {
|
||||||
|
@ -22,6 +22,7 @@ package smx509
|
|||||||
import (
|
import (
|
||||||
"bytes"
|
"bytes"
|
||||||
"crypto"
|
"crypto"
|
||||||
|
sdkecdh "crypto/ecdh"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
@ -66,8 +67,9 @@ type pkixPublicKey struct {
|
|||||||
// The encoded public key is a SubjectPublicKeyInfo structure
|
// The encoded public key is a SubjectPublicKeyInfo structure
|
||||||
// (see RFC 5280, Section 4.1).
|
// (see RFC 5280, Section 4.1).
|
||||||
//
|
//
|
||||||
// It returns a *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey, or
|
// It returns a *[rsa.PublicKey], *[dsa.PublicKey], *[ecdsa.PublicKey],
|
||||||
// ed25519.PublicKey. More types might be supported in the future.
|
// [ed25519.PublicKey] (not a pointer), or *[ecdh.PublicKey] (for X25519).
|
||||||
|
// More types might be supported in the future.
|
||||||
//
|
//
|
||||||
// This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY".
|
// This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY".
|
||||||
func ParsePKIXPublicKey(derBytes []byte) (any, error) {
|
func ParsePKIXPublicKey(derBytes []byte) (any, error) {
|
||||||
@ -116,9 +118,25 @@ func marshalPublicKey(pub any) (publicKeyBytes []byte, publicKeyAlgorithm pkix.A
|
|||||||
case ed25519.PublicKey:
|
case ed25519.PublicKey:
|
||||||
publicKeyBytes = pub
|
publicKeyBytes = pub
|
||||||
publicKeyAlgorithm.Algorithm = oidPublicKeyEd25519
|
publicKeyAlgorithm.Algorithm = oidPublicKeyEd25519
|
||||||
case *ecdh.PublicKey: //TODO:will add SDK ECDH public key support from golang 1.19 later.
|
case *sdkecdh.PublicKey:
|
||||||
|
publicKeyBytes = pub.Bytes()
|
||||||
|
if pub.Curve() == sdkecdh.X25519() {
|
||||||
|
publicKeyAlgorithm.Algorithm = oidPublicKeyX25519
|
||||||
|
} else {
|
||||||
|
oid, ok := oidFromSDKECDHCurve(pub.Curve())
|
||||||
|
if !ok {
|
||||||
|
return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve")
|
||||||
|
}
|
||||||
|
publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA
|
||||||
|
var paramBytes []byte
|
||||||
|
paramBytes, err = asn1.Marshal(oid)
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
publicKeyAlgorithm.Parameters.FullBytes = paramBytes
|
||||||
|
}
|
||||||
|
case *ecdh.PublicKey:
|
||||||
publicKeyBytes = pub.Bytes()
|
publicKeyBytes = pub.Bytes()
|
||||||
|
|
||||||
oid, ok := oidFromECDHCurve(pub.Curve())
|
oid, ok := oidFromECDHCurve(pub.Curve())
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve")
|
return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve")
|
||||||
@ -562,6 +580,21 @@ func oidFromECDHCurve(curve ecdh.Curve) (asn1.ObjectIdentifier, bool) {
|
|||||||
return nil, false
|
return nil, false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func oidFromSDKECDHCurve(curve sdkecdh.Curve) (asn1.ObjectIdentifier, bool) {
|
||||||
|
switch curve {
|
||||||
|
case sdkecdh.X25519():
|
||||||
|
return oidPublicKeyX25519, true
|
||||||
|
case sdkecdh.P256():
|
||||||
|
return oidNamedCurveP256, true
|
||||||
|
case sdkecdh.P384():
|
||||||
|
return oidNamedCurveP384, true
|
||||||
|
case sdkecdh.P521():
|
||||||
|
return oidNamedCurveP521, true
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil, false
|
||||||
|
}
|
||||||
|
|
||||||
// KeyUsage represents the set of actions that are valid for a given key. It's
|
// KeyUsage represents the set of actions that are valid for a given key. It's
|
||||||
// a bitmap of the KeyUsage* constants.
|
// a bitmap of the KeyUsage* constants.
|
||||||
type KeyUsage = x509.KeyUsage
|
type KeyUsage = x509.KeyUsage
|
||||||
|
@ -4,6 +4,7 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"crypto"
|
"crypto"
|
||||||
"crypto/dsa"
|
"crypto/dsa"
|
||||||
|
sdkecdh "crypto/ecdh"
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
"crypto/ed25519"
|
"crypto/ed25519"
|
||||||
"crypto/elliptic"
|
"crypto/elliptic"
|
||||||
@ -75,6 +76,13 @@ func TestParsePKIXPublicKey(t *testing.T) {
|
|||||||
t.Errorf("Value returned from ParsePKIXPublicKey was not an Ed25519 public key")
|
t.Errorf("Value returned from ParsePKIXPublicKey was not an Ed25519 public key")
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
t.Run("X25519", func(t *testing.T) {
|
||||||
|
pub := testParsePKIXPublicKey(t, pemX25519Key)
|
||||||
|
k, ok := pub.(*sdkecdh.PublicKey)
|
||||||
|
if !ok || k.Curve() != sdkecdh.X25519() {
|
||||||
|
t.Errorf("Value returned from ParsePKIXPublicKey was not an X25519 public key")
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
var pemPublicKey = `-----BEGIN PUBLIC KEY-----
|
var pemPublicKey = `-----BEGIN PUBLIC KEY-----
|
||||||
@ -113,6 +121,13 @@ MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=
|
|||||||
-----END PUBLIC KEY-----
|
-----END PUBLIC KEY-----
|
||||||
`
|
`
|
||||||
|
|
||||||
|
// pemX25519Key was generated from pemX25519Key with "openssl pkey -pubout".
|
||||||
|
var pemX25519Key = `
|
||||||
|
-----BEGIN PUBLIC KEY-----
|
||||||
|
MCowBQYDK2VuAyEA5yGXrH/6OzxuWEhEWS01/f4OP+Of3Yrddy6/J1kDTVM=
|
||||||
|
-----END PUBLIC KEY-----
|
||||||
|
`
|
||||||
|
|
||||||
func TestPKIXMismatchPublicKeyFormat(t *testing.T) {
|
func TestPKIXMismatchPublicKeyFormat(t *testing.T) {
|
||||||
|
|
||||||
const pkcs1PublicKey = "308201080282010100817cfed98bcaa2e2a57087451c7674e0c675686dc33ff1268b0c2a6ee0202dec710858ee1c31bdf5e7783582e8ca800be45f3275c6576adc35d98e26e95bb88ca5beb186f853b8745d88bc9102c5f38753bcda519fb05948d5c77ac429255ff8aaf27d9f45d1586e95e2e9ba8a7cb771b8a09dd8c8fed3f933fd9b439bc9f30c475953418ef25f71a2b6496f53d94d39ce850aa0cc75d445b5f5b4f4ee4db78ab197a9a8d8a852f44529a007ac0ac23d895928d60ba538b16b0b087a7f903ed29770e215019b77eaecc360f35f7ab11b6d735978795b2c4a74e5bdea4dc6594cd67ed752a108e666729a753ab36d6c4f606f8760f507e1765be8cd744007e629020103"
|
const pkcs1PublicKey = "308201080282010100817cfed98bcaa2e2a57087451c7674e0c675686dc33ff1268b0c2a6ee0202dec710858ee1c31bdf5e7783582e8ca800be45f3275c6576adc35d98e26e95bb88ca5beb186f853b8745d88bc9102c5f38753bcda519fb05948d5c77ac429255ff8aaf27d9f45d1586e95e2e9ba8a7cb771b8a09dd8c8fed3f933fd9b439bc9f30c475953418ef25f71a2b6496f53d94d39ce850aa0cc75d445b5f5b4f4ee4db78ab197a9a8d8a852f44529a007ac0ac23d895928d60ba538b16b0b087a7f903ed29770e215019b77eaecc360f35f7ab11b6d735978795b2c4a74e5bdea4dc6594cd67ed752a108e666729a753ab36d6c4f606f8760f507e1765be8cd744007e629020103"
|
||||||
@ -2464,7 +2479,7 @@ func TestCreateRevocationList(t *testing.T) {
|
|||||||
ThisUpdate: time.Time{}.Add(time.Hour * 24),
|
ThisUpdate: time.Time{}.Add(time.Hour * 24),
|
||||||
NextUpdate: time.Time{}.Add(time.Hour * 48),
|
NextUpdate: time.Time{}.Add(time.Hour * 48),
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "valid, Ed25519 key",
|
name: "valid, Ed25519 key",
|
||||||
key: ed25519Priv,
|
key: ed25519Priv,
|
||||||
@ -2676,7 +2691,7 @@ func TestCreateRevocationList(t *testing.T) {
|
|||||||
t.Fatalf("Unexpected second extension: got %v, want %v",
|
t.Fatalf("Unexpected second extension: got %v, want %v",
|
||||||
parsedCRL.Extensions[1], crlExt)
|
parsedCRL.Extensions[1], crlExt)
|
||||||
}
|
}
|
||||||
// With Go 1.19's updated RevocationList, we can now directly compare
|
// With Go 1.19's updated RevocationList, we can now directly compare
|
||||||
// the RawSubject of the certificate to RawIssuer on the parsed CRL.
|
// the RawSubject of the certificate to RawIssuer on the parsed CRL.
|
||||||
// However, this doesn't work with our hacked issuers above (that
|
// However, this doesn't work with our hacked issuers above (that
|
||||||
// aren't parsed from a proper DER bundle but are instead manually
|
// aren't parsed from a proper DER bundle but are instead manually
|
||||||
|
Loading…
x
Reference in New Issue
Block a user