add support for P-384
This commit is contained in:
32
crypto/_allkeys/allkeys.go
Normal file
32
crypto/_allkeys/allkeys.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package allkeys
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
"github.com/INFURA/go-did/crypto/ed25519"
|
||||
helpers "github.com/INFURA/go-did/crypto/internal"
|
||||
"github.com/INFURA/go-did/crypto/p256"
|
||||
"github.com/INFURA/go-did/crypto/p384"
|
||||
"github.com/INFURA/go-did/crypto/x25519"
|
||||
)
|
||||
|
||||
var decoders = map[uint64]func(b []byte) (crypto.PublicKey, error){
|
||||
ed25519.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return ed25519.PublicKeyFromBytes(b) },
|
||||
p256.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return p256.PublicKeyFromBytes(b) },
|
||||
p384.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return p384.PublicKeyFromBytes(b) },
|
||||
x25519.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return x25519.PublicKeyFromBytes(b) },
|
||||
}
|
||||
|
||||
// PublicKeyFromPublicKeyMultibase decodes the public key from its PublicKeyMultibase form
|
||||
func PublicKeyFromPublicKeyMultibase(multibase string) (crypto.PublicKey, error) {
|
||||
code, pubBytes, err := helpers.PublicKeyMultibaseDecode(multibase)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("invalid publicKeyMultibase: %w", err)
|
||||
}
|
||||
decoder, ok := decoders[code]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("unsupported publicKeyMultibase code: %d", code)
|
||||
}
|
||||
return decoder(pubBytes)
|
||||
}
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"golang.org/x/crypto/cryptobyte"
|
||||
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
"github.com/INFURA/go-did/crypto/_helpers"
|
||||
"github.com/INFURA/go-did/crypto/internal"
|
||||
)
|
||||
|
||||
var _ crypto.SigningPublicKey = &PublicKey{}
|
||||
|
||||
@@ -106,9 +106,9 @@ func (p *PrivateKey) SignToBytes(message []byte) ([]byte, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sig := make([]byte, 64)
|
||||
r.FillBytes(sig[:32])
|
||||
s.FillBytes(sig[32:])
|
||||
sig := make([]byte, SignatureBytesSize)
|
||||
r.FillBytes(sig[:SignatureBytesSize/2])
|
||||
s.FillBytes(sig[SignatureBytesSize/2:])
|
||||
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"math/big"
|
||||
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
helpers "github.com/INFURA/go-did/crypto/_helpers"
|
||||
helpers "github.com/INFURA/go-did/crypto/internal"
|
||||
)
|
||||
|
||||
var _ crypto.SigningPublicKey = (*PublicKey)(nil)
|
||||
@@ -118,8 +118,8 @@ func (p *PublicKey) VerifyBytes(message, signature []byte) bool {
|
||||
// Hash the message with SHA-256
|
||||
hash := sha256.Sum256(message)
|
||||
|
||||
r := new(big.Int).SetBytes(signature[:32])
|
||||
s := new(big.Int).SetBytes(signature[32:])
|
||||
r := new(big.Int).SetBytes(signature[:SignatureBytesSize/2])
|
||||
s := new(big.Int).SetBytes(signature[SignatureBytesSize/2:])
|
||||
|
||||
return ecdsa.Verify((*ecdsa.PublicKey)(p), hash[:], r, s)
|
||||
}
|
||||
|
||||
32
crypto/p384/key.go
Normal file
32
crypto/p384/key.go
Normal file
@@ -0,0 +1,32 @@
|
||||
package p384
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
)
|
||||
|
||||
const (
|
||||
// PublicKeyBytesSize is the size, in bytes, of public keys in raw bytes.
|
||||
PublicKeyBytesSize = 49
|
||||
// PrivateKeyBytesSize is the size, in bytes, of private keys in raw bytes.
|
||||
PrivateKeyBytesSize = 48
|
||||
// SignatureBytesSize is the size, in bytes, of signatures in raw bytes.
|
||||
SignatureBytesSize = 96
|
||||
|
||||
MultibaseCode = uint64(0x1201)
|
||||
)
|
||||
|
||||
func GenerateKeyPair() (*PublicKey, *PrivateKey, error) {
|
||||
priv, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
pub := priv.Public().(*ecdsa.PublicKey)
|
||||
return (*PublicKey)(pub), (*PrivateKey)(priv), nil
|
||||
}
|
||||
|
||||
const (
|
||||
pemPubBlockType = "PUBLIC KEY"
|
||||
pemPrivBlockType = "PRIVATE KEY"
|
||||
)
|
||||
31
crypto/p384/key_test.go
Normal file
31
crypto/p384/key_test.go
Normal file
@@ -0,0 +1,31 @@
|
||||
package p384
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/INFURA/go-did/crypto/_testsuite"
|
||||
)
|
||||
|
||||
var harness = testsuite.TestHarness[*PublicKey, *PrivateKey]{
|
||||
Name: "p384",
|
||||
GenerateKeyPair: GenerateKeyPair,
|
||||
PublicKeyFromBytes: PublicKeyFromBytes,
|
||||
PublicKeyFromPublicKeyMultibase: PublicKeyFromPublicKeyMultibase,
|
||||
PublicKeyFromX509DER: PublicKeyFromX509DER,
|
||||
PublicKeyFromX509PEM: PublicKeyFromX509PEM,
|
||||
PrivateKeyFromBytes: PrivateKeyFromBytes,
|
||||
PrivateKeyFromPKCS8DER: PrivateKeyFromPKCS8DER,
|
||||
PrivateKeyFromPKCS8PEM: PrivateKeyFromPKCS8PEM,
|
||||
MultibaseCode: MultibaseCode,
|
||||
PublicKeyBytesSize: PublicKeyBytesSize,
|
||||
PrivateKeyBytesSize: PrivateKeyBytesSize,
|
||||
SignatureBytesSize: SignatureBytesSize,
|
||||
}
|
||||
|
||||
func TestSuite(t *testing.T) {
|
||||
testsuite.TestSuite(t, harness)
|
||||
}
|
||||
|
||||
func BenchmarkSuite(b *testing.B) {
|
||||
testsuite.BenchSuite(b, harness)
|
||||
}
|
||||
145
crypto/p384/private.go
Normal file
145
crypto/p384/private.go
Normal file
@@ -0,0 +1,145 @@
|
||||
package p384
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/rand"
|
||||
"crypto/sha512"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
)
|
||||
|
||||
var _ crypto.SigningPrivateKey = (*PrivateKey)(nil)
|
||||
var _ crypto.KeyExchangePrivateKey = (*PrivateKey)(nil)
|
||||
|
||||
type PrivateKey ecdsa.PrivateKey
|
||||
|
||||
// PrivateKeyFromBytes converts a serialized public key to a PrivateKey.
|
||||
// This compact serialization format is the raw key material, without metadata or structure.
|
||||
// It errors if the slice is not the right size.
|
||||
func PrivateKeyFromBytes(b []byte) (*PrivateKey, error) {
|
||||
if len(b) != PrivateKeyBytesSize {
|
||||
return nil, fmt.Errorf("invalid P-384 private key size")
|
||||
}
|
||||
|
||||
res := &ecdsa.PrivateKey{
|
||||
D: new(big.Int).SetBytes(b),
|
||||
PublicKey: ecdsa.PublicKey{Curve: elliptic.P384()},
|
||||
}
|
||||
|
||||
// recompute the public key
|
||||
res.PublicKey.X, res.PublicKey.Y = res.PublicKey.Curve.ScalarBaseMult(b)
|
||||
|
||||
return (*PrivateKey)(res), nil
|
||||
}
|
||||
|
||||
// PrivateKeyFromPKCS8DER decodes a PKCS#8 DER (binary) encoded private key.
|
||||
func PrivateKeyFromPKCS8DER(bytes []byte) (*PrivateKey, error) {
|
||||
priv, err := x509.ParsePKCS8PrivateKey(bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ecdsaPriv := priv.(*ecdsa.PrivateKey)
|
||||
return (*PrivateKey)(ecdsaPriv), nil
|
||||
}
|
||||
|
||||
// PrivateKeyFromPKCS8PEM decodes an PKCS#8 PEM (string) encoded private key.
|
||||
func PrivateKeyFromPKCS8PEM(str string) (*PrivateKey, error) {
|
||||
block, _ := pem.Decode([]byte(str))
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("failed to decode PEM block")
|
||||
}
|
||||
if block.Type != pemPrivBlockType {
|
||||
return nil, fmt.Errorf("incorrect PEM block type")
|
||||
}
|
||||
return PrivateKeyFromPKCS8DER(block.Bytes)
|
||||
}
|
||||
|
||||
func (p *PrivateKey) Equal(other crypto.PrivateKey) bool {
|
||||
if other, ok := other.(*PrivateKey); ok {
|
||||
return (*ecdsa.PrivateKey)(p).Equal((*ecdsa.PrivateKey)(other))
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *PrivateKey) Public() crypto.PublicKey {
|
||||
ecdhPub := (*ecdsa.PrivateKey)(p).Public().(*ecdsa.PublicKey)
|
||||
return (*PublicKey)(ecdhPub)
|
||||
}
|
||||
|
||||
func (p *PrivateKey) ToBytes() []byte {
|
||||
// fixed size buffer that can get allocated on the caller's stack after inlining.
|
||||
var buf [PrivateKeyBytesSize]byte
|
||||
((*ecdsa.PrivateKey)(p)).D.FillBytes(buf[:])
|
||||
return buf[:]
|
||||
}
|
||||
|
||||
func (p *PrivateKey) ToPKCS8DER() []byte {
|
||||
res, _ := x509.MarshalPKCS8PrivateKey((*ecdsa.PrivateKey)(p))
|
||||
return res
|
||||
}
|
||||
|
||||
func (p *PrivateKey) ToPKCS8PEM() string {
|
||||
der := p.ToPKCS8DER()
|
||||
return string(pem.EncodeToMemory(&pem.Block{
|
||||
Type: pemPrivBlockType,
|
||||
Bytes: der,
|
||||
}))
|
||||
}
|
||||
|
||||
/*
|
||||
Note: signatures for the crypto.SigningPrivateKey interface assumes SHA384,
|
||||
which should be correct almost always. If there is a need to use a different
|
||||
hash function, we can add separate functions that have that flexibility.
|
||||
*/
|
||||
|
||||
func (p *PrivateKey) SignToBytes(message []byte) ([]byte, error) {
|
||||
// Hash the message with SHA-384
|
||||
hash := sha512.Sum384(message)
|
||||
|
||||
r, s, err := ecdsa.Sign(rand.Reader, (*ecdsa.PrivateKey)(p), hash[:])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
sig := make([]byte, SignatureBytesSize)
|
||||
r.FillBytes(sig[:SignatureBytesSize/2])
|
||||
s.FillBytes(sig[SignatureBytesSize/2:])
|
||||
|
||||
return sig, nil
|
||||
}
|
||||
|
||||
func (p *PrivateKey) SignToASN1(message []byte) ([]byte, error) {
|
||||
// Hash the message with SHA-384
|
||||
hash := sha512.Sum384(message)
|
||||
|
||||
return ecdsa.SignASN1(rand.Reader, (*ecdsa.PrivateKey)(p), hash[:])
|
||||
}
|
||||
|
||||
func (p *PrivateKey) PublicKeyIsCompatible(remote crypto.PublicKey) bool {
|
||||
if _, ok := remote.(*PublicKey); ok {
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *PrivateKey) KeyExchange(remote crypto.PublicKey) ([]byte, error) {
|
||||
if remote, ok := remote.(*PublicKey); ok {
|
||||
// First, we need to convert the ECDSA (signing only) to the equivalent ECDH keys
|
||||
ecdhPriv, err := (*ecdsa.PrivateKey)(p).ECDH()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ecdhPub, err := (*ecdsa.PublicKey)(remote).ECDH()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return ecdhPriv.ECDH(ecdhPub)
|
||||
}
|
||||
return nil, fmt.Errorf("incompatible public key")
|
||||
}
|
||||
132
crypto/p384/public.go
Normal file
132
crypto/p384/public.go
Normal file
@@ -0,0 +1,132 @@
|
||||
package p384
|
||||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"crypto/elliptic"
|
||||
"crypto/sha512"
|
||||
"crypto/x509"
|
||||
"encoding/pem"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
helpers "github.com/INFURA/go-did/crypto/internal"
|
||||
)
|
||||
|
||||
var _ crypto.SigningPublicKey = (*PublicKey)(nil)
|
||||
|
||||
type PublicKey ecdsa.PublicKey
|
||||
|
||||
// PublicKeyFromBytes converts a serialized public key to a PublicKey.
|
||||
// This compact serialization format is the raw key material, without metadata or structure.
|
||||
// It errors if the slice is not the right size.
|
||||
func PublicKeyFromBytes(b []byte) (*PublicKey, error) {
|
||||
if len(b) != PublicKeyBytesSize {
|
||||
return nil, fmt.Errorf("invalid P-384 public key size")
|
||||
}
|
||||
x, y := elliptic.UnmarshalCompressed(elliptic.P384(), b)
|
||||
if x == nil {
|
||||
return nil, fmt.Errorf("invalid P-384 public key")
|
||||
}
|
||||
return (*PublicKey)(&ecdsa.PublicKey{Curve: elliptic.P384(), X: x, Y: y}), nil
|
||||
}
|
||||
|
||||
// PublicKeyFromXY converts x and y coordinates into a PublicKey.
|
||||
func PublicKeyFromXY(x, y *big.Int) (*PublicKey, error) {
|
||||
if !elliptic.P384().IsOnCurve(x, y) {
|
||||
return nil, fmt.Errorf("invalid P-384 public key")
|
||||
}
|
||||
return (*PublicKey)(&ecdsa.PublicKey{Curve: elliptic.P384(), X: x, Y: y}), nil
|
||||
}
|
||||
|
||||
// PublicKeyFromPublicKeyMultibase decodes the public key from its Multibase form
|
||||
func PublicKeyFromPublicKeyMultibase(multibase string) (*PublicKey, error) {
|
||||
code, bytes, err := helpers.PublicKeyMultibaseDecode(multibase)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if code != MultibaseCode {
|
||||
return nil, fmt.Errorf("invalid code")
|
||||
}
|
||||
return PublicKeyFromBytes(bytes)
|
||||
}
|
||||
|
||||
// PublicKeyFromX509DER decodes an X.509 DER (binary) encoded public key.
|
||||
func PublicKeyFromX509DER(bytes []byte) (*PublicKey, error) {
|
||||
pub, err := x509.ParsePKIXPublicKey(bytes)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
ecdsaPub := pub.(*ecdsa.PublicKey)
|
||||
return (*PublicKey)(ecdsaPub), nil
|
||||
}
|
||||
|
||||
// PublicKeyFromX509PEM decodes an X.509 PEM (string) encoded public key.
|
||||
func PublicKeyFromX509PEM(str string) (*PublicKey, error) {
|
||||
block, _ := pem.Decode([]byte(str))
|
||||
if block == nil {
|
||||
return nil, fmt.Errorf("failed to decode PEM block")
|
||||
}
|
||||
if block.Type != pemPubBlockType {
|
||||
return nil, fmt.Errorf("incorrect PEM block type")
|
||||
}
|
||||
return PublicKeyFromX509DER(block.Bytes)
|
||||
}
|
||||
|
||||
func (p *PublicKey) Equal(other crypto.PublicKey) bool {
|
||||
if other, ok := other.(*PublicKey); ok {
|
||||
return (*ecdsa.PublicKey)(p).Equal((*ecdsa.PublicKey)(other))
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (p *PublicKey) ToBytes() []byte {
|
||||
ecdsaPub := (*ecdsa.PublicKey)(p)
|
||||
return elliptic.MarshalCompressed(elliptic.P384(), ecdsaPub.X, ecdsaPub.Y)
|
||||
}
|
||||
|
||||
func (p *PublicKey) ToPublicKeyMultibase() string {
|
||||
ecdsaPub := (*ecdsa.PublicKey)(p)
|
||||
bytes := elliptic.MarshalCompressed(elliptic.P384(), ecdsaPub.X, ecdsaPub.Y)
|
||||
return helpers.PublicKeyMultibaseEncode(MultibaseCode, bytes)
|
||||
}
|
||||
|
||||
func (p *PublicKey) ToX509DER() []byte {
|
||||
res, _ := x509.MarshalPKIXPublicKey((*ecdsa.PublicKey)(p))
|
||||
return res
|
||||
}
|
||||
|
||||
func (p *PublicKey) ToX509PEM() string {
|
||||
der := p.ToX509DER()
|
||||
return string(pem.EncodeToMemory(&pem.Block{
|
||||
Type: pemPubBlockType,
|
||||
Bytes: der,
|
||||
}))
|
||||
}
|
||||
|
||||
/*
|
||||
Note: signatures for the crypto.SigningPrivateKey interface assumes SHA384,
|
||||
which should be correct almost always. If there is a need to use a different
|
||||
hash function, we can add separate functions that have that flexibility.
|
||||
*/
|
||||
|
||||
func (p *PublicKey) VerifyBytes(message, signature []byte) bool {
|
||||
if len(signature) != SignatureBytesSize {
|
||||
return false
|
||||
}
|
||||
|
||||
// Hash the message with SHA-384
|
||||
hash := sha512.Sum384(message)
|
||||
|
||||
r := new(big.Int).SetBytes(signature[:SignatureBytesSize/2])
|
||||
s := new(big.Int).SetBytes(signature[SignatureBytesSize/2:])
|
||||
|
||||
return ecdsa.Verify((*ecdsa.PublicKey)(p), hash[:], r, s)
|
||||
}
|
||||
|
||||
func (p *PublicKey) VerifyASN1(message, signature []byte) bool {
|
||||
// Hash the message with SHA-384
|
||||
hash := sha512.Sum384(message)
|
||||
|
||||
return ecdsa.VerifyASN1((*ecdsa.PublicKey)(p), hash[:], signature)
|
||||
}
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"math/big"
|
||||
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
helpers "github.com/INFURA/go-did/crypto/_helpers"
|
||||
"github.com/INFURA/go-did/crypto/ed25519"
|
||||
helpers "github.com/INFURA/go-did/crypto/internal"
|
||||
)
|
||||
|
||||
var _ crypto.PublicKey = (*PublicKey)(nil)
|
||||
|
||||
@@ -6,9 +6,10 @@ import (
|
||||
|
||||
"github.com/INFURA/go-did"
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
"github.com/INFURA/go-did/crypto/_helpers"
|
||||
allkeys "github.com/INFURA/go-did/crypto/_allkeys"
|
||||
"github.com/INFURA/go-did/crypto/ed25519"
|
||||
"github.com/INFURA/go-did/crypto/p256"
|
||||
"github.com/INFURA/go-did/crypto/p384"
|
||||
"github.com/INFURA/go-did/crypto/x25519"
|
||||
"github.com/INFURA/go-did/verifications/ed25519"
|
||||
"github.com/INFURA/go-did/verifications/multikey"
|
||||
@@ -38,16 +39,7 @@ func Decode(identifier string) (did.DID, error) {
|
||||
|
||||
msi := identifier[len(keyPrefix):]
|
||||
|
||||
code, bytes, err := helpers.PublicKeyMultibaseDecode(msi)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %w", did.ErrInvalidDid, err)
|
||||
}
|
||||
|
||||
decoder, ok := decoders[code]
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("%w: unsupported did:key multicodec: 0x%x", did.ErrInvalidDid, code)
|
||||
}
|
||||
pub, err := decoder(bytes)
|
||||
pub, err := allkeys.PublicKeyFromPublicKeyMultibase(msi)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%w: %w", did.ErrInvalidDid, err)
|
||||
}
|
||||
@@ -58,12 +50,6 @@ func Decode(identifier string) (did.DID, error) {
|
||||
return d, nil
|
||||
}
|
||||
|
||||
var decoders = map[uint64]func(b []byte) (crypto.PublicKey, error){
|
||||
ed25519.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return ed25519.PublicKeyFromBytes(b) },
|
||||
p256.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return p256.PublicKeyFromBytes(b) },
|
||||
x25519.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return x25519.PublicKeyFromBytes(b) },
|
||||
}
|
||||
|
||||
func FromPublicKey(pub crypto.PublicKey) (did.DID, error) {
|
||||
switch pub := pub.(type) {
|
||||
case ed25519.PublicKey:
|
||||
@@ -76,7 +62,7 @@ func FromPublicKey(pub crypto.PublicKey) (did.DID, error) {
|
||||
xmsi := xpub.ToPublicKeyMultibase()
|
||||
d.keyAgreement = x25519vm.NewKeyAgreementKey2020(fmt.Sprintf("did:key:%s#%s", d.msi, xmsi), xpub, d)
|
||||
return d, nil
|
||||
case *p256.PublicKey:
|
||||
case *p256.PublicKey, *p384.PublicKey:
|
||||
d := DidKey{msi: pub.ToPublicKeyMultibase()}
|
||||
mk := multikey.NewMultiKey(fmt.Sprintf("did:key:%s#%s", d.msi, d.msi), pub, d)
|
||||
d.signature = mk
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
"github.com/INFURA/go-did/crypto/ed25519"
|
||||
"github.com/INFURA/go-did/crypto/p256"
|
||||
"github.com/INFURA/go-did/crypto/p384"
|
||||
"github.com/INFURA/go-did/crypto/x25519"
|
||||
)
|
||||
|
||||
@@ -22,6 +23,16 @@ type jwk struct {
|
||||
|
||||
func (j jwk) MarshalJSON() ([]byte, error) {
|
||||
switch pubkey := j.pubkey.(type) {
|
||||
case ed25519.PublicKey:
|
||||
return json.Marshal(struct {
|
||||
Kty string `json:"kty"`
|
||||
Crv string `json:"crv"`
|
||||
X string `json:"x"`
|
||||
}{
|
||||
Kty: "OKP",
|
||||
Crv: "Ed25519",
|
||||
X: base64.RawURLEncoding.EncodeToString(pubkey.ToBytes()),
|
||||
})
|
||||
case *p256.PublicKey:
|
||||
return json.Marshal(struct {
|
||||
Kty string `json:"kty"`
|
||||
@@ -34,15 +45,17 @@ func (j jwk) MarshalJSON() ([]byte, error) {
|
||||
X: base64.RawURLEncoding.EncodeToString(pubkey.X.Bytes()),
|
||||
Y: base64.RawURLEncoding.EncodeToString(pubkey.Y.Bytes()),
|
||||
})
|
||||
case ed25519.PublicKey:
|
||||
case *p384.PublicKey:
|
||||
return json.Marshal(struct {
|
||||
Kty string `json:"kty"`
|
||||
Crv string `json:"crv"`
|
||||
X string `json:"x"`
|
||||
Y string `json:"y"`
|
||||
}{
|
||||
Kty: "OKP",
|
||||
Crv: "Ed25519",
|
||||
X: base64.RawURLEncoding.EncodeToString(pubkey.ToBytes()),
|
||||
Kty: "EC",
|
||||
Crv: "P-384",
|
||||
X: base64.RawURLEncoding.EncodeToString(pubkey.X.Bytes()),
|
||||
Y: base64.RawURLEncoding.EncodeToString(pubkey.Y.Bytes()),
|
||||
})
|
||||
case *x25519.PublicKey:
|
||||
return json.Marshal(struct {
|
||||
@@ -89,6 +102,9 @@ func (j *jwk) UnmarshalJSON(bytes []byte) error {
|
||||
case "P-256":
|
||||
j.pubkey, err = p256.PublicKeyFromXY(x, y)
|
||||
return err
|
||||
case "P-384":
|
||||
j.pubkey, err = p384.PublicKeyFromXY(x, y)
|
||||
return err
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unsupported Curve %s", aux["crv"])
|
||||
|
||||
@@ -7,10 +7,7 @@ import (
|
||||
|
||||
"github.com/INFURA/go-did"
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
helpers "github.com/INFURA/go-did/crypto/_helpers"
|
||||
"github.com/INFURA/go-did/crypto/ed25519"
|
||||
"github.com/INFURA/go-did/crypto/p256"
|
||||
"github.com/INFURA/go-did/crypto/x25519"
|
||||
allkeys "github.com/INFURA/go-did/crypto/_allkeys"
|
||||
)
|
||||
|
||||
// Specification: https://www.w3.org/TR/cid-1.0/#Multikey
|
||||
@@ -74,15 +71,7 @@ func (m *MultiKey) UnmarshalJSON(bytes []byte) error {
|
||||
return errors.New("invalid controller")
|
||||
}
|
||||
|
||||
code, pubBytes, err := helpers.PublicKeyMultibaseDecode(aux.PublicKeyMultibase)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid publicKeyMultibase: %w", err)
|
||||
}
|
||||
decoder, ok := decoders[code]
|
||||
if !ok {
|
||||
return fmt.Errorf("unsupported publicKeyMultibase code: %d", code)
|
||||
}
|
||||
m.pubkey, err = decoder(pubBytes)
|
||||
m.pubkey, err = allkeys.PublicKeyFromPublicKeyMultibase(aux.PublicKeyMultibase)
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid publicKeyMultibase: %w", err)
|
||||
}
|
||||
@@ -90,12 +79,6 @@ func (m *MultiKey) UnmarshalJSON(bytes []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
var decoders = map[uint64]func(b []byte) (crypto.PublicKey, error){
|
||||
ed25519.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return ed25519.PublicKeyFromBytes(b) },
|
||||
p256.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return p256.PublicKeyFromBytes(b) },
|
||||
x25519.MultibaseCode: func(b []byte) (crypto.PublicKey, error) { return x25519.PublicKeyFromBytes(b) },
|
||||
}
|
||||
|
||||
func (m MultiKey) ID() string {
|
||||
return m.id
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user