From 793fd1cdd626cc4ffc0e9f7faf57203711b1da91 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 24 Dec 2024 15:10:23 +0800 Subject: [PATCH] update blob sign Signed-off-by: Patrick Zheng --- notation.go | 14 +++++++++----- signer/plugin.go | 13 ++++++++----- signer/plugin_test.go | 11 +++++++++++ signer/signer.go | 28 ++++++++++++++++------------ signer/signer_test.go | 11 +++++++++++ 5 files changed, 55 insertions(+), 22 deletions(-) diff --git a/notation.go b/notation.go index af5ea5e3..d4e13f52 100644 --- a/notation.go +++ b/notation.go @@ -48,7 +48,7 @@ var errDoneVerification = errors.New("done verification") var reservedAnnotationPrefixes = [...]string{"io.cncf.notary"} -// SignerSignOptions contains parameters for Signer.Sign. +// SignerSignOptions contains parameters for Signer and BlobSigner. type SignerSignOptions struct { // SignatureMediaType is the envelope type of the signature. // Currently, both `application/jose+json` and `application/cose` are @@ -89,15 +89,18 @@ type Signer interface { // SignBlobOptions contains parameters for notation.SignBlob. type SignBlobOptions struct { SignerSignOptions + // ContentMediaType is the media-type of the blob being signed. ContentMediaType string + // UserMetadata contains key-value pairs that are added to the signature // payload UserMetadata map[string]string } // BlobDescriptorGenerator creates descriptor using the digest Algorithm. -// Below is the example of minimal descriptor, it must contain mediatype, digest and size of the artifact +// Below is the example of minimal descriptor, it must contain mediatype, +// digest and size of the artifact. // // { // "mediaType": "application/octet-stream", @@ -110,8 +113,8 @@ type BlobDescriptorGenerator func(digest.Algorithm) (ocispec.Descriptor, error) // The interface allows signing with local or remote keys, // and packing in various signature formats. type BlobSigner interface { - // SignBlob signs the descriptor returned by genDesc , - // and returns the signature and SignerInfo + // SignBlob signs the descriptor returned by genDesc, and returns the + // signature and SignerInfo. SignBlob(ctx context.Context, genDesc BlobDescriptorGenerator, opts SignerSignOptions) ([]byte, *signature.SignerInfo, error) } @@ -200,7 +203,8 @@ func Sign(ctx context.Context, signer Signer, repo registry.Repository, signOpts return targetDesc, nil } -// SignBlob signs the arbitrary data and returns the signature +// SignBlob signs the arbitrary data from blobReader and returns +// the signature and SignerInfo. func SignBlob(ctx context.Context, signer BlobSigner, blobReader io.Reader, signBlobOpts SignBlobOptions) ([]byte, *signature.SignerInfo, error) { // sanity checks if err := validateSignArguments(signer, signBlobOpts.SignerSignOptions); err != nil { diff --git a/signer/plugin.go b/signer/plugin.go index b7f7a020..86b607b5 100644 --- a/signer/plugin.go +++ b/signer/plugin.go @@ -35,7 +35,8 @@ import ( ) // PluginSigner signs artifacts and generates signatures. -// It implements notation.Signer +// +// It implements notation.Signer and notation.BlobSigner. type PluginSigner struct { plugin plugin.SignPlugin keyID string @@ -49,16 +50,17 @@ var algorithms = map[crypto.Hash]digest.Algorithm{ crypto.SHA512: digest.SHA512, } -// NewFromPlugin creates a notation.Signer that signs artifacts and generates +// NewFromPlugin creates a PluginSigner that signs artifacts and generates // signatures by delegating the one or more operations to the named plugin, // as defined in https://github.com/notaryproject/notaryproject/blob/main/specs/plugin-extensibility.md#signing-interfaces. +// // Deprecated: NewFromPlugin function exists for historical compatibility and should not be used. // To create PluginSigner, use NewPluginSigner() function. func NewFromPlugin(plugin plugin.SignPlugin, keyID string, pluginConfig map[string]string) (notation.Signer, error) { return NewPluginSigner(plugin, keyID, pluginConfig) } -// NewPluginSigner creates a notation.Signer that signs artifacts and generates +// NewPluginSigner creates a PluginSigner that signs artifacts and generates // signatures by delegating the one or more operations to the named plugin, // as defined in https://github.com/notaryproject/notaryproject/blob/main/specs/plugin-extensibility.md#signing-interfaces. func NewPluginSigner(plugin plugin.SignPlugin, keyID string, pluginConfig map[string]string) (*PluginSigner, error) { @@ -82,7 +84,7 @@ func (s *PluginSigner) PluginAnnotations() map[string]string { } // Sign signs the artifact described by its descriptor and returns the -// marshalled envelope. +// signature and SignerInfo. func (s *PluginSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts notation.SignerSignOptions) ([]byte, *signature.SignerInfo, error) { logger := log.GetLogger(ctx) mergedConfig := s.mergeConfig(opts.PluginConfig) @@ -116,7 +118,8 @@ func (s *PluginSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts n return nil, nil, fmt.Errorf("plugin does not have signing capabilities") } -// SignBlob signs the arbitrary data and returns the marshalled envelope. +// SignBlob signs the descriptor returned by genDesc, and returns the +// signature and SignerInfo. func (s *PluginSigner) SignBlob(ctx context.Context, descGenFunc notation.BlobDescriptorGenerator, opts notation.SignerSignOptions) ([]byte, *signature.SignerInfo, error) { logger := log.GetLogger(ctx) mergedConfig := s.mergeConfig(opts.PluginConfig) diff --git a/signer/plugin_test.go b/signer/plugin_test.go index 634df66f..bafc4777 100644 --- a/signer/plugin_test.go +++ b/signer/plugin_test.go @@ -216,6 +216,17 @@ func (p *mockPlugin) GenerateEnvelope(ctx context.Context, req *proto.GenerateEn return &proto.GenerateEnvelopeResponse{}, nil } +func TestPluginSignerImpl(t *testing.T) { + p := &PluginSigner{} + if _, ok := interface{}(p).(notation.Signer); !ok { + t.Fatal("PluginSigner does not implement notation.Signer") + } + + if _, ok := interface{}(p).(notation.BlobSigner); !ok { + t.Fatal("PluginSigner does not implement notation.BlobSigner") + } +} + func TestNewFromPluginFailed(t *testing.T) { tests := map[string]struct { pl plugin.SignPlugin diff --git a/signer/signer.go b/signer/signer.go index 276049ff..ff380d82 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -36,19 +36,21 @@ import ( // signingAgent is the unprotected header field used by signature. const signingAgent = "notation-go/1.3.0+unreleased" -// GenericSigner implements notation.Signer and embeds signature.Signer +// GenericSigner implements notation.Signer and notation.BlobSigner. +// It embeds signature.Signer. type GenericSigner struct { signer signature.Signer } -// New returns a builtinSigner given key and cert chain +// New returns a notation.Signer given key and cert chain. +// // Deprecated: New function exists for historical compatibility and should not be used. // To create GenericSigner, use NewGenericSigner() function. func New(key crypto.PrivateKey, certChain []*x509.Certificate) (notation.Signer, error) { return NewGenericSigner(key, certChain) } -// NewGenericSigner returns a builtinSigner given key and cert chain +// NewGenericSigner returns a builtinSigner given key and cert chain. func NewGenericSigner(key crypto.PrivateKey, certChain []*x509.Certificate) (*GenericSigner, error) { localSigner, err := signature.NewLocalSigner(certChain, key) if err != nil { @@ -59,12 +61,13 @@ func NewGenericSigner(key crypto.PrivateKey, certChain []*x509.Certificate) (*Ge }, nil } -// NewFromFiles returns a builtinSigner given key and certChain paths. +// NewFromFiles returns a notation.Signer given key and certChain paths. func NewFromFiles(keyPath, certChainPath string) (notation.Signer, error) { return NewGenericSignerFromFiles(keyPath, certChainPath) } -// NewGenericSignerFromFiles returns a builtinSigner given key and certChain paths. +// NewGenericSignerFromFiles returns a builtinSigner given key and certChain +// paths. func NewGenericSignerFromFiles(keyPath, certChainPath string) (*GenericSigner, error) { if keyPath == "" { return nil, errors.New("key path not specified") @@ -96,7 +99,7 @@ func NewGenericSignerFromFiles(keyPath, certChainPath string) (*GenericSigner, e } // Sign signs the artifact described by its descriptor and returns the -// marshalled envelope. +// signature and SignerInfo. func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts notation.SignerSignOptions) ([]byte, *signature.SignerInfo, error) { logger := log.GetLogger(ctx) logger.Debugf("Generic signing for %v in signature media type %v", desc.Digest, opts.SignatureMediaType) @@ -172,17 +175,18 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts return sig, &envContent.SignerInfo, nil } -// SignBlob signs the descriptor returned by blobGen and returns the marshalled envelope -func (s *GenericSigner) SignBlob(ctx context.Context, descGenFunc notation.BlobDescriptorGenerator, opts notation.SignerSignOptions) ([]byte, *signature.SignerInfo, error) { +// SignBlob signs the descriptor returned by genDesc, and returns the +// signature and SignerInfo. +func (s *GenericSigner) SignBlob(ctx context.Context, genDesc notation.BlobDescriptorGenerator, opts notation.SignerSignOptions) ([]byte, *signature.SignerInfo, error) { logger := log.GetLogger(ctx) - logger.Debugf("Generic blob signing for signature media type %v", opts.SignatureMediaType) + logger.Debugf("Generic blob signing for signature media type %s", opts.SignatureMediaType) ks, err := s.signer.KeySpec() if err != nil { return nil, nil, err } - desc, err := getDescriptor(ks, descGenFunc) + desc, err := getDescriptor(ks, genDesc) if err != nil { return nil, nil, err } @@ -190,11 +194,11 @@ func (s *GenericSigner) SignBlob(ctx context.Context, descGenFunc notation.BlobD return s.Sign(ctx, desc, opts) } -func getDescriptor(ks signature.KeySpec, descGenFunc notation.BlobDescriptorGenerator) (ocispec.Descriptor, error) { +func getDescriptor(ks signature.KeySpec, genDesc notation.BlobDescriptorGenerator) (ocispec.Descriptor, error) { digestAlg, ok := algorithms[ks.SignatureAlgorithm().Hash()] if !ok { return ocispec.Descriptor{}, fmt.Errorf("unknown hashing algo %v", ks.SignatureAlgorithm().Hash()) } - return descGenFunc(digestAlg) + return genDesc(digestAlg) } diff --git a/signer/signer_test.go b/signer/signer_test.go index c497623d..22f3e2a1 100644 --- a/signer/signer_test.go +++ b/signer/signer_test.go @@ -162,6 +162,17 @@ func testSignerFromFile(t *testing.T, keyCert *keyCertPair, envelopeType, dir st basicVerification(t, sig, envelopeType, keyCert.certs[len(keyCert.certs)-1], nil) } +func TestGenericSignerImpl(t *testing.T) { + g := &GenericSigner{} + if _, ok := interface{}(g).(notation.Signer); !ok { + t.Fatal("GenericSigner does not implement notation.Signer") + } + + if _, ok := interface{}(g).(notation.BlobSigner); !ok { + t.Fatal("GenericSigner does not implement notation.BlobSigner") + } +} + func TestNewFromFiles(t *testing.T) { // sign with key dir := t.TempDir()