Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for crypto.Signer when signing and verifying signatures #48

Merged
merged 5 commits into from
Sep 2, 2024

Conversation

wolfeidau
Copy link
Contributor

@wolfeidau wolfeidau commented Aug 28, 2024

This change will enable the use of KMS signing in AWS and possibly GCP as these services can implement crypto.Signer and provide signatures for the pipeline signing feature.

@wolfeidau wolfeidau changed the title Add support for crypto.Signer when signing and verifying signatures PIPE-58: Add support for crypto.Signer when signing and verifying signatures Aug 29, 2024
@wolfeidau wolfeidau changed the title PIPE-58: Add support for crypto.Signer when signing and verifying signatures Add support for crypto.Signer when signing and verifying signatures Aug 29, 2024
Copy link
Contributor

@patrobinson patrobinson left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry for the non-review, I'm keen to see this land but I don't understand enough.

@@ -113,16 +120,28 @@ func Sign(_ context.Context, key jwk.Key, sf SignedFielder, opts ...Option) (*pi
return nil, err
}

if options.logger != nil {
switch key := key.(type) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is new to me!
I haven't done serious Golang development for a while, you used to need to do Reflect here but that was pretty slow. Is this some newish Golang feature?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Type switches have been around for a very long time: https://web.archive.org/web/20120331010210/golang.org/ref/spec

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How had I never come across this before!
I needed the magic words to google, it's called a TypeSwitchGuard

@@ -113,16 +120,28 @@ func Sign(_ context.Context, key jwk.Key, sf SignedFielder, opts ...Option) (*pi
return nil, err
}

if options.logger != nil {
switch key := key.(type) {
case jwk.Key:
pk, err := key.PublicKey()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method isn't implemented in the above interface

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Within this case, key has the type jwk.Key, since it was redeclared within the switch line (key := key.(type)). This is probably the most magical of all Go syntax.

@@ -73,9 +75,14 @@ func configureOptions(opts ...Option) options {
return options
}

type Key interface {
Algorithm() jwa.KeyAlgorithm
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused, how could crypto.Signer implement this interface?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A caller to Sign would supply a key having some concrete type that implements Key. Whether that value has a concrete type that also implements crypto.Signer can be determined by the type switch.

Copy link
Contributor

@DrJosh9000 DrJosh9000 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Really great work, I have a few small comments but otherwise :shipit:

return nil, fmt.Errorf("failed to marshal public key: %w", err)
}

debug(options.logger, "Public Key Thumbprint (sha256): %x", sha256.Sum256(data))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we're here, we could replace hex.EncodeToString with a %x verb in the other debug log (line 135)

@@ -134,6 +139,126 @@ func TestSignVerify(t *testing.T) {
}
}

var _ crypto.Signer = MockCryptoSigner{}

type MockCryptoSigner struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My only quibble here (very minor) is I would call this a fake instead of a mock, since it lacks the ability to check whether its methods were called (a good thing).

RepositoryURL: "fake-repo",
}

cases := []struct {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since there's only one test case, it's probably overkill to set up the table-driven test infrastructure like this, but OTOH might be useful if we plan to add more cases?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@DrJosh9000 yeah I figure at some point we will need more test cases so i left it a table.


block, _ := pem.Decode([]byte(pemPrivateKey))
x509Encoded := block.Bytes
privateKey, _ := x509.ParseECPrivateKey(x509Encoded)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's unlikely, but if we accidentally screw up the private key file such that this fails, we should probably t.Fatalf out and report the error.

t.Fatalf("os.ReadFile(%q) error = %v", privateKeyPath, err)
}

block, _ := pem.Decode([]byte(pemPrivateKey))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Funny how this looks like an ignored error, but isn't. According to the docs, block would be nil if it failed to parse. Arguably we could check that and t.Fatalf, but since the following line would panic, it's not a big deal.

@wolfeidau wolfeidau merged commit 09eb8d4 into main Sep 2, 2024
1 check passed
@wolfeidau wolfeidau deleted the feat_support_crypto_signer branch September 2, 2024 00:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants