Skip to content
Open
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 go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@ require (
github.com/notaryproject/notation-core-go v1.0.0-rc.1
github.com/opencontainers/go-digest v1.0.0
github.com/opencontainers/image-spec v1.1.0-rc2
github.com/veraison/go-cose v1.0.0-rc.2
oras.land/oras-go/v2 v2.0.0-rc.6
github.com/veraison/go-cose v1.0.0
oras.land/oras-go/v2 v2.0.0
)

require (
Expand Down
8 changes: 4 additions & 4 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/testify v1.7.2 h1:4jaiDzPyXQvSd7D0EjG45355tLlV3VOECpq10pLC+8s=
github.com/stretchr/testify v1.7.2/go.mod h1:R6va5+xMeoiuVRoj+gSkQ7d3FALtqAAGI1FQKckRals=
github.com/veraison/go-cose v1.0.0-rc.2 h1:zH3QmP4N5kwpdGauceIT3aJm8iUyV9OqpUOb+7CF7rQ=
github.com/veraison/go-cose v1.0.0-rc.2/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4=
github.com/veraison/go-cose v1.0.0 h1:Jxirc0rl3gG7wUFgW+82tBQNeK8T8e2Bk1Vd298ob4A=
github.com/veraison/go-cose v1.0.0/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4=
github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM=
github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d h1:sK3txAijHtOK88l68nt020reeT1ZdKLIYetKl95FzVY=
Expand All @@ -39,5 +39,5 @@ golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGm
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
oras.land/oras-go/v2 v2.0.0-rc.6 h1:jGWysqm8flq+X0Vj8bZ6rkASAqTab5k18Mx9hEjFc8g=
oras.land/oras-go/v2 v2.0.0-rc.6/go.mod h1:iVExH1NxrccIxjsiq17L91WCZ4KIw6jVQyCLsZsu1gc=
oras.land/oras-go/v2 v2.0.0 h1:+LRAz92WF7AvYQsQjPEAIw3Xb2zPPhuydjpi4pIHmc0=
oras.land/oras-go/v2 v2.0.0/go.mod h1:iVExH1NxrccIxjsiq17L91WCZ4KIw6jVQyCLsZsu1gc=
18 changes: 17 additions & 1 deletion notation.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ func Verify(ctx context.Context, verifier Verifier, repo registry.Repository, re
break
}
numOfSignatureProcessed++
logger.Infof("Processing signature with digest: %v", sigManifestDesc.Digest)
logger.Infof("Processing signature with manifest mediaType: %v and digest: %v", sigManifestDesc.MediaType, sigManifestDesc.Digest)
// get signature envelope
sigBlob, sigDesc, err := repo.FetchSignatureBlob(ctx, sigManifestDesc)
if err != nil {
Expand Down Expand Up @@ -393,6 +393,7 @@ func generateAnnotations(signerInfo *signature.SignerInfo) (map[string]string, e

func (outcome *VerificationOutcome) GetUserMetadata() (map[string]string, error) {
var payload envelope.Payload

err := json.Unmarshal(outcome.EnvelopeContent.Payload.Content, &payload)
if err != nil {
return nil, errors.New("Failed to unmarshal the payload content in the signature blob to envelope.Payload")
Expand All @@ -404,3 +405,18 @@ func (outcome *VerificationOutcome) GetUserMetadata() (map[string]string, error)

return payload.TargetArtifact.Annotations, nil
}

func GetDescriptorFromPayload(payload *signature.Payload) (*ocispec.Descriptor, error) {
if payload == nil {
return nil, errors.New("Empty payload")
}

var parsedPayload envelope.Payload

err := json.Unmarshal(payload.Content, &parsedPayload)
if err != nil {
return nil, errors.New("Failed to unmarshall the payload content to envelope.Payload")
}

return &parsedPayload.TargetArtifact, nil
}
81 changes: 59 additions & 22 deletions registry/repository.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,24 @@ const (
maxManifestSizeLimit = 4 * 1024 * 1024 // 4 MiB
)

// RepositoryOptions provides user options when creating a Repository
type RepositoryOptions struct {
// OCIImageManifest specifies if user wants to use OCI image manifest
// to store signatures in remote registries.
// By default, Notation will use OCI artifact manifest to store signatures.
// If OCIImageManifest flag is set to true, Notation will instead use
// OCI image manifest.
// Note, Notation will not automatically convert between these two types
// on any occasion.
// OCI artifact manifest: https://github.com/opencontainers/image-spec/blob/v1.1.0-rc2/artifact.md
// OCI image manifest: https://github.com/opencontainers/image-spec/blob/v1.1.0-rc2/manifest.md
OCIImageManifest bool
}

// repositoryClient implements Repository
type repositoryClient struct {
registry.Repository
RepositoryOptions
}

// NewRepository returns a new Repository
Expand All @@ -28,6 +43,15 @@ func NewRepository(repo registry.Repository) Repository {
}
}

// NewRepositoryWithOptions returns a new Repository with user specified
// options.
func NewRepositoryWithOptions(repo registry.Repository, opts RepositoryOptions) Repository {
return &repositoryClient{
Repository: repo,
RepositoryOptions: opts,
}
}

// Resolve resolves a reference(tag or digest) to a manifest descriptor
func (c *repositoryClient) Resolve(ctx context.Context, reference string) (ocispec.Descriptor, error) {
return c.Repository.Manifests().Resolve(ctx, reference)
Expand All @@ -42,22 +66,18 @@ func (c *repositoryClient) ListSignatures(ctx context.Context, desc ocispec.Desc
// FetchSignatureBlob returns signature envelope blob and descriptor given
// signature manifest descriptor
func (c *repositoryClient) FetchSignatureBlob(ctx context.Context, desc ocispec.Descriptor) ([]byte, ocispec.Descriptor, error) {
sigManifest, err := c.getSignatureManifest(ctx, desc)
sigBlobDesc, err := c.getSignatureBlobDesc(ctx, desc)
if err != nil {
return nil, ocispec.Descriptor{}, err
}
if len(sigManifest.Blobs) != 1 {
return nil, ocispec.Descriptor{}, fmt.Errorf("signature manifest requries exactly one signature envelope blob, got %d", len(sigManifest.Blobs))
if sigBlobDesc.Size > maxBlobSizeLimit {
return nil, ocispec.Descriptor{}, fmt.Errorf("signature blob too large: %d bytes", sigBlobDesc.Size)
}
sigDesc := sigManifest.Blobs[0]
if sigDesc.Size > maxBlobSizeLimit {
return nil, ocispec.Descriptor{}, fmt.Errorf("signature blob too large: %d bytes", sigDesc.Size)
}
sigBlob, err := content.FetchAll(ctx, c.Repository.Blobs(), sigDesc)
sigBlob, err := content.FetchAll(ctx, c.Repository.Blobs(), sigBlobDesc)
if err != nil {
return nil, ocispec.Descriptor{}, err
}
return sigBlob, sigDesc, nil
return sigBlob, sigBlobDesc, nil
}

// PushSignature creates and uploads an signature manifest along with its
Expand All @@ -77,34 +97,51 @@ func (c *repositoryClient) PushSignature(ctx context.Context, mediaType string,
return blobDesc, manifestDesc, nil
}

// getSignatureManifest returns signature manifest given signature manifest
// descriptor
func (c *repositoryClient) getSignatureManifest(ctx context.Context, sigManifestDesc ocispec.Descriptor) (*ocispec.Artifact, error) {
if sigManifestDesc.MediaType != ocispec.MediaTypeArtifactManifest {
return nil, fmt.Errorf("sigManifestDesc.MediaType requires %q, got %q", ocispec.MediaTypeArtifactManifest, sigManifestDesc.MediaType)
// getSignatureBlobDesc returns signature blob descriptor from
// signature manifest blobs or layers given signature manifest descriptor
func (c *repositoryClient) getSignatureBlobDesc(ctx context.Context, sigManifestDesc ocispec.Descriptor) (ocispec.Descriptor, error) {
if sigManifestDesc.MediaType != ocispec.MediaTypeArtifactManifest && sigManifestDesc.MediaType != ocispec.MediaTypeImageManifest {
return ocispec.Descriptor{}, fmt.Errorf("sigManifestDesc.MediaType requires %q or %q, got %q", ocispec.MediaTypeArtifactManifest, ocispec.MediaTypeImageManifest, sigManifestDesc.MediaType)
}
if sigManifestDesc.Size > maxManifestSizeLimit {
return nil, fmt.Errorf("manifest too large: %d bytes", sigManifestDesc.Size)
return ocispec.Descriptor{}, fmt.Errorf("signature manifest too large: %d bytes", sigManifestDesc.Size)
}
manifestJSON, err := content.FetchAll(ctx, c.Repository.Manifests(), sigManifestDesc)
if err != nil {
return nil, err
return ocispec.Descriptor{}, err
}

var sigManifest ocispec.Artifact
err = json.Unmarshal(manifestJSON, &sigManifest)
if err != nil {
return nil, err
var signatureBlobs []ocispec.Descriptor

// OCI image manifest
if sigManifestDesc.MediaType == ocispec.MediaTypeImageManifest {
var sigManifest ocispec.Manifest
if err := json.Unmarshal(manifestJSON, &sigManifest); err != nil {
return ocispec.Descriptor{}, err
}
signatureBlobs = sigManifest.Layers
} else { // OCI artifact manifest
var sigManifest ocispec.Artifact
if err := json.Unmarshal(manifestJSON, &sigManifest); err != nil {
return ocispec.Descriptor{}, err
}
signatureBlobs = sigManifest.Blobs
}
return &sigManifest, nil

if len(signatureBlobs) != 1 {
return ocispec.Descriptor{}, fmt.Errorf("signature manifest requries exactly one signature envelope blob, got %d", len(signatureBlobs))
}

return signatureBlobs[0], nil
}

// uploadSignatureManifest uploads the signature manifest to the registry
func (c *repositoryClient) uploadSignatureManifest(ctx context.Context, subject, blobDesc ocispec.Descriptor, annotations map[string]string) (ocispec.Descriptor, error) {
opts := oras.PackOptions{
Subject: &subject,
ManifestAnnotations: annotations,
PackImageManifest: c.OCIImageManifest,
}

return oras.Pack(ctx, c.Repository.Manifests(), ArtifactTypeNotation, []ocispec.Descriptor{blobDesc}, opts)
return oras.Pack(ctx, c.Repository, ArtifactTypeNotation, []ocispec.Descriptor{blobDesc}, opts)
}
Loading