Skip to content

Commit

Permalink
Pass expiry to envelope-generator plugin (#222)
Browse files Browse the repository at this point in the history
There will be two PRs, one in notation-go([PR#222](#222))
and other in notation([PR#458](notaryproject/notation#458)) repo.

*Tests are failing because this PR depends on #222

Issue: notaryproject/notation#443

Signed-off-by: Pritesh Bandi <pritesb@amazon.com>
  • Loading branch information
priteshbandi authored Dec 2, 2022
1 parent 35d9060 commit bc022cc
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 23 deletions.
15 changes: 12 additions & 3 deletions notation.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,9 @@ type SignOptions struct {
// supported.
SignatureMediaType string

// Expiry identifies the expiration time of the resulted signature.
Expiry time.Time
// ExpiryDuration identifies the expiry duration of the resulted signature. Zero value
// represents no expiry duration.
ExpiryDuration time.Duration

// Sets or overrides the plugin configuration.
PluginConfig map[string]string
Expand All @@ -54,8 +55,16 @@ type Signer interface {
// remote.
// The descriptor of the sign content is returned upon sucessful signing.
func Sign(ctx context.Context, signer Signer, repo registry.Repository, opts SignOptions) (ocispec.Descriptor, error) {
logger := log.GetLogger(ctx)
// Input validation for expiry duration
if opts.ExpiryDuration < 0 {
return ocispec.Descriptor{}, fmt.Errorf("expiry duration cannot be a negative value")
}

if opts.ExpiryDuration%time.Second != 0 {
return ocispec.Descriptor{}, fmt.Errorf("expiry duration supports minimum granularity of seconds")
}

logger := log.GetLogger(ctx)
artifactRef := opts.ArtifactReference
ref, err := orasRegistry.ParseReference(artifactRef)
if err != nil {
Expand Down
51 changes: 51 additions & 0 deletions notation_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,58 @@ import (
"errors"
"fmt"
"testing"
"time"

"github.com/notaryproject/notation-core-go/signature"
"github.com/notaryproject/notation-go/internal/mock"
"github.com/notaryproject/notation-go/plugin"
"github.com/notaryproject/notation-go/verifier/trustpolicy"
ocispec "github.com/opencontainers/image-spec/specs-go/v1"
)

func TestSignSuccess(t *testing.T) {
repo := mock.NewRepository()
testCases := []struct {
name string
dur time.Duration
}{
{"expiryInHours", 24 * time.Hour},
{"oneSecondExpiry", 1 * time.Second},
{"zeroExpiry", 0},
}
for _, tc := range testCases {
t.Run(tc.name, func(b *testing.T) {
opts := SignOptions{
ExpiryDuration: tc.dur,
ArtifactReference: mock.SampleArtifactUri,
}
_, err := Sign(context.Background(), &dummySigner{}, repo, opts)
if err != nil {
b.Fatalf("Sign failed with error: %v", err)
}
})
}
}

func TestSignWithInvalidExpiry(t *testing.T) {
repo := mock.NewRepository()
testCases := []struct {
name string
dur time.Duration
}{
{"negativeExpiry", -24 * time.Hour},
{"splitSecondExpiry", 1 * time.Millisecond},
}
for _, tc := range testCases {
t.Run(tc.name, func(b *testing.T) {
_, err := Sign(context.Background(), &dummySigner{}, repo, SignOptions{ExpiryDuration: tc.dur})
if err == nil {
b.Fatalf("Expected error but not found")
}
})
}
}

func TestRegistryResolveError(t *testing.T) {
policyDocument := dummyPolicyDocument()
repo := mock.NewRepository()
Expand Down Expand Up @@ -172,6 +217,12 @@ func dummyPolicyStatement() (policyStatement trustpolicy.TrustPolicy) {
return
}

type dummySigner struct{}

func (s *dummySigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts SignOptions) ([]byte, *signature.SignerInfo, error) {
return []byte("ABC"), &signature.SignerInfo{}, nil
}

type dummyVerifier struct {
TrustPolicyDoc *trustpolicy.Document
PluginManager plugin.Manager
Expand Down
13 changes: 7 additions & 6 deletions plugin/proto/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,12 +50,13 @@ type GenerateSignatureResponse struct {
// GenerateEnvelopeRequest contains the parameters passed in a generate-envelope
// request.
type GenerateEnvelopeRequest struct {
ContractVersion string `json:"contractVersion"`
KeyID string `json:"keyId"`
PayloadType string `json:"payloadType"`
SignatureEnvelopeType string `json:"signatureEnvelopeType"`
Payload []byte `json:"payload"`
PluginConfig map[string]string `json:"pluginConfig,omitempty"`
ContractVersion string `json:"contractVersion"`
KeyID string `json:"keyId"`
PayloadType string `json:"payloadType"`
SignatureEnvelopeType string `json:"signatureEnvelopeType"`
Payload []byte `json:"payload"`
ExpiryDurationInSeconds uint64 `json:"expiryDurationInSeconds,omitempty"`
PluginConfig map[string]string `json:"pluginConfig,omitempty"`
}

func (GenerateEnvelopeRequest) Command() Command {
Expand Down
12 changes: 7 additions & 5 deletions signer/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"encoding/json"
"errors"
"fmt"
"time"

"github.com/notaryproject/notation-core-go/signature"
"github.com/notaryproject/notation-go"
Expand Down Expand Up @@ -98,11 +99,12 @@ func (s *pluginSigner) generateSignatureEnvelope(ctx context.Context, desc ocisp
}
// Execute plugin sign command.
req := &proto.GenerateEnvelopeRequest{
KeyID: s.keyID,
Payload: payloadBytes,
SignatureEnvelopeType: opts.SignatureMediaType,
PayloadType: envelope.MediaTypePayloadV1,
PluginConfig: s.mergeConfig(opts.PluginConfig),
KeyID: s.keyID,
Payload: payloadBytes,
SignatureEnvelopeType: opts.SignatureMediaType,
PayloadType: envelope.MediaTypePayloadV1,
ExpiryDurationInSeconds: uint64(opts.ExpiryDuration / time.Second),
PluginConfig: s.mergeConfig(opts.PluginConfig),
}
resp, err := s.plugin.GenerateEnvelope(ctx, req)
if err != nil {
Expand Down
6 changes: 3 additions & 3 deletions signer/plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,7 +181,7 @@ func TestSigner_Sign_ExpiryInValid(t *testing.T) {
signer := pluginSigner{
plugin: newMockPlugin(false, false, false, false, keyCertPairCollections[0].key, keyCertPairCollections[0].certs, ks),
}
_, _, err := signer.Sign(context.Background(), ocispec.Descriptor{}, notation.SignOptions{Expiry: time.Now().Add(-100), SignatureMediaType: envelopeType})
_, _, err := signer.Sign(context.Background(), ocispec.Descriptor{}, notation.SignOptions{ExpiryDuration: -24 * time.Hour, SignatureMediaType: envelopeType})
wantEr := "expiry cannot be equal or before the signing time"
if err == nil || !strings.Contains(err.Error(), wantEr) {
t.Errorf("Signer.Sign() error = %v, wantErr %v", err, wantEr)
Expand Down Expand Up @@ -303,8 +303,8 @@ func basicSignTest(t *testing.T, pluginSigner *pluginSigner, envelopeType string
if mockPlugin.keySpec.SignatureAlgorithm() != signerInfo.SignatureAlgorithm {
t.Fatalf("Signer.Sign() signing algorithm changed")
}
if validSignOpts.Expiry.Unix() != signerInfo.SignedAttributes.Expiry.Unix() {
t.Fatalf("Signer.Sign() expiry changed")
if validSignOpts.ExpiryDuration != signerInfo.SignedAttributes.Expiry.Sub(signerInfo.SignedAttributes.SigningTime) {
t.Fatalf("Signer.Sign() expiry duration changed")
}
if !reflect.DeepEqual(mockPlugin.certs, signerInfo.CertificateChain) {
t.Fatalf(" Signer.Sign() cert chain changed")
Expand Down
5 changes: 3 additions & 2 deletions signer/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,8 +90,9 @@ func (s *genericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts
SigningAgent: signingAgent, // TODO: include external signing plugin's name and version. https://github.com/notaryproject/notation-go/issues/80
}

if !opts.Expiry.IsZero() {
signReq.Expiry = opts.Expiry
// Add expiry only if ExpiryDuration is not zero
if opts.ExpiryDuration != 0 {
signReq.Expiry = signReq.SigningTime.Add(opts.ExpiryDuration)
}

// perform signing
Expand Down
6 changes: 2 additions & 4 deletions signer/signer_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -212,7 +212,7 @@ func TestSignWithoutExpiry(t *testing.T) {

ctx := context.Background()
desc, sOpts := generateSigningContent(nil)
sOpts.Expiry = time.Time{} // reset expiry
sOpts.ExpiryDuration = 0 // reset expiry
sOpts.SignatureMediaType = envelopeType
sig, _, err := s.Sign(ctx, desc, sOpts)
if err != nil {
Expand Down Expand Up @@ -268,9 +268,7 @@ func generateSigningContent(tsa *timestamptest.TSA) (ocispec.Descriptor, notatio
"foo": "bar",
},
}
sOpts := notation.SignOptions{
Expiry: time.Now().UTC().Add(time.Hour),
}
sOpts := notation.SignOptions{ExpiryDuration: 24 * time.Hour}
if tsa != nil {
tsaRoots := x509.NewCertPool()
tsaRoots.AddCert(tsa.Certificate())
Expand Down

0 comments on commit bc022cc

Please sign in to comment.