Skip to content

Commit

Permalink
refactor: refactor: move jwk from kms-go, and refactor implementation.
Browse files Browse the repository at this point in the history
Signed-off-by: Volodymyr Kubiv <[email protected]>
  • Loading branch information
vkubiv committed Feb 7, 2024
1 parent e95287d commit 8f5c717
Show file tree
Hide file tree
Showing 26 changed files with 1,325 additions and 1,122 deletions.
4 changes: 2 additions & 2 deletions .golangci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ linters-settings:
gofmt:
simplify: true
gocyclo:
min-complexity: 10
min-complexity: 12
maligned:
suggest-new: true
dupl:
Expand Down Expand Up @@ -61,7 +61,7 @@ linters-settings:
- unnamedResult
- whyNoLint # TODO enable.
funlen:
lines: 60
lines: 80
statements: 40
wsl:
strict-append: true
Expand Down
153 changes: 153 additions & 0 deletions crypto-ext/jwksupport/create.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
/*
Copyright Gen Digital Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package jwksupport

import (
"crypto/ed25519"
"crypto/elliptic"
"errors"
"fmt"
"math/big"

"github.com/trustbloc/bbs-signature-go/bbs12381g2pub"
"github.com/trustbloc/kms-go/util/cryptoutil"

"github.com/trustbloc/did-go/doc/jose/jwk"
)

const (
ecKty = "EC"
okpKty = "OKP"
x25519Crv = "X25519"
ed25519Crv = "Ed25519"
bls12381G2Crv = "BLS12381_G2"
bls12381G2Size = 96
)

// FromEdPublicKey creates jwk from ed25519 key.
func FromEdPublicKey(pub ed25519.PublicKey) *jwk.JWK {
return &jwk.JWK{
Kty: "OKP",
Crv: ed25519Crv,
X: jwk.NewBuffer(pub),
}
}

// FromEdPrivateKey creates jwk from ed25519 key.
func FromEdPrivateKey(ed ed25519.PrivateKey) *jwk.JWK {
raw := FromEdPublicKey(ed25519.PublicKey(ed[32:]))
raw.D = jwk.NewBuffer(ed[0:32])

return raw
}

// JWKFromX25519Key creates jwk from x25519 key.
func JWKFromX25519Key(pubKey []byte) (*jwk.JWK, error) {
if len(pubKey) != cryptoutil.Curve25519KeySize {
return nil, errors.New("JWKFromX25519Key: invalid key")
}

return &jwk.JWK{
Crv: x25519Crv,
Kty: okpKty,
X: jwk.NewFixedSizeBuffer(pubKey, cryptoutil.Curve25519KeySize),
}, nil
}

// FromEcdsaPubKeyBytes creates jwk from ecdsa public key.
func FromEcdsaPubKeyBytes(curve elliptic.Curve, pubKeyBytes []byte) (*jwk.JWK, error) {
x, y := elliptic.UnmarshalCompressed(curve, pubKeyBytes)
if x == nil {
return nil, fmt.Errorf("error unmarshalling key bytes")
}

return FromEcdsaContent(EcdsaContent{
Curve: curve,
X: x,
Y: y,
})
}

// FromBLS12381G2 creates jwk from bbs12381g2 public key.
func FromBLS12381G2(key *bbs12381g2pub.PublicKey) (*jwk.JWK, error) {
var raw *jwk.JWK

mKey, err := key.Marshal()
if err != nil {
return nil, err
}

raw = &jwk.JWK{
Kty: ecKty,
Crv: bls12381G2Crv,
X: jwk.NewFixedSizeBuffer(mKey, bls12381G2Size),
}

return raw, nil
}

// EcdsaContent represent content of ecdsa key.
type EcdsaContent struct {
Curve elliptic.Curve

X *big.Int
Y *big.Int
}

// FromEcdsaContent creates jwk from ecdsa key.
func FromEcdsaContent(content EcdsaContent) (*jwk.JWK, error) {
name, err := curveName(content.Curve)
if err != nil {
return nil, err
}

size := curveSize(content.Curve)

xBytes := content.X.Bytes()
yBytes := content.Y.Bytes()

if len(xBytes) > size || len(yBytes) > size {
return nil, fmt.Errorf("go-jose/go-jose: invalid EC key (X/Y too large)")
}

key := &jwk.JWK{
Kty: "EC",
Crv: name,
X: jwk.NewFixedSizeBuffer(xBytes, size),
Y: jwk.NewFixedSizeBuffer(yBytes, size),
}

return key, nil
}

// Get JOSE name of curve.
func curveName(crv elliptic.Curve) (string, error) {
switch crv {
case elliptic.P256():
return "P-256", nil
case elliptic.P384():
return "P-384", nil
case elliptic.P521():
return "P-521", nil
default:
return "", fmt.Errorf("unsupported/unknown elliptic curve")
}
}

// Get size of curve in bytes.
func curveSize(crv elliptic.Curve) int {
bits := crv.Params().BitSize

div := bits / 8
mod := bits % 8

if mod == 0 {
return div
}

return div + 1
}
95 changes: 95 additions & 0 deletions crypto-ext/jwksupport/fingerprint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
/*
Copyright Gen Digital Inc. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
*/

package jwksupport

import (
"crypto/elliptic"
"fmt"

"github.com/trustbloc/kms-go/util/cryptoutil"

"github.com/trustbloc/did-go/doc/jose/jwk"

"github.com/trustbloc/did-go/doc/fingerprint"
)

// CreateDIDKeyByJwk creates a did:key ID using the multicodec key fingerprint as per the did:key format spec found at:
// https://w3c-ccg.github.io/did-method-key/#format.
func CreateDIDKeyByJwk(jsonWebKey *jwk.JWK) (string, string, error) {
if jsonWebKey == nil {
return "", "", fmt.Errorf("jsonWebKey is required")
}

switch jsonWebKey.Kty {
case "EC":
code, curve, err := ecCodeAndCurve(jsonWebKey.Crv)
if err != nil {
return "", "", err
}

bytes := elliptic.MarshalCompressed(curve, jsonWebKey.X.BigInt(), jsonWebKey.Y.BigInt())
didKey, keyID := fingerprint.CreateDIDKeyByCode(code, bytes)

return didKey, keyID, nil

case "OKP":
var code uint64

switch jsonWebKey.Crv {
case "X25519":
var keyData = jsonWebKey.X.Bytes()

if len(keyData) != cryptoutil.Curve25519KeySize {
return "", "", jwk.ErrInvalidKey
}

code = fingerprint.X25519PubKeyMultiCodec
didKey, keyID := fingerprint.CreateDIDKeyByCode(code, keyData)

return didKey, keyID, nil
case "Ed25519":
keyData, err := ToED25519PublicKeyBytes(jsonWebKey)
if err != nil {
return "", "", err
}

didKey, keyID := fingerprint.CreateED25519DIDKey(keyData)

return didKey, keyID, nil

default:
return "", "", fmt.Errorf(
"unsupported kty %q and crv %q combination", jsonWebKey.Kty, jsonWebKey.Crv)
}

default:
return "", "", fmt.Errorf("unsupported kty %q", jsonWebKey.Kty)
}
}

func ecCodeAndCurve(ecCurve string) (uint64, elliptic.Curve, error) {
var (
curve elliptic.Curve
code uint64
)

switch ecCurve {
case elliptic.P256().Params().Name, "NIST_P256":
curve = elliptic.P256()
code = fingerprint.P256PubKeyMultiCodec
case elliptic.P384().Params().Name, "NIST_P384":
curve = elliptic.P384()
code = fingerprint.P384PubKeyMultiCodec
case elliptic.P521().Params().Name, "NIST_P521":
curve = elliptic.P521()
code = fingerprint.P521PubKeyMultiCodec
default:
return 0, nil, fmt.Errorf("unsupported crv %s", ecCurve)
}

return code, curve, nil
}
Loading

0 comments on commit 8f5c717

Please sign in to comment.