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

revert: "feat: add support for signing blob (#379)" #411

Merged
merged 3 commits into from
May 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions example_localSign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,8 @@ func Example_localSign() {
// Users should replace `exampleCertTuple.PrivateKey` with their own private
// key and replace `exampleCerts` with the corresponding full certificate
// chain, following the Notary certificate requirements:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/signature-specification.md#certificate-requirements
exampleSigner, err := signer.NewGenericSigner(exampleCertTuple.PrivateKey, exampleCerts)
// https://github.com/notaryproject/notaryproject/blob/v1.0.0-rc.1/specs/signature-specification.md#certificate-requirements
exampleSigner, err := signer.New(exampleCertTuple.PrivateKey, exampleCerts)
if err != nil {
panic(err) // Handle error
}
Expand Down
7 changes: 3 additions & 4 deletions example_remoteSign_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,12 @@ import (
"crypto/x509"
"fmt"

"oras.land/oras-go/v2/registry/remote"

"github.com/notaryproject/notation-core-go/signature/cose"
"github.com/notaryproject/notation-core-go/testhelper"
"github.com/notaryproject/notation-go"
"github.com/notaryproject/notation-go/registry"
"github.com/notaryproject/notation-go/signer"
"oras.land/oras-go/v2/registry/remote"
)

// Both COSE ("application/cose") and JWS ("application/jose+json")
Expand All @@ -46,8 +45,8 @@ func Example_remoteSign() {
// Users should replace `exampleCertTuple.PrivateKey` with their own private
// key and replace `exampleCerts` with the corresponding full certificate
// chain, following the Notary certificate requirements:
// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/signature-specification.md#certificate-requirements
exampleSigner, err := signer.NewGenericSigner(exampleCertTuple.PrivateKey, exampleCerts)
// https://github.com/notaryproject/notaryproject/blob/v1.0.0-rc.1/specs/signature-specification.md#certificate-requirements
exampleSigner, err := signer.New(exampleCertTuple.PrivateKey, exampleCerts)
if err != nil {
panic(err) // Handle error
}
Expand Down
112 changes: 112 additions & 0 deletions log/log_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,3 +39,115 @@ func TestGetLoggerWithNoLogger(t *testing.T) {
t.Errorf("GetLogger() = %v, want Discard", got)
}
}

func TestDiscardLogger(t *testing.T) {
logger := &discardLogger{}

t.Run("Debug", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("method panicked")
}
}()
logger.Debug("test")
})

t.Run("Debugf", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("method panicked")
}
}()
logger.Debugf("test %s", "format")
})

t.Run("Debugln", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("method panicked")
}
}()
logger.Debugln("test")
})

t.Run("Info", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("method panicked")
}
}()
logger.Info("test")
})

t.Run("Infof", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("method panicked")
}
}()
logger.Infof("test %s", "format")
})

t.Run("Infoln", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("method panicked")
}
}()
logger.Infoln("test")
})

t.Run("Warn", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("method panicked")
}
}()
logger.Warn("test")
})

t.Run("Warnf", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("method panicked")
}
}()
logger.Warnf("test %s", "format")
})

t.Run("Warnln", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("method panicked")
}
}()
logger.Warnln("test")
})

t.Run("Error", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("method panicked")
}
}()
logger.Error("test")
})

t.Run("Errorf", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("method panicked")
}
}()
logger.Errorf("test %s", "format")
})

t.Run("Errorln", func(t *testing.T) {
defer func() {
if r := recover(); r != nil {
t.Errorf("method panicked")
}
}()
logger.Errorln("test")
})
}
110 changes: 15 additions & 95 deletions notation.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,17 +22,13 @@
"encoding/json"
"errors"
"fmt"
"io"
"mime"
"strings"
"time"

orasRegistry "oras.land/oras-go/v2/registry"
"oras.land/oras-go/v2/registry/remote"

"github.com/notaryproject/notation-core-go/signature"
"github.com/notaryproject/notation-core-go/signature/cose"
"github.com/notaryproject/notation-core-go/signature/jws"
"github.com/notaryproject/notation-go/internal/envelope"
"github.com/notaryproject/notation-go/log"
"github.com/notaryproject/notation-go/registry"
Expand All @@ -48,7 +44,7 @@
// SignerSignOptions contains parameters for Signer.Sign.
type SignerSignOptions struct {
// SignatureMediaType is the envelope type of the signature.
// Currently, both `application/jose+json` and `application/cose` are
// Currently both `application/jose+json` and `application/cose` are
// supported.
SignatureMediaType string

Expand All @@ -63,37 +59,15 @@
SigningAgent string
}

// Signer is a generic interface for signing an OCI artifact.
// Signer is a generic interface for signing an artifact.
// The interface allows signing with local or remote keys,
// and packing in various signature formats.
type Signer interface {
// Sign signs the OCI artifact described by its descriptor,
// Sign signs the artifact described by its descriptor,
// and returns the signature and SignerInfo.
Sign(ctx context.Context, desc ocispec.Descriptor, opts SignerSignOptions) ([]byte, *signature.SignerInfo, error)
}

// 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.
type BlobDescriptorGenerator func(digest.Algorithm) (ocispec.Descriptor, error)

// BlobSigner is a generic interface for signing arbitrary data.
// 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(ctx context.Context, genDesc BlobDescriptorGenerator, opts SignerSignOptions) ([]byte, *signature.SignerInfo, error)
}

// signerAnnotation facilitates return of manifest annotations by signers
type signerAnnotation interface {
// PluginAnnotations returns signature manifest annotations returned from
Expand All @@ -114,16 +88,22 @@
UserMetadata map[string]string
}

// Sign signs the OCI artifact and push the signature to the Repository.
// The descriptor of the sign content is returned upon successful signing.
// Sign signs the artifact and push the signature to the Repository.
// The descriptor of the sign content is returned upon sucessful signing.
func Sign(ctx context.Context, signer Signer, repo registry.Repository, signOpts SignOptions) (ocispec.Descriptor, error) {
// sanity check
if err := validateSignArguments(signer, signOpts.SignerSignOptions); err != nil {
return ocispec.Descriptor{}, err
if signer == nil {
return ocispec.Descriptor{}, errors.New("signer cannot be nil")

Check warning on line 96 in notation.go

View check run for this annotation

Codecov / codecov/patch

notation.go#L96

Added line #L96 was not covered by tests
}
if repo == nil {
return ocispec.Descriptor{}, errors.New("repo cannot be nil")
}
if signOpts.ExpiryDuration < 0 {
return ocispec.Descriptor{}, fmt.Errorf("expiry duration cannot be a negative value")
}
if signOpts.ExpiryDuration%time.Second != 0 {
return ocispec.Descriptor{}, fmt.Errorf("expiry duration supports minimum granularity of seconds")
}

logger := log.GetLogger(ctx)
artifactRef := signOpts.ArtifactReference
Expand Down Expand Up @@ -179,50 +159,6 @@
return targetDesc, nil
}

// SignBlob signs the arbitrary data and returns the signature
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 {
return nil, nil, err
}

if blobReader == nil {
return nil, nil, errors.New("blobReader cannot be nil")
}

if signBlobOpts.ContentMediaType == "" {
return nil, nil, errors.New("content media-type cannot be empty")
}

if _, _, err := mime.ParseMediaType(signBlobOpts.ContentMediaType); err != nil {
return nil, nil, fmt.Errorf("invalid content media-type '%s': %v", signBlobOpts.ContentMediaType, err)
}

getDescFunc := getDescriptorFunc(ctx, blobReader, signBlobOpts.ContentMediaType, signBlobOpts.UserMetadata)
return signer.SignBlob(ctx, getDescFunc, signBlobOpts.SignerSignOptions)
}

func validateSignArguments(signer any, signOpts SignerSignOptions) error {
if signer == nil {
return errors.New("signer cannot be nil")
}
if signOpts.ExpiryDuration < 0 {
return errors.New("expiry duration cannot be a negative value")
}
if signOpts.ExpiryDuration%time.Second != 0 {
return errors.New("expiry duration supports minimum granularity of seconds")
}
if signOpts.SignatureMediaType == "" {
return errors.New("signature media-type cannot be empty")
}

if !(signOpts.SignatureMediaType == jws.MediaTypeEnvelope || signOpts.SignatureMediaType == cose.MediaTypeEnvelope) {
return fmt.Errorf("invalid signature media-type '%s'", signOpts.SignatureMediaType)
}

return nil
}

func addUserMetadataToDescriptor(ctx context.Context, desc ocispec.Descriptor, userMetadata map[string]string) (ocispec.Descriptor, error) {
logger := log.GetLogger(ctx)

Expand Down Expand Up @@ -307,7 +243,7 @@

// VerifierVerifyOptions contains parameters for Verifier.Verify.
type VerifierVerifyOptions struct {
// ArtifactReference is the reference of the artifact that is being
// ArtifactReference is the reference of the artifact that is been
// verified against to. It must be a full reference.
ArtifactReference string

Expand Down Expand Up @@ -341,7 +277,7 @@

// VerifyOptions contains parameters for notation.Verify.
type VerifyOptions struct {
// ArtifactReference is the reference of the artifact that is being
// ArtifactReference is the reference of the artifact that is been
// verified against to.
ArtifactReference string

Expand Down Expand Up @@ -520,19 +456,3 @@
annotations[ocispec.AnnotationCreated] = signingTime.Format(time.RFC3339)
return annotations, nil
}

func getDescriptorFunc(ctx context.Context, reader io.Reader, contentMediaType string, userMetadata map[string]string) BlobDescriptorGenerator {
return func(hashAlgo digest.Algorithm) (ocispec.Descriptor, error) {
digester := hashAlgo.Digester()
bytes, err := io.Copy(digester.Hash(), reader)
if err != nil {
return ocispec.Descriptor{}, err
}
targetDesc := ocispec.Descriptor{
MediaType: contentMediaType,
Digest: digester.Digest(),
Size: bytes,
}
return addUserMetadataToDescriptor(ctx, targetDesc, userMetadata)
}
}
Loading
Loading