jwk: move to a specific package, also decode private keys
This commit is contained in:
76
crypto/jwk/private.go
Normal file
76
crypto/jwk/private.go
Normal file
@@ -0,0 +1,76 @@
|
||||
package jwk
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"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/p521"
|
||||
"github.com/INFURA/go-did/crypto/secp256k1"
|
||||
"github.com/INFURA/go-did/crypto/x25519"
|
||||
)
|
||||
|
||||
type PrivateJwk struct {
|
||||
Privkey crypto.PrivateKey
|
||||
}
|
||||
|
||||
func (pj PrivateJwk) UnmarshalJSON(bytes []byte) error {
|
||||
aux := make(map[string]string)
|
||||
err := json.Unmarshal(bytes, &aux)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
switch aux["kty"] {
|
||||
case "EC": // Elliptic curve
|
||||
// we only use D, ignore X/Y which will be recomputed from D
|
||||
d, err := base64.RawURLEncoding.DecodeString(aux["d"])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid d parameter with kty=EC: %w", err)
|
||||
}
|
||||
switch aux["crv"] {
|
||||
case "P-256":
|
||||
pj.Privkey, err = p256.PrivateKeyFromBytes(d)
|
||||
return err
|
||||
case "P-384":
|
||||
pj.Privkey, err = p384.PrivateKeyFromBytes(d)
|
||||
return err
|
||||
case "P-521":
|
||||
pj.Privkey, err = p521.PrivateKeyFromBytes(d)
|
||||
return err
|
||||
case "secp256k1":
|
||||
pj.Privkey, err = secp256k1.PrivateKeyFromBytes(d)
|
||||
return err
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unsupported Curve %s", aux["crv"])
|
||||
}
|
||||
|
||||
case "RSA":
|
||||
return fmt.Errorf("not implemented")
|
||||
|
||||
case "OKP": // Octet key pair
|
||||
x, err := base64.RawURLEncoding.DecodeString(aux["x"])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid x parameter with kty=OKP: %w", err)
|
||||
}
|
||||
switch aux["crv"] {
|
||||
case "Ed25519":
|
||||
pj.Privkey, err = ed25519.PrivateKeyFromBytes(x)
|
||||
return err
|
||||
case "X25519":
|
||||
pj.Privkey, err = x25519.PrivateKeyFromBytes(x)
|
||||
return err
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unsupported Curve %s", aux["crv"])
|
||||
}
|
||||
|
||||
default:
|
||||
return fmt.Errorf("unsupported key type %s", aux["kty"])
|
||||
}
|
||||
}
|
||||
@@ -1,16 +1,16 @@
|
||||
package jsonwebkey
|
||||
package jwk
|
||||
|
||||
import (
|
||||
"encoding/base64"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
||||
"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/p521"
|
||||
"github.com/INFURA/go-did/crypto/secp256k1"
|
||||
"github.com/INFURA/go-did/crypto/x25519"
|
||||
)
|
||||
|
||||
@@ -18,12 +18,12 @@ import (
|
||||
// - https://www.rfc-editor.org/rfc/rfc7517#section-4 (JWK)
|
||||
// - https://www.iana.org/assignments/jose/jose.xhtml#web-key-types (key parameters)
|
||||
|
||||
type jwk struct {
|
||||
pubkey crypto.PublicKey
|
||||
type PublicJwk struct {
|
||||
Pubkey crypto.PublicKey
|
||||
}
|
||||
|
||||
func (j jwk) MarshalJSON() ([]byte, error) {
|
||||
switch pubkey := j.pubkey.(type) {
|
||||
func (pj PublicJwk) MarshalJSON() ([]byte, error) {
|
||||
switch pubkey := pj.Pubkey.(type) {
|
||||
case ed25519.PublicKey:
|
||||
return json.Marshal(struct {
|
||||
Kty string `json:"kty"`
|
||||
@@ -70,6 +70,18 @@ func (j jwk) MarshalJSON() ([]byte, error) {
|
||||
X: base64.RawURLEncoding.EncodeToString(pubkey.XBytes()),
|
||||
Y: base64.RawURLEncoding.EncodeToString(pubkey.YBytes()),
|
||||
})
|
||||
case *secp256k1.PublicKey:
|
||||
return json.Marshal(struct {
|
||||
Kty string `json:"kty"`
|
||||
Crv string `json:"crv"`
|
||||
X string `json:"x"`
|
||||
Y string `json:"y"`
|
||||
}{
|
||||
Kty: "EC",
|
||||
Crv: "secp256k1",
|
||||
X: base64.RawURLEncoding.EncodeToString(pubkey.XBytes()),
|
||||
Y: base64.RawURLEncoding.EncodeToString(pubkey.YBytes()),
|
||||
})
|
||||
case *x25519.PublicKey:
|
||||
return json.Marshal(struct {
|
||||
Kty string `json:"kty"`
|
||||
@@ -86,40 +98,35 @@ func (j jwk) MarshalJSON() ([]byte, error) {
|
||||
}
|
||||
}
|
||||
|
||||
func (j *jwk) UnmarshalJSON(bytes []byte) error {
|
||||
func (pj *PublicJwk) UnmarshalJSON(bytes []byte) error {
|
||||
aux := make(map[string]string)
|
||||
err := json.Unmarshal(bytes, &aux)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
bigIntBase64Url := func(s string) (*big.Int, error) {
|
||||
raw, err := base64.RawURLEncoding.DecodeString(s)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return new(big.Int).SetBytes(raw), nil
|
||||
}
|
||||
|
||||
switch aux["kty"] {
|
||||
case "EC": // Elliptic curve
|
||||
x, err := bigIntBase64Url(aux["x"])
|
||||
x, err := base64.RawURLEncoding.DecodeString(aux["x"])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid x parameter with kty=EC: %w", err)
|
||||
}
|
||||
y, err := bigIntBase64Url(aux["y"])
|
||||
y, err := base64.RawURLEncoding.DecodeString(aux["y"])
|
||||
if err != nil {
|
||||
return fmt.Errorf("invalid y parameter with kty=EC: %w", err)
|
||||
}
|
||||
switch aux["crv"] {
|
||||
case "P-256":
|
||||
j.pubkey, err = p256.PublicKeyFromXY(x, y)
|
||||
pj.Pubkey, err = p256.PublicKeyFromXY(x, y)
|
||||
return err
|
||||
case "P-384":
|
||||
j.pubkey, err = p384.PublicKeyFromXY(x, y)
|
||||
pj.Pubkey, err = p384.PublicKeyFromXY(x, y)
|
||||
return err
|
||||
case "P-521":
|
||||
j.pubkey, err = p521.PublicKeyFromXY(x, y)
|
||||
pj.Pubkey, err = p521.PublicKeyFromXY(x, y)
|
||||
return err
|
||||
case "secp256k1":
|
||||
pj.Pubkey, err = secp256k1.PublicKeyFromXY(x, y)
|
||||
return err
|
||||
|
||||
default:
|
||||
@@ -136,10 +143,10 @@ func (j *jwk) UnmarshalJSON(bytes []byte) error {
|
||||
}
|
||||
switch aux["crv"] {
|
||||
case "Ed25519":
|
||||
j.pubkey, err = ed25519.PublicKeyFromBytes(x)
|
||||
pj.Pubkey, err = ed25519.PublicKeyFromBytes(x)
|
||||
return err
|
||||
case "X25519":
|
||||
j.pubkey, err = x25519.PublicKeyFromBytes(x)
|
||||
pj.Pubkey, err = x25519.PublicKeyFromBytes(x)
|
||||
return err
|
||||
|
||||
default:
|
||||
@@ -6,6 +6,7 @@ import (
|
||||
|
||||
"github.com/INFURA/go-did"
|
||||
"github.com/INFURA/go-did/crypto"
|
||||
"github.com/INFURA/go-did/crypto/jwk"
|
||||
)
|
||||
|
||||
// Specification: https://www.w3.org/TR/vc-jws-2020/
|
||||
@@ -34,24 +35,24 @@ func NewJsonWebKey2020(id string, pubkey crypto.PublicKey, controller did.DID) *
|
||||
|
||||
func (j JsonWebKey2020) MarshalJSON() ([]byte, error) {
|
||||
return json.Marshal(struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Controller string `json:"controller"`
|
||||
PublicKeyJWK jwk `json:"publicKeyJwk"`
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Controller string `json:"controller"`
|
||||
PublicKeyJWK jwk.PublicJwk `json:"publicKeyJwk"`
|
||||
}{
|
||||
ID: j.ID(),
|
||||
Type: j.Type(),
|
||||
Controller: j.Controller(),
|
||||
PublicKeyJWK: jwk{pubkey: j.pubkey},
|
||||
PublicKeyJWK: jwk.PublicJwk{Pubkey: j.pubkey},
|
||||
})
|
||||
}
|
||||
|
||||
func (j *JsonWebKey2020) UnmarshalJSON(bytes []byte) error {
|
||||
aux := struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Controller string `json:"controller"`
|
||||
PublicKeyJWK jwk `json:"publicKeyJwk"`
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Controller string `json:"controller"`
|
||||
PublicKeyJWK jwk.PublicJwk `json:"publicKeyJwk"`
|
||||
}{}
|
||||
err := json.Unmarshal(bytes, &aux)
|
||||
if err != nil {
|
||||
@@ -69,7 +70,7 @@ func (j *JsonWebKey2020) UnmarshalJSON(bytes []byte) error {
|
||||
return errors.New("invalid controller")
|
||||
}
|
||||
|
||||
j.pubkey = aux.PublicKeyJWK.pubkey
|
||||
j.pubkey = aux.PublicKeyJWK.Pubkey
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user