Skip to content

Commit

Permalink
Add support for passing a private key to the fake KMS signer
Browse files Browse the repository at this point in the history
The private key is passed in the context.

Signed-off-by: Hayden Blauzvern <hblauzvern@google.com>
  • Loading branch information
haydentherapper committed Mar 31, 2022
1 parent c43c8ee commit f0d31ea
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 11 deletions.
37 changes: 27 additions & 10 deletions pkg/signature/kms/fake/signer.go
Expand Up @@ -26,31 +26,44 @@ import (

// SignerVerifier creates and verifies digital signatures over a message using an in-memory signer
type SignerVerifier struct {
signer *signature.ECDSASignerVerifier
signer signature.SignerVerifier
}

// ReferenceScheme is a scheme for fake KMS keys. Do not use in production.
const ReferenceScheme = "fakekms://"

func init() {
sigkms.AddProvider(ReferenceScheme, func(_ context.Context, _ string, _ crypto.Hash, _ ...signature.RPCOption) (sigkms.SignerVerifier, error) {
return LoadSignerVerifier()
sigkms.AddProvider(ReferenceScheme, func(ctx context.Context, _ string, hf crypto.Hash, _ ...signature.RPCOption) (sigkms.SignerVerifier, error) {
return LoadSignerVerifier(ctx, hf)
})
}

// LoadSignerVerifier generates signatures using the default ECDSA signer.
func LoadSignerVerifier() (*SignerVerifier, error) {
signer, _, err := signature.NewDefaultECDSASignerVerifier()
// LoadSignerVerifier generates a signer/verifier using the default ECDSA signer or loads
// a signer from a provided private key and hash. The context should contain a mapping from
// a string "priv" to a crypto.PrivateKey (RSA, ECDSA, or ED25519).
func LoadSignerVerifier(ctx context.Context, hf crypto.Hash) (*SignerVerifier, error) {
val := ctx.Value("priv")
if val == nil {
signer, _, err := signature.NewDefaultECDSASignerVerifier()
if err != nil {
return nil, err
}
sv := &SignerVerifier{
signer: signer,
}
return sv, nil
}
signer, err := signature.LoadSignerVerifier(val.(crypto.PrivateKey), hf)
if err != nil {
return nil, err
}
g := &SignerVerifier{
sv := &SignerVerifier{
signer: signer,
}
return g, nil
return sv, nil
}

// SignMessage signs the provided message using the in-memory -signer.
// SignMessage signs the provided message using the in-memory signer.
func (g *SignerVerifier) SignMessage(message io.Reader, opts ...signature.SignOption) ([]byte, error) {
return g.signer.SignMessage(message, opts...)
}
Expand Down Expand Up @@ -78,7 +91,11 @@ func (g *SignerVerifier) VerifySignature(signature, message io.Reader, opts ...s

// CreateKey returns the signer's public key.
func (g *SignerVerifier) CreateKey(etx context.Context, algorithm string) (crypto.PublicKey, error) {
return g.signer.Public(), nil
pub, err := g.signer.PublicKey()
if err != nil {
return nil, err
}
return pub, nil
}

type cryptoSignerWrapper struct {
Expand Down
59 changes: 58 additions & 1 deletion pkg/signature/kms/fake/signer_test.go
Expand Up @@ -18,6 +18,8 @@ import (
"bytes"
"context"
"crypto"
"crypto/ecdsa"
"crypto/elliptic"
"crypto/rand"
"crypto/sha256"
"testing"
Expand All @@ -29,7 +31,7 @@ import (
func TestFakeSigner(t *testing.T) {
msg := []byte{1, 2, 3, 4, 5}

signer, err := kms.Get(context.Background(), "fakekms://projects/project/locations/us-west1/keyRings/key-ring/cryptoKeys/key/cryptoKeyVersions/1", crypto.SHA256)
signer, err := kms.Get(context.Background(), "fakekms://key", crypto.SHA256)
if err != nil {
t.Fatalf("unexpected error getting signer: %v", err)
}
Expand Down Expand Up @@ -69,3 +71,58 @@ func TestFakeSigner(t *testing.T) {
t.Fatalf("unexpected error verifying signature: %v", err)
}
}

func TestFakeSignerWithPrivateKey(t *testing.T) {
msg := []byte{1, 2, 3, 4, 5}

priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
if err != nil {
t.Fatalf("error generating ecdsa private key: %v", err)
}

signer, err := kms.Get(context.WithValue(context.TODO(), "priv", priv), "fakekms://key", crypto.SHA256)
if err != nil {
t.Fatalf("unexpected error getting signer: %v", err)
}
pub, err := signer.PublicKey()
if err != nil {
t.Fatalf("unexpected error getting public key")
}

// Compare public key to provided key
if err := cryptoutils.EqualKeys(priv.Public(), pub); err != nil {
t.Fatalf("expected public keys to be equal: %v", err)
}

createdPub, err := signer.CreateKey(context.Background(), "")
if err != nil {
t.Fatalf("unexpected error creating key: %v", err)
}
if err := cryptoutils.EqualKeys(createdPub, pub); err != nil {
t.Fatalf("expected public keys to be equal: %v", err)
}

if signer.DefaultAlgorithm() != signer.SupportedAlgorithms()[0] {
t.Fatal("expected algorithms to match")
}

// Test crypto.Signer implementation
cryptoSigner, _, err := signer.CryptoSigner(context.Background(), func(err error) {})
if err != nil {
t.Fatalf("unexpected error fetching crypto.Signer: %v", err)
}
if err := cryptoutils.EqualKeys(cryptoSigner.Public(), pub); err != nil {
t.Fatalf("expected public keys to be equal: %v", err)
}

sha := sha256.New()
sha.Write(msg)
digest := sha.Sum(nil)
sig, err := cryptoSigner.Sign(rand.Reader, digest, nil)
if err != nil {
t.Fatalf("unexpected error signing with crypto.Signer: %v", err)
}
if err := signer.VerifySignature(bytes.NewReader(sig), bytes.NewReader(msg)); err != nil {
t.Fatalf("unexpected error verifying signature: %v", err)
}
}

0 comments on commit f0d31ea

Please sign in to comment.