Skip to content

Commit

Permalink
test passing context to crypto sign
Browse files Browse the repository at this point in the history
  • Loading branch information
nickysemenza committed Jun 21, 2023
1 parent cd5cba1 commit 26712ae
Show file tree
Hide file tree
Showing 18 changed files with 142 additions and 100 deletions.
27 changes: 14 additions & 13 deletions client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import (

"github.com/cloudflare/cfssl/log"
"github.com/cloudflare/gokeyless/protocol"
"github.com/cloudflare/gokeyless/signer"
"github.com/cloudflare/gokeyless/tracing"
"github.com/lziest/ttlcache"
"github.com/opentracing/opentracing-go"
Expand Down Expand Up @@ -189,11 +190,11 @@ func (c *Client) getRemote(server string) (Remote, error) {
return r, nil
}

// NewRemoteSignerWithCertID returns a remote keyserver based crypto.Signer
// NewRemoteSignerWithCertID returns a remote keyserver based signer.CtxSigner
// ski, sni, serverIP, and certID are used to identify the key by the remote
// keyserver.
func NewRemoteSignerWithCertID(ctx context.Context, c *Client, keyserver string, ski protocol.SKI,
pub crypto.PublicKey, sni string, certID string, serverIP net.IP) (crypto.Signer, error) {
pub crypto.PublicKey, sni string, certID string, serverIP net.IP) (signer.CtxSigner, error) {
span, _ := opentracing.StartSpanFromContext(ctx, "client.NewRemoteSignerWithCertID")
defer span.Finish()
priv := PrivateKey{
Expand All @@ -219,11 +220,11 @@ func NewRemoteSignerWithCertID(ctx context.Context, c *Client, keyserver string,
return &priv, nil
}

// NewRemoteSigner returns a remote keyserver based crypto.Signer,
// NewRemoteSigner returns a remote keyserver based signer.CtxSigner,
// ski, sni, and serverIP are used to identified the key by the remote
// keyserver.
func NewRemoteSigner(ctx context.Context, c *Client, keyserver string, ski protocol.SKI,
pub crypto.PublicKey, sni string, serverIP net.IP) (crypto.Signer, error) {
pub crypto.PublicKey, sni string, serverIP net.IP) (signer.CtxSigner, error) {

span, _ := opentracing.StartSpanFromContext(ctx, "client.NewRemoteSignerWithCertID")
defer span.Finish()
Expand All @@ -250,11 +251,11 @@ func NewRemoteSigner(ctx context.Context, c *Client, keyserver string, ski proto
}

// NewRemoteSignerTemplate returns a remote keyserver
// based crypto.Signer with the public key.
// based signer.CtxSigner with the public key.
// SKI is computed from the public key and along with sni and serverIP,
// the remote Signer uses those key identification info to contact the
// remote keyserver for keyless operations.
func (c *Client) NewRemoteSignerTemplate(ctx context.Context, keyserver string, pub crypto.PublicKey, sni string, serverIP net.IP) (crypto.Signer, error) {
func (c *Client) NewRemoteSignerTemplate(ctx context.Context, keyserver string, pub crypto.PublicKey, sni string, serverIP net.IP) (signer.CtxSigner, error) {
ski, err := protocol.GetSKI(pub)
if err != nil {
return nil, err
Expand All @@ -263,10 +264,10 @@ func (c *Client) NewRemoteSignerTemplate(ctx context.Context, keyserver string,
}

// NewRemoteSignerTemplateWithCertID returns a remote keyserver
// based crypto.Signer with the public key.
// based signer.CtxSigner with the public key.
// SKI is computed from public key, and along with sni, serverIP, and
// certID the remote signer uses these to contact the remote keyserver.
func (c *Client) NewRemoteSignerTemplateWithCertID(ctx context.Context, keyserver string, pub crypto.PublicKey, sni string, serverIP net.IP, certID string) (crypto.Signer, error) {
func (c *Client) NewRemoteSignerTemplateWithCertID(ctx context.Context, keyserver string, pub crypto.PublicKey, sni string, serverIP net.IP, certID string) (signer.CtxSigner, error) {
ski, err := protocol.GetSKI(pub)
if err != nil {
return nil, err
Expand All @@ -276,20 +277,20 @@ func (c *Client) NewRemoteSignerTemplateWithCertID(ctx context.Context, keyserve

// NewRemoteSignerByPublicKey returns a remote keyserver based signer
// with the the public key.
func (c *Client) NewRemoteSignerByPublicKey(ctx context.Context, server string, pub crypto.PublicKey) (crypto.Signer, error) {
func (c *Client) NewRemoteSignerByPublicKey(ctx context.Context, server string, pub crypto.PublicKey) (signer.CtxSigner, error) {
return c.NewRemoteSignerTemplate(ctx, server, pub, "", nil)
}

// NewRemoteSignerByCert returns a remote keyserver based signer
// with the the public key contained in a x509.Certificate.
func (c *Client) NewRemoteSignerByCert(ctx context.Context, server string, cert *x509.Certificate) (crypto.Signer, error) {
func (c *Client) NewRemoteSignerByCert(ctx context.Context, server string, cert *x509.Certificate) (signer.CtxSigner, error) {
return c.NewRemoteSignerTemplate(ctx, server, cert.PublicKey, "", nil)
}

// NewRemoteSignerByCertPEM returns a remote keyserver based signer
// with the public key extracted from a single PEM cert
// (possibly the leaf of a chain of certs).
func (c *Client) NewRemoteSignerByCertPEM(ctx context.Context, server string, certsPEM []byte) (crypto.Signer, error) {
func (c *Client) NewRemoteSignerByCertPEM(ctx context.Context, server string, certsPEM []byte) (signer.CtxSigner, error) {
block, _ := pem.Decode(certsPEM)
if block == nil {
return nil, errors.New("couldn't parse PEM bytes")
Expand All @@ -309,7 +310,7 @@ var (
)

// ScanDir reads all .pubkey and .crt files from a directory and returns associated PublicKey structs.
func (c *Client) ScanDir(server, dir string, LoadPubKey func([]byte) (crypto.PublicKey, error)) (privkeys []crypto.Signer, err error) {
func (c *Client) ScanDir(server, dir string, LoadPubKey func([]byte) (crypto.PublicKey, error)) (privkeys []signer.CtxSigner, err error) {
err = filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
if err != nil {
return err
Expand All @@ -325,7 +326,7 @@ func (c *Client) ScanDir(server, dir string, LoadPubKey func([]byte) (crypto.Pub
return err
}

var priv crypto.Signer
var priv signer.CtxSigner
if LoadPubKey == nil {
LoadPubKey = DefaultLoadPubKey
}
Expand Down
6 changes: 3 additions & 3 deletions client/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ type PrivateKey struct {
certID string

// We have shove the span context inside PrivateKey because
// it's used by calling functions on the `crypto.Signer` interface, which don't take ctx as a parameter.
// it's used by calling functions on the `signer.CtxSigner` interface, which don't take ctx as a parameter.
JaegerSpan []byte
}

Expand Down Expand Up @@ -161,8 +161,8 @@ func (key *PrivateKey) execute(ctx context.Context, op protocol.Op, msg []byte)
return result.Payload, nil
}

// Sign implements the crypto.Signer operation for the given key.
func (key *PrivateKey) Sign(r io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
// Sign implements the signer.CtxSigner operation for the given key.
func (key *PrivateKey) Sign(ctx context.Context, r io.Reader, msg []byte, opts crypto.SignerOpts) ([]byte, error) {
spanCtx, err := tracing.SpanContextFromBinary(key.JaegerSpan)
if err != nil {
log.Errorf("failed to extract span: %v", err)
Expand Down
28 changes: 13 additions & 15 deletions client/remote_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ package client

import (
"context"
"crypto"
"crypto/x509"
"encoding/pem"
"log"
Expand All @@ -11,9 +10,8 @@ import (
"testing"
"time"

"github.com/cloudflare/cfssl/helpers"
"github.com/cloudflare/cfssl/helpers/derhelpers"
"github.com/cloudflare/gokeyless/server"
"github.com/cloudflare/gokeyless/signer"
"github.com/stretchr/testify/require"
)

Expand All @@ -37,8 +35,8 @@ var (
sAddr string
s *server.Server
c *Client
rsaSigner crypto.Signer
ecdsaSigner crypto.Signer
rsaSigner signer.CtxSigner
ecdsaSigner signer.CtxSigner
remote Remote
deadRemote Remote
)
Expand All @@ -48,15 +46,15 @@ func fixedCurrentTime() time.Time {
return time.Date(2019, time.March, 1, 0, 0, 0, 0, time.UTC)
}

// LoadKey attempts to load a private key from PEM or DER.
func LoadKey(in []byte) (priv crypto.Signer, err error) {
priv, err = helpers.ParsePrivateKeyPEM(in)
if err == nil {
return priv, nil
}
// // LoadKey attempts to load a private key from PEM or DER.
// func LoadKey(in []byte) (priv crypto.Signer, err error) {
// priv, err = helpers.ParsePrivateKeyPEM(in)
// if err == nil {
// return priv, nil
// }

return derhelpers.ParsePrivateKeyDER(in)
}
// return derhelpers.ParsePrivateKeyDER(in)
// }

// Set up compatible server and client for use by tests.
func TestMain(m *testing.M) {
Expand All @@ -68,7 +66,7 @@ func TestMain(m *testing.M) {
}
s.TLSConfig().Time = fixedCurrentTime

keys, err := server.NewKeystoreFromDir("testdata", LoadKey)
keys, err := server.NewKeystoreFromDir("testdata", server.DefaultLoadKey)
if err != nil {
log.Fatal(err)
}
Expand Down Expand Up @@ -241,7 +239,7 @@ func TestSlowServer(t *testing.T) {
}

// helper function reads a cert from a file and convert it to a signer
func NewRemoteSignerByCertFile(filepath string) (crypto.Signer, error) {
func NewRemoteSignerByCertFile(filepath string) (signer.CtxSigner, error) {
pemBytes, err := os.ReadFile(filepath)
if err != nil {
return nil, err
Expand Down
16 changes: 9 additions & 7 deletions internal/azure/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
"github.com/Azure/go-autorest/autorest/azure"
"github.com/Azure/go-autorest/autorest/azure/auth"
"github.com/cloudflare/cfssl/log"
"github.com/cloudflare/gokeyless/signer"
jose "gopkg.in/square/go-jose.v2"
)

Expand All @@ -37,9 +38,9 @@ type KeyVaultSigner struct {
}

// must conform to the interface
var _ crypto.Signer = KeyVaultSigner{}
var _ signer.CtxSigner = KeyVaultSigner{}

// New creates a client that implements `crypto.Signer` backed by Azure Key Vault or Azure Managed HSM at the given uri
// New creates a client that implements `signer.CtxSigner` backed by Azure Key Vault or Azure Managed HSM at the given uri
// The URL should be contain the key version (i.e. `https://vault-name.vault.azure.net/keys/key-name/abc`)
// Required roles are `/keys/read/action` and `/keys/sign/action`, the minimum built in Role that fuffils these is `Crypto User`
// RBAC reference: https://docs.microsoft.com/en-us/azure/key-vault/managed-hsm/built-in-roles#permitted-operations
Expand Down Expand Up @@ -77,8 +78,8 @@ func (k KeyVaultSigner) Public() crypto.PublicKey {
return k.pub
}

// Sign makes an API call to sign the provided bytes, mapping the hash in `crypto.SignerOps` to a JWK Signature Algorithm
func (k KeyVaultSigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
// Sign makes an API call to sign the provided bytes, mapping the hash in `signer.CtxSignerOps` to a JWK Signature Algorithm
func (k KeyVaultSigner) Sign(ctx context.Context, _ io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {

// base64url required as per https://docs.microsoft.com/en-us/azure/key-vault/general/about-keys-secrets-certificates#data-types
payload := base64.RawURLEncoding.EncodeToString(digest)
Expand All @@ -88,7 +89,7 @@ func (k KeyVaultSigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts)
return nil, err
}

signed, err := k.client.Sign(context.Background(), k.baseURL, k.keyName, k.keyVersion, keyvault.KeySignParameters{Algorithm: algo, Value: &payload})
signed, err := k.client.Sign(ctx, k.baseURL, k.keyName, k.keyVersion, keyvault.KeySignParameters{Algorithm: algo, Value: &payload})
if err != nil {
return nil, fmt.Errorf("azure: failed to sign: %w", err)
}
Expand All @@ -107,7 +108,8 @@ func (k KeyVaultSigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts)
return convert1363ToAsn1(res)
}

// map the signature algirthm to the relevant JWK one
// map the signature algirthm to the relevant JWK one
//
// see https://tools.ietf.org/html/rfc7518#section-3.1
func (k KeyVaultSigner) determineSigAlg(opts crypto.SignerOpts) (algo keyvault.JSONWebKeySignatureAlgorithm, err error) {
switch {
Expand All @@ -133,7 +135,7 @@ func (k KeyVaultSigner) determineSigAlg(opts crypto.SignerOpts) (algo keyvault.J
// 1. fetch the specified version of the key
// 2. Ensure that the key type supports a signing operation that is also supported by keyless.
// 3. marshals the JWK into json, so that it can be unmarshalled into jose's JWK format
// 4. extract the public key from the JWK (crypto.Signer's `Public()` must be implemented so keyless can calculate the SKI)
// 4. extract the public key from the JWK (signer.CtxSigner's `Public()` must be implemented so keyless can calculate the SKI)
//
// note: other similar codebases directly massage the public key out of the keyvault.KeyBundle
// see:
Expand Down
2 changes: 1 addition & 1 deletion internal/azure/azure_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func TestSmoke(t *testing.T) {
require.Equal(alg, keyvault.RS384)
require.NoError(err)

sig, err := k.Sign(nil, []byte("digest"), crypto.SHA384)
sig, err := k.Sign(context.Background(), nil, []byte("digest"), crypto.SHA384)
require.Equal(sig, []byte("digest"))
require.NoError(err)

Expand Down
11 changes: 6 additions & 5 deletions internal/google/google.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (

kms "cloud.google.com/go/kms/apiv1"
"github.com/cloudflare/cfssl/log"
"github.com/cloudflare/gokeyless/signer"
"github.com/googleapis/gax-go/v2"
kmspb "google.golang.org/genproto/googleapis/cloud/kms/v1"
"google.golang.org/protobuf/types/known/wrapperspb"
Expand All @@ -22,7 +23,7 @@ type kmsClient interface {
GetPublicKey(ctx context.Context, req *kmspb.GetPublicKeyRequest, opts ...gax.CallOption) (*kmspb.PublicKey, error)
}

// KMSSigner is a crypto.Signer for Google Cloud KMS
// KMSSigner is a signer.CtxSigner for Google Cloud KMS
type KMSSigner struct {
client kmsClient
name string
Expand All @@ -34,7 +35,7 @@ type KMSSigner struct {
}

// must conform to the interface
var _ crypto.Signer = KMSSigner{}
var _ signer.CtxSigner = KMSSigner{}

// New creates a new signer with the given KMS key resource name
func New(name string) (*KMSSigner, error) {
Expand All @@ -58,8 +59,8 @@ func (k KMSSigner) Public() crypto.PublicKey {
return k.pub
}

// Sign makes an API call to sign the provided bytes, mapping the hash in `crypto.SignerOps` to a JWK Signature Algorithm
func (k KMSSigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
// Sign makes an API call to sign the provided bytes, mapping the hash in `signer.CtxSignerOps` to a JWK Signature Algorithm
func (k KMSSigner) Sign(ctx context.Context, _ io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
var payload kmspb.Digest
switch opts {
case crypto.SHA256: // for OpECDSASignSHA256 and OpRSASignSHA256
Expand All @@ -85,7 +86,7 @@ func (k KMSSigner) Sign(_ io.Reader, digest []byte, opts crypto.SignerOpts) (sig
}

// Call the API.
result, err := k.client.AsymmetricSign(context.Background(), req)
result, err := k.client.AsymmetricSign(ctx, req)
if err != nil {
return nil, fmt.Errorf("google: failed to sign digest: %w", err)
}
Expand Down
2 changes: 1 addition & 1 deletion internal/google/google_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func TestSmoke(t *testing.T) {
}
require.Equal(k.Public(), pub)

sig, err := k.Sign(nil, []byte("digest"), crypto.SHA256)
sig, err := k.Sign(context.Background(), nil, []byte("digest"), crypto.SHA256)
require.NoError(err)
require.Equal(sig, []byte("digest"))

Expand Down
12 changes: 6 additions & 6 deletions internal/rfc7512/rfc7512.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,18 +3,18 @@

// Package rfc7512 provides a parser for the PKCS #11 URI format as specified in
// RFC 7512: The PKCS #11 URI Scheme. Additionally, it provides a wrapper around
// the crypto11 package for loading a key pair as a crypto.Signer object.
// the crypto11 package for loading a key pair as a signer.CtxSigner object.
package rfc7512

import (
"crypto"
"fmt"
"net/url"
"strconv"
"strings"
"time"

"github.com/ThalesIgnite/crypto11"
"github.com/cloudflare/gokeyless/signer"
)

// PKCS11URI contains the information for accessing a PKCS #11 storage object,
Expand Down Expand Up @@ -187,7 +187,7 @@ func ParsePKCS11URI(uri string) (*PKCS11URI, error) {
//
// An error is returned if the crypto11 module cannot find the module, token,
// or the specified object.
func LoadPKCS11Signer(pk11uri *PKCS11URI) (crypto.Signer, error) {
func LoadPKCS11Signer(pk11uri *PKCS11URI) (signer.CtxSigner, error) {
config := &crypto11.Config{
Path: pk11uri.ModulePath,
TokenSerial: pk11uri.Serial,
Expand All @@ -208,12 +208,12 @@ func LoadPKCS11Signer(pk11uri *PKCS11URI) (crypto.Signer, error) {
return nil, fmt.Errorf("pkcs11 Configure: %w", err)
}

signer, err := context.FindKeyPair(pk11uri.ID, pk11uri.Object)
s, err := context.FindKeyPair(pk11uri.ID, pk11uri.Object)
if err != nil {
return nil, fmt.Errorf("pkcs11 FindKeyPair: %w", err)
} else if signer == nil {
} else if s == nil {
return nil, fmt.Errorf("not found")
}

return signer, nil
return signer.WrapSigner(s), nil
}
Loading

0 comments on commit 26712ae

Please sign in to comment.