From 41de3ab01cedef96c04bc2c7973dacca4d629577 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 9 Aug 2024 09:38:45 +0800 Subject: [PATCH 01/11] removed blob sign/verify Signed-off-by: Patrick Zheng --- example_signBlob_test.go | 85 ------ example_verifyBlob_test.go | 151 ----------- notation.go | 155 ----------- notation_test.go | 179 +------------ signer/plugin.go | 40 --- signer/plugin_test.go | 27 -- signer/signer.go | 27 -- signer/signer_test.go | 25 -- verifier/helpers_test.go | 14 - verifier/trustpolicy/blob.go | 151 ----------- verifier/trustpolicy/blob_test.go | 168 ------------ verifier/trustpolicy/trustpolicy_test.go | 20 -- verifier/verifier.go | 157 ++--------- verifier/verifier_test.go | 325 ++++++----------------- 14 files changed, 105 insertions(+), 1419 deletions(-) delete mode 100644 example_signBlob_test.go delete mode 100644 example_verifyBlob_test.go delete mode 100644 verifier/trustpolicy/blob.go delete mode 100644 verifier/trustpolicy/blob_test.go diff --git a/example_signBlob_test.go b/example_signBlob_test.go deleted file mode 100644 index cab78ca5..00000000 --- a/example_signBlob_test.go +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright The Notary Project Authors. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package notation_test - -import ( - "context" - "fmt" - "strings" - - "github.com/notaryproject/notation-core-go/signature" - "github.com/notaryproject/notation-core-go/signature/jws" - "github.com/notaryproject/notation-go" - "github.com/notaryproject/notation-go/signer" -) - -// ExampleSignBlob demonstrates how to use signer.BlobSign to sign arbitrary data. -func Example_signBlob() { - //exampleSigner implements notation.Signer and notation.BlobSigner. Given key and X509 certificate chain, - // it provides method to sign OCI artifacts or blobs. - // Users should replace `exampleCertTuple.PrivateKey` with their own private - // key and replace `exampleCerts` with the corresponding 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) - if err != nil { - panic(err) // Handle error - } - - // Both COSE ("application/cose") and JWS ("application/jose+json") - // signature mediaTypes are supported. - exampleSignatureMediaType := jws.MediaTypeEnvelope - exampleContentMediaType := "video/mp4" - - // exampleSignOptions is an example of notation.SignBlobOptions. - exampleSignOptions := notation.SignBlobOptions{ - SignerSignOptions: notation.SignerSignOptions{ - SignatureMediaType: exampleSignatureMediaType, - SigningAgent: "example signing agent", - }, - ContentMediaType: exampleContentMediaType, - UserMetadata: map[string]string{"buildId": "101"}, - } - - // exampleReader reads the data that needs to be signed. This data can be in a file or in memory. - exampleReader := strings.NewReader("example blob") - - // Upon successful signing, signature envelope and signerInfo are returned. - // signatureEnvelope can be used in a verification process later on. - signatureEnvelope, signerInfo, err := notation.SignBlob(context.Background(), exampleSigner, exampleReader, exampleSignOptions) - if err != nil { - panic(err) // Handle error - } - - fmt.Println("Successfully signed") - - // a peek of the signature envelope generated - sigBlob, err := signature.ParseEnvelope(exampleSignatureMediaType, signatureEnvelope) - if err != nil { - panic(err) // Handle error - } - sigContent, err := sigBlob.Content() - if err != nil { - panic(err) // Handle error - } - fmt.Println("signature Payload ContentType:", sigContent.Payload.ContentType) - fmt.Println("signature Payload Content:", string(sigContent.Payload.Content)) - fmt.Println("signerInfo SigningAgent:", signerInfo.UnsignedAttributes.SigningAgent) - - // Output: - // Successfully signed - // signature Payload ContentType: application/vnd.cncf.notary.payload.v1+json - // signature Payload Content: {"targetArtifact":{"annotations":{"buildId":"101"},"digest":"sha384:b8ab24dafba5cf7e4c89c562f811cf10493d4203da982d3b1345f366ca863d9c2ed323dbd0fb7ff83a80302ceffa5a61","mediaType":"video/mp4","size":12}} - // signerInfo SigningAgent: example signing agent -} diff --git a/example_verifyBlob_test.go b/example_verifyBlob_test.go deleted file mode 100644 index ce9d94de..00000000 --- a/example_verifyBlob_test.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright The Notary Project Authors. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package notation_test - -import ( - "context" - "fmt" - "os" - "strings" - - "github.com/notaryproject/notation-core-go/signature/jws" - "github.com/notaryproject/notation-go" - "github.com/notaryproject/notation-go/dir" - "github.com/notaryproject/notation-go/verifier" - "github.com/notaryproject/notation-go/verifier/trustpolicy" - "github.com/notaryproject/notation-go/verifier/truststore" -) - -// examplePolicyDocument is an example of a valid trust policy document. -// trust policy document should follow this spec: -// https://github.com/notaryproject/notaryproject/blob/v1.1.0/specs/trust-store-trust-policy.md#trust-policy -var exampleBlobPolicyDocument = trustpolicy.BlobDocument{ - Version: "1.0", - TrustPolicies: []trustpolicy.BlobTrustPolicy{ - { - Name: "test-statement-name", - SignatureVerification: trustpolicy.SignatureVerification{VerificationLevel: trustpolicy.LevelStrict.Name, Override: map[trustpolicy.ValidationType]trustpolicy.ValidationAction{trustpolicy.TypeRevocation: trustpolicy.ActionSkip}}, - TrustStores: []string{"ca:valid-trust-store"}, - TrustedIdentities: []string{"*"}, - }, - }, -} - -// ExampleVerifyBlob demonstrates how to use verifier.Verify to verify a -// signature of the blob. -func Example_verifyBlob() { - // Both COSE ("application/cose") and JWS ("application/jose+json") - // signature mediaTypes are supported. - exampleSignatureMediaType := jws.MediaTypeEnvelope - - // exampleSignatureEnvelope is a valid signature envelope. - exampleSignatureEnvelope := getSignatureEnvelope() - - // createTrustStoreForBlobVerify creates a trust store directory for demo purpose. - // Users could use the default trust store from Notary and add trusted - // certificates into it following the trust store spec: - // https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-store - if err := createTrustStoreForBlobVerify(); err != nil { - panic(err) // Handle error - } - - // exampleVerifier implements notation.Verify and notation.VerifyBlob. - exampleVerifier, err := verifier.NewVerifier(nil, &exampleBlobPolicyDocument, truststore.NewX509TrustStore(dir.ConfigFS()), nil) - if err != nil { - panic(err) // Handle error - } - - // exampleReader reads the data that needs to be verified. This data can be in a file or in memory. - exampleReader := strings.NewReader("example blob") - - // exampleVerifyOptions is an example of notation.VerifierVerifyOptions - exampleVerifyOptions := notation.VerifyBlobOptions{ - BlobVerifierVerifyOptions: notation.BlobVerifierVerifyOptions{ - SignatureMediaType: exampleSignatureMediaType, - TrustPolicyName: "test-statement-name", - }, - } - - // upon successful verification, the signature verification outcome is - // returned. - _, outcome, err := notation.VerifyBlob(context.Background(), exampleVerifier, exampleReader, []byte(exampleSignatureEnvelope), exampleVerifyOptions) - if err != nil { - panic(err) // Handle error - } - - fmt.Println("Successfully verified") - - // a peek of the payload inside the signature envelope - fmt.Println("payload ContentType:", outcome.EnvelopeContent.Payload.ContentType) - - // Note, upon successful verification, payload.TargetArtifact from the - // signature envelope matches exactly with our exampleTargetDescriptor. - // (This check has been done for the user inside verifier.Verify.) - fmt.Println("payload Content:", string(outcome.EnvelopeContent.Payload.Content)) - - // Output: - // Successfully verified - // payload ContentType: application/vnd.cncf.notary.payload.v1+json - // payload Content: {"targetArtifact":{"digest":"sha384:b8ab24dafba5cf7e4c89c562f811cf10493d4203da982d3b1345f366ca863d9c2ed323dbd0fb7ff83a80302ceffa5a61","mediaType":"video/mp4","size":12}} -} - -func createTrustStoreForBlobVerify() error { - // changing the path of the trust store for demo purpose. - // Users could keep the default value, i.e. os.UserConfigDir. - dir.UserConfigDir = "tmp" - - // an example of a valid X509 self-signed certificate for demo purpose ONLY. - // (This self-signed cert is paired with the private key used to - // generate the `exampleSignatureEnvelopePem` above.) - // Users should replace `exampleX509Certificate` with their own trusted - // certificate and add to the trust store, following the - // Notary certificate requirements: - // https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/signature-specification.md#certificate-requirements - exampleX509Certificate := `-----BEGIN CERTIFICATE----- -MIIEbDCCAtSgAwIBAgIBUzANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJVUzEL -MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEl -MCMGA1UEAxMcTm90YXRpb24gRXhhbXBsZSBzZWxmLXNpZ25lZDAgFw0yNDA0MDQy -MTIwMjBaGA8yMTI0MDQwNDIxMjAyMFowZDELMAkGA1UEBhMCVVMxCzAJBgNVBAgT -AldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3RhcnkxJTAjBgNVBAMT -HE5vdGF0aW9uIEV4YW1wbGUgc2VsZi1zaWduZWQwggGiMA0GCSqGSIb3DQEBAQUA -A4IBjwAwggGKAoIBgQDGIiN4yCjSVqFELZwxK/BMb8BokP587L8oPrZ1g8H7LudB -moLNDT7vF9xccbCfU3yNuOd0WaOgnENiCs81VHidyJsj1Oz3u+0Zn3ng7V+uZr6m -AIO74efA9ClMiY4i4HIt8IAZF57AL2mzDnCITgSWxikf030Il85MI42STvA+qYuz -ZEOp3XvKo8bDgQFvbtgK0HYYMfrka7VDmIWVo0rBMGm5btI8HOYQ0r9aqsrCxLAv -1AQeOQm+wbRcp4R5PIUJr+REGn7JCbOyXg/7qqHXKKmvV5yrGaraw8gZ5pqP/RHK -XUJIfvD0Vf2epJmsvC+6vXkSWtz+cA8J4GQx4J4SXL57hoYkC5qv39SOLzlWls3I -6fgeO+SZ0sceMd8NKlom/L5eOJBfB3bTQB83hq/3bRtjT7/qCMsL3VcndKkS+vGF -JPw5uTH+pmBgHrLr6tRoRRjwRFuZ0dO05AbdjCaxgVDtFI3wNbaXn/1VlRGySQIS -UNWxCrUsSzndeqwmjqsCAwEAAaMnMCUwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQM -MAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBgQBdi0SaJAaeKBB0I+Fjcbmc -4zRvHE4GDSMSDnAK97nrZCZ9iwKuY4x6mv9lwQe2P3VXROoL9JmONNf0yaObOwQj -ILGnbe2rzYtUardz2gzh+6KNzJHspRvk1f06mp4496XQ3STMRSr8kno1svKQMy0Y -FRsGMKs4fWHavIAqNXg9ymrZvvXiatN2UiVtAA/jBFScZAWskeb2WHNzORi7H5Z1 -mp5+IlNYQpzdIu/dvLVxzhh2UvkRdsQqsMgt/MOU84RncwUNZM4yI5EGPoaSJdsj -AGNd+UV6ur7QmVI2Q9EZNRlaDJtaoZmKns5j1SlmDXWKbdRmw42ORDudODj/pHA9 -+u+ca9t3uLsbqO9yPm8m+6fyxffWS11QAH6O7EjydJWcEe5tYkPpL6kcaEyQKESm -5CDlsk+W3ElpaUu6tsnGKODvgdAN3m0noC+qxzCMqoCM4+M5V6OptR98MDl2FK0B -5+WF6YHBxf/uqDvFktUczjrIWuyfECywp05bpGAErGE= ------END CERTIFICATE-----` - - // Adding the certificate into the trust store. - if err := os.MkdirAll("tmp/truststore/x509/ca/valid-trust-store", 0700); err != nil { - return err - } - return os.WriteFile("tmp/truststore/x509/ca/valid-trust-store/NotationBlobExample.pem", []byte(exampleX509Certificate), 0600) -} - -func getSignatureEnvelope() string { - return `{"payload":"eyJ0YXJnZXRBcnRpZmFjdCI6eyJkaWdlc3QiOiJzaGEzODQ6YjhhYjI0ZGFmYmE1Y2Y3ZTRjODljNTYyZjgxMWNmMTA0OTNkNDIwM2RhOTgyZDNiMTM0NWYzNjZjYTg2M2Q5YzJlZDMyM2RiZDBmYjdmZjgzYTgwMzAyY2VmZmE1YTYxIiwibWVkaWFUeXBlIjoidmlkZW8vbXA0Iiwic2l6ZSI6MTJ9fQ","protected":"eyJhbGciOiJQUzM4NCIsImNyaXQiOlsiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSJdLCJjdHkiOiJhcHBsaWNhdGlvbi92bmQuY25jZi5ub3RhcnkucGF5bG9hZC52MStqc29uIiwiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSI6Im5vdGFyeS54NTA5IiwiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1RpbWUiOiIyMDI0LTA0LTA0VDE0OjIwOjIxLTA3OjAwIn0","header":{"x5c":["MIIEbDCCAtSgAwIBAgIBUzANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTElMCMGA1UEAxMcTm90YXRpb24gRXhhbXBsZSBzZWxmLXNpZ25lZDAgFw0yNDA0MDQyMTIwMjBaGA8yMTI0MDQwNDIxMjAyMFowZDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3RhcnkxJTAjBgNVBAMTHE5vdGF0aW9uIEV4YW1wbGUgc2VsZi1zaWduZWQwggGiMA0GCSqGSIb3DQEBAQUAA4IBjwAwggGKAoIBgQDGIiN4yCjSVqFELZwxK/BMb8BokP587L8oPrZ1g8H7LudBmoLNDT7vF9xccbCfU3yNuOd0WaOgnENiCs81VHidyJsj1Oz3u+0Zn3ng7V+uZr6mAIO74efA9ClMiY4i4HIt8IAZF57AL2mzDnCITgSWxikf030Il85MI42STvA+qYuzZEOp3XvKo8bDgQFvbtgK0HYYMfrka7VDmIWVo0rBMGm5btI8HOYQ0r9aqsrCxLAv1AQeOQm+wbRcp4R5PIUJr+REGn7JCbOyXg/7qqHXKKmvV5yrGaraw8gZ5pqP/RHKXUJIfvD0Vf2epJmsvC+6vXkSWtz+cA8J4GQx4J4SXL57hoYkC5qv39SOLzlWls3I6fgeO+SZ0sceMd8NKlom/L5eOJBfB3bTQB83hq/3bRtjT7/qCMsL3VcndKkS+vGFJPw5uTH+pmBgHrLr6tRoRRjwRFuZ0dO05AbdjCaxgVDtFI3wNbaXn/1VlRGySQISUNWxCrUsSzndeqwmjqsCAwEAAaMnMCUwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBgQBdi0SaJAaeKBB0I+Fjcbmc4zRvHE4GDSMSDnAK97nrZCZ9iwKuY4x6mv9lwQe2P3VXROoL9JmONNf0yaObOwQjILGnbe2rzYtUardz2gzh+6KNzJHspRvk1f06mp4496XQ3STMRSr8kno1svKQMy0YFRsGMKs4fWHavIAqNXg9ymrZvvXiatN2UiVtAA/jBFScZAWskeb2WHNzORi7H5Z1mp5+IlNYQpzdIu/dvLVxzhh2UvkRdsQqsMgt/MOU84RncwUNZM4yI5EGPoaSJdsjAGNd+UV6ur7QmVI2Q9EZNRlaDJtaoZmKns5j1SlmDXWKbdRmw42ORDudODj/pHA9+u+ca9t3uLsbqO9yPm8m+6fyxffWS11QAH6O7EjydJWcEe5tYkPpL6kcaEyQKESm5CDlsk+W3ElpaUu6tsnGKODvgdAN3m0noC+qxzCMqoCM4+M5V6OptR98MDl2FK0B5+WF6YHBxf/uqDvFktUczjrIWuyfECywp05bpGAErGE="],"io.cncf.notary.signingAgent":"example signing agent"},"signature":"liOjdgQ9BKuQTZGXRh3o6P8AMUIq_MKQReEcqA5h8M4RYs3DV_wXfaLCr2x_NRcwjTZsoO1_J77hmzkkk4L0IuFP8Qw0KKtmc83G0yFi4yYV5fwzrIbnhC2GRLuqLPnK-C4qYmv52ld3ebvo7XWwRHu30-VXePmTRFp6iG-eSAgkNgwhxSZ0ZmTFLG3ceNiX2bxpLHlXdPwA3aFKbd6nKrzo4CZ1ZyLNmAIaoA5-kmc0Hyt45trpxaaiWusI_pcTLw71YCqEAs32tEq3q6hRAgAZZN-Qvm9GyNp9EuaPiKjMbJFqtjome5ITxyNd-5t09dDCUgSe3t-iqv2Blm4E080AP1TYwUKLYklGniUP1dAtOau5G2juZLpl7tr4LQ99mycflnAmV7e79eEWXffvy5EAl77dW4_vM7lEemm08m2wddGuDOWXYb1j1r2_a5Xb92umHq6ZMhAp200A0pUkm9640x8z5jdudi_7KeezdqUK7ZMmSxHohiylyKD_20Cy"}` -} diff --git a/notation.go b/notation.go index fcad813c..d64fd2cf 100644 --- a/notation.go +++ b/notation.go @@ -23,8 +23,6 @@ import ( "encoding/json" "errors" "fmt" - "io" - "mime" "strings" "time" @@ -80,35 +78,6 @@ type Signer interface { 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. -// Below is the example of minimal descriptor, it must contain mediatype, digest and size of the artifact -// -// { -// "mediaType": "application/octet-stream", -// "digest": "sha256:2f3a23b6373afb134ddcd864be8e037e34a662d090d33ee849471ff73c873345", -// "size": 1024 -// } -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 @@ -194,29 +163,6 @@ func Sign(ctx context.Context, signer Signer, repo registry.Repository, signOpts 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 := validateContentMediaType(signBlobOpts.ContentMediaType); err != nil { - return nil, nil, 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") @@ -348,33 +294,6 @@ type Verifier interface { Verify(ctx context.Context, desc ocispec.Descriptor, signature []byte, opts VerifierVerifyOptions) (*VerificationOutcome, error) } -// BlobVerifierVerifyOptions contains parameters for BlobVerifier.Verify. -type BlobVerifierVerifyOptions struct { - // SignatureMediaType is the envelope type of the signature. - // Currently only `application/jose+json` and `application/cose` are - // supported. - SignatureMediaType string - - // PluginConfig is a map of plugin configs. - PluginConfig map[string]string - - // UserMetadata contains key-value pairs that must be present in the - // signature. - UserMetadata map[string]string - - // TrustPolicyName is the name of trust policy picked by caller. - // If empty, the global trust policy will be applied. - TrustPolicyName string -} - -// BlobVerifier is a generic interface for verifying a blob. -type BlobVerifier interface { - // VerifyBlob verifies the `signature` against the target artifact using the - // descriptor returned by descGenFunc parameter and - // returns the outcome upon successful verification. - VerifyBlob(ctx context.Context, descGenFunc BlobDescriptorGenerator, signature []byte, opts BlobVerifierVerifyOptions) (*VerificationOutcome, error) -} - type verifySkipper interface { // SkipVerify validates whether the verification level is skip. SkipVerify(ctx context.Context, opts VerifierVerifyOptions) (bool, *trustpolicy.VerificationLevel, error) @@ -399,55 +318,6 @@ type VerifyOptions struct { UserMetadata map[string]string } -// VerifyBlobOptions contains parameters for notation.VerifyBlob. -type VerifyBlobOptions struct { - BlobVerifierVerifyOptions - - // ContentMediaType is the media-type type of the content being verified. - ContentMediaType string -} - -// VerifyBlob performs signature verification for a blob using notation supported -// verification types (like integrity, authenticity, etc.) and return the -// successful signature verification outcome. The blob is read using blobReader and -// upon successful verification, it returns the descriptor of the blob. -// For more details on signature verification, see -// https://github.com/notaryproject/notaryproject/blob/main/specs/trust-store-trust-policy.md#signature-verification -func VerifyBlob(ctx context.Context, blobVerifier BlobVerifier, blobReader io.Reader, signature []byte, verifyBlobOpts VerifyBlobOptions) (ocispec.Descriptor, *VerificationOutcome, error) { - if blobVerifier == nil { - return ocispec.Descriptor{}, nil, errors.New("blobVerifier cannot be nil") - } - - if blobReader == nil { - return ocispec.Descriptor{}, nil, errors.New("blobReader cannot be nil") - } - - if len(signature) == 0 { - return ocispec.Descriptor{}, nil, errors.New("signature cannot be nil or empty") - } - - if err := validateContentMediaType(verifyBlobOpts.ContentMediaType); err != nil { - return ocispec.Descriptor{}, nil, err - } - - if err := validateSigMediaType(verifyBlobOpts.SignatureMediaType); err != nil { - return ocispec.Descriptor{}, nil, err - } - - getDescFunc := getDescriptorFunc(ctx, blobReader, verifyBlobOpts.ContentMediaType, verifyBlobOpts.UserMetadata) - vo, err := blobVerifier.VerifyBlob(ctx, getDescFunc, signature, verifyBlobOpts.BlobVerifierVerifyOptions) - if err != nil { - return ocispec.Descriptor{}, nil, err - } - - var desc ocispec.Descriptor - if err = json.Unmarshal(vo.EnvelopeContent.Payload.Content, &desc); err != nil { - return ocispec.Descriptor{}, nil, err - } - - return desc, vo, nil -} - // Verify performs signature verification on each of the notation supported // verification types (like integrity, authenticity, etc.) and return the // successful signature verification outcome. @@ -611,31 +481,6 @@ func generateAnnotations(signerInfo *signature.SignerInfo, annotations map[strin 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) - } -} - -func validateContentMediaType(contentMediaType string) error { - if contentMediaType != "" { - if _, _, err := mime.ParseMediaType(contentMediaType); err != nil { - return fmt.Errorf("invalid content media-type %q: %v", contentMediaType, err) - } - } - return nil -} - func validateSigMediaType(sigMediaType string) error { if !(sigMediaType == jws.MediaTypeEnvelope || sigMediaType == cose.MediaTypeEnvelope) { return fmt.Errorf("invalid signature media-type %q", sigMediaType) diff --git a/notation_test.go b/notation_test.go index 51840959..6e31a31d 100644 --- a/notation_test.go +++ b/notation_test.go @@ -18,11 +18,9 @@ import ( "encoding/json" "errors" "fmt" - "io" "math" "os" "path/filepath" - "strings" "testing" "time" @@ -37,7 +35,6 @@ import ( "github.com/notaryproject/notation-go/plugin" "github.com/notaryproject/notation-go/registry" "github.com/notaryproject/notation-go/verifier/trustpolicy" - "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -68,85 +65,6 @@ func TestSignSuccess(t *testing.T) { } } -func TestSignBlobSuccess(t *testing.T) { - reader := strings.NewReader("some content") - testCases := []struct { - name string - dur time.Duration - mtype string - agent string - pConfig map[string]string - metadata map[string]string - }{ - {"expiryInHours", 24 * time.Hour, "video/mp4", "", nil, nil}, - {"oneSecondExpiry", 1 * time.Second, "video/mp4", "", nil, nil}, - {"zeroExpiry", 0, "video/mp4", "", nil, nil}, - {"validContentType", 1 * time.Second, "video/mp4", "", nil, nil}, - {"emptyContentType", 1 * time.Second, "video/mp4", "someDummyAgent", map[string]string{"hi": "hello"}, map[string]string{"bye": "tata"}}, - } - for _, tc := range testCases { - t.Run(tc.name, func(b *testing.T) { - opts := SignBlobOptions{ - SignerSignOptions: SignerSignOptions{ - SignatureMediaType: jws.MediaTypeEnvelope, - ExpiryDuration: tc.dur, - PluginConfig: tc.pConfig, - SigningAgent: tc.agent, - }, - UserMetadata: expectedMetadata, - ContentMediaType: tc.mtype, - } - - _, _, err := SignBlob(context.Background(), &dummySigner{}, reader, opts) - if err != nil { - b.Fatalf("Sign failed with error: %v", err) - } - }) - } -} - -func TestSignBlobError(t *testing.T) { - reader := strings.NewReader("some content") - testCases := []struct { - name string - signer BlobSigner - dur time.Duration - rdr io.Reader - sigMType string - ctMType string - errMsg string - }{ - {"negativeExpiry", &dummySigner{}, -1 * time.Second, nil, "video/mp4", jws.MediaTypeEnvelope, "expiry duration cannot be a negative value"}, - {"milliSecExpiry", &dummySigner{}, 1 * time.Millisecond, nil, "video/mp4", jws.MediaTypeEnvelope, "expiry duration supports minimum granularity of seconds"}, - {"invalidContentMediaType", &dummySigner{}, 1 * time.Second, reader, "video/mp4/zoping", jws.MediaTypeEnvelope, "invalid content media-type \"video/mp4/zoping\": mime: unexpected content after media subtype"}, - {"emptyContentMediaType", &dummySigner{}, 1 * time.Second, reader, "", jws.MediaTypeEnvelope, "content media-type cannot be empty"}, - {"invalidSignatureMediaType", &dummySigner{}, 1 * time.Second, reader, "", "", "content media-type cannot be empty"}, - {"nilReader", &dummySigner{}, 1 * time.Second, nil, "video/mp4", jws.MediaTypeEnvelope, "blobReader cannot be nil"}, - {"nilSigner", nil, 1 * time.Second, reader, "video/mp4", jws.MediaTypeEnvelope, "signer cannot be nil"}, - {"signerError", &dummySigner{fail: true}, 1 * time.Second, reader, "video/mp4", jws.MediaTypeEnvelope, "expected SignBlob failure"}, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - opts := SignBlobOptions{ - SignerSignOptions: SignerSignOptions{ - SignatureMediaType: jws.MediaTypeEnvelope, - ExpiryDuration: tc.dur, - PluginConfig: nil, - }, - ContentMediaType: tc.sigMType, - } - - _, _, err := SignBlob(context.Background(), tc.signer, tc.rdr, opts) - if err == nil { - t.Fatalf("expected error but didnt found") - } - if err.Error() != tc.errMsg { - t.Fatalf("expected err message to be '%s' but found '%s'", tc.errMsg, err.Error()) - } - }) - } -} - func TestSignSuccessWithUserMetadata(t *testing.T) { repo := mock.NewRepository() opts := SignOptions{} @@ -309,7 +227,6 @@ func TestRegistryResolveError(t *testing.T) { policyDocument := dummyPolicyDocument() verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict} - errorMessage := "network error" expectedErr := ErrorSignatureRetrievalFailed{Msg: errorMessage} @@ -328,7 +245,6 @@ func TestVerifyEmptyReference(t *testing.T) { policyDocument := dummyPolicyDocument() verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict} - errorMessage := "reference is missing digest or tag" expectedErr := ErrorSignatureRetrievalFailed{Msg: errorMessage} @@ -529,63 +445,6 @@ func TestVerifyFailed(t *testing.T) { }) } -func TestVerifyBlobError(t *testing.T) { - reader := strings.NewReader("some content") - sig := []byte("signature") - testCases := []struct { - name string - verifier BlobVerifier - sig []byte - rdr io.Reader - ctMType string - sigMType string - errMsg string - }{ - {"nilVerifier", nil, sig, reader, "video/mp4", jws.MediaTypeEnvelope, "blobVerifier cannot be nil"}, - {"verifierError", &dummyVerifier{FailVerify: true}, sig, reader, "video/mp4", jws.MediaTypeEnvelope, "failed verify"}, - {"nilSignature", &dummyVerifier{}, nil, reader, "video/mp4", jws.MediaTypeEnvelope, "signature cannot be nil or empty"}, - {"emptySignature", &dummyVerifier{}, []byte{}, reader, "video/mp4", jws.MediaTypeEnvelope, "signature cannot be nil or empty"}, - {"nilReader", &dummyVerifier{}, sig, nil, "video/mp4", jws.MediaTypeEnvelope, "blobReader cannot be nil"}, - {"invalidContentType", &dummyVerifier{}, sig, reader, "video/mp4/zoping", jws.MediaTypeEnvelope, "invalid content media-type \"video/mp4/zoping\": mime: unexpected content after media subtype"}, - {"invalidSigType", &dummyVerifier{}, sig, reader, "video/mp4", "hola!", "invalid signature media-type \"hola!\""}, - } - for _, tc := range testCases { - t.Run(tc.name, func(t *testing.T) { - opts := VerifyBlobOptions{ - BlobVerifierVerifyOptions: BlobVerifierVerifyOptions{ - SignatureMediaType: tc.sigMType, - UserMetadata: nil, - TrustPolicyName: "", - }, - ContentMediaType: tc.ctMType, - } - - _, _, err := VerifyBlob(context.Background(), tc.verifier, tc.rdr, tc.sig, opts) - if err == nil { - t.Fatalf("expected error but didnt found") - } - if err.Error() != tc.errMsg { - t.Fatalf("expected err message to be '%s' but found '%s'", tc.errMsg, err.Error()) - } - }) - } -} - -func TestVerifyBlobValid(t *testing.T) { - opts := VerifyBlobOptions{ - BlobVerifierVerifyOptions: BlobVerifierVerifyOptions{ - SignatureMediaType: jws.MediaTypeEnvelope, - UserMetadata: nil, - TrustPolicyName: "", - }, - } - - _, _, err := VerifyBlob(context.Background(), &dummyVerifier{}, strings.NewReader("some content"), []byte("signature"), opts) - if err != nil { - t.Fatalf("SignaureMediaTypeMismatch expected: %v got: %v", nil, err) - } -} - func dummyPolicyDocument() (policyDoc trustpolicy.Document) { policyDoc = trustpolicy.Document{ Version: "1.0", @@ -605,10 +464,7 @@ func dummyPolicyStatement() (policyStatement trustpolicy.TrustPolicy) { return } - -type dummySigner struct { - fail bool -} +type dummySigner struct{} func (s *dummySigner) Sign(_ context.Context, _ ocispec.Descriptor, _ SignerSignOptions) ([]byte, *signature.SignerInfo, error) { return []byte("ABC"), &signature.SignerInfo{ @@ -618,23 +474,6 @@ func (s *dummySigner) Sign(_ context.Context, _ ocispec.Descriptor, _ SignerSign }, nil } -func (s *dummySigner) SignBlob(_ context.Context, descGenFunc BlobDescriptorGenerator, _ SignerSignOptions) ([]byte, *signature.SignerInfo, error) { - if s.fail { - return nil, nil, errors.New("expected SignBlob failure") - } - - _, err := descGenFunc(digest.SHA384) - if err != nil { - return nil, nil, err - } - - return []byte("ABC"), &signature.SignerInfo{ - SignedAttributes: signature.SignedAttributes{ - SigningTime: time.Now(), - }, - }, nil -} - type verifyMetadataSigner struct{} func (s *verifyMetadataSigner) Sign(_ context.Context, desc ocispec.Descriptor, _ SignerSignOptions) ([]byte, *signature.SignerInfo, error) { @@ -668,22 +507,6 @@ func (v *dummyVerifier) Verify(_ context.Context, _ ocispec.Descriptor, _ []byte return outcome, nil } -func (v *dummyVerifier) VerifyBlob(_ context.Context, _ BlobDescriptorGenerator, _ []byte, _ BlobVerifierVerifyOptions) (*VerificationOutcome, error) { - if v.FailVerify { - return nil, errors.New("failed verify") - } - - return &VerificationOutcome{ - VerificationResults: []*ValidationResult{}, - VerificationLevel: &v.VerificationLevel, - EnvelopeContent: &signature.EnvelopeContent{ - Payload: signature.Payload{ - Content: []byte("{}"), - }, - }, - }, nil -} - var ( reference = "sha256:19dbd2e48e921426ee8ace4dc892edfb2ecdc1d1a72d5416c83670c30acecef0" artifactReference = "local/oci-layout@sha256:19dbd2e48e921426ee8ace4dc892edfb2ecdc1d1a72d5416c83670c30acecef0" diff --git a/signer/plugin.go b/signer/plugin.go index b7f7a020..5768f7b1 100644 --- a/signer/plugin.go +++ b/signer/plugin.go @@ -15,7 +15,6 @@ package signer import ( "context" - "crypto" "crypto/x509" "encoding/json" "errors" @@ -30,7 +29,6 @@ import ( "github.com/notaryproject/notation-go/log" "github.com/notaryproject/notation-go/plugin/proto" "github.com/notaryproject/notation-plugin-framework-go/plugin" - "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -43,12 +41,6 @@ type PluginSigner struct { manifestAnnotations map[string]string } -var algorithms = map[crypto.Hash]digest.Algorithm{ - crypto.SHA256: digest.SHA256, - crypto.SHA384: digest.SHA384, - crypto.SHA512: digest.SHA512, -} - // NewFromPlugin creates a notation.Signer 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. @@ -116,38 +108,6 @@ 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. -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) - - logger.Debug("Invoking plugin's get-plugin-metadata command") - metadata, err := s.plugin.GetMetadata(ctx, &plugin.GetMetadataRequest{PluginConfig: mergedConfig}) - if err != nil { - return nil, nil, err - } - - logger.Debug("Invoking plugin's describe-key command") - ks, err := s.getKeySpec(ctx, mergedConfig) - if err != nil { - return nil, nil, err - } - - // get descriptor to sign - desc, err := getDescriptor(ks, descGenFunc) - if err != nil { - return nil, nil, err - } - - logger.Debugf("Using plugin %v with capabilities %v to sign blob using descriptor %+v", metadata.Name, metadata.Capabilities, desc) - if metadata.HasCapability(plugin.CapabilitySignatureGenerator) { - return s.generateSignature(ctx, desc, opts, ks, metadata, mergedConfig) - } else if metadata.HasCapability(plugin.CapabilityEnvelopeGenerator) { - return s.generateSignatureEnvelope(ctx, desc, opts) - } - return nil, nil, fmt.Errorf("plugin does not have signing capabilities") -} - func (s *PluginSigner) getKeySpec(ctx context.Context, config map[string]string) (signature.KeySpec, error) { logger := log.GetLogger(ctx) logger.Debug("Invoking plugin's describe-key command") diff --git a/signer/plugin_test.go b/signer/plugin_test.go index 634df66f..c4f5b7fe 100644 --- a/signer/plugin_test.go +++ b/signer/plugin_test.go @@ -32,7 +32,6 @@ import ( "github.com/notaryproject/notation-go/internal/envelope" "github.com/notaryproject/notation-go/plugin" "github.com/notaryproject/notation-go/plugin/proto" - "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -71,16 +70,6 @@ type mockPlugin struct { keySpec signature.KeySpec } -func getDescriptorFunc(throwError bool) func(hashAlgo digest.Algorithm) (ocispec.Descriptor, error) { - return func(hashAlgo digest.Algorithm) (ocispec.Descriptor, error) { - if throwError { - return ocispec.Descriptor{}, errors.New("") - } - return validSignDescriptor, nil - } - -} - func newMockPlugin(key crypto.PrivateKey, certs []*x509.Certificate, keySpec signature.KeySpec) *mockPlugin { return &mockPlugin{ key: key, @@ -336,22 +325,6 @@ func TestPluginSigner_Sign_Valid(t *testing.T) { } } -func TestPluginSigner_SignBlob_Valid(t *testing.T) { - for _, envelopeType := range signature.RegisteredEnvelopeTypes() { - for _, keyCert := range keyCertPairCollections { - t.Run(fmt.Sprintf("external plugin,envelopeType=%v_keySpec=%v", envelopeType, keyCert.keySpecName), func(t *testing.T) { - keySpec, _ := proto.DecodeKeySpec(proto.KeySpec(keyCert.keySpecName)) - pluginSigner := PluginSigner{ - plugin: newMockPlugin(keyCert.key, keyCert.certs, keySpec), - } - validSignOpts.SignatureMediaType = envelopeType - data, signerInfo, err := pluginSigner.SignBlob(context.Background(), getDescriptorFunc(false), validSignOpts) - basicSignTest(t, &pluginSigner, envelopeType, data, signerInfo, err) - }) - } - } -} - func TestPluginSigner_SignEnvelope_RunFailed(t *testing.T) { for _, envelopeType := range signature.RegisteredEnvelopeTypes() { t.Run(fmt.Sprintf("envelopeType=%v", envelopeType), func(t *testing.T) { diff --git a/signer/signer.go b/signer/signer.go index 4bd995cd..fe710942 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -167,30 +167,3 @@ 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) { - logger := log.GetLogger(ctx) - logger.Debugf("Generic blob signing for signature media type %v", opts.SignatureMediaType) - - ks, err := s.signer.KeySpec() - if err != nil { - return nil, nil, err - } - - desc, err := getDescriptor(ks, descGenFunc) - if err != nil { - return nil, nil, err - } - - return s.Sign(ctx, desc, opts) -} - -func getDescriptor(ks signature.KeySpec, descGenFunc 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) -} diff --git a/signer/signer_test.go b/signer/signer_test.go index fd1f4fb5..1dac5ebe 100644 --- a/signer/signer_test.go +++ b/signer/signer_test.go @@ -259,31 +259,6 @@ func TestSignWithTimestamping(t *testing.T) { } } -func TestSignBlobWithCertChain(t *testing.T) { - // sign with key - for _, envelopeType := range signature.RegisteredEnvelopeTypes() { - for _, keyCert := range keyCertPairCollections { - t.Run(fmt.Sprintf("envelopeType=%v_keySpec=%v", envelopeType, keyCert.keySpecName), func(t *testing.T) { - s, err := NewGenericSigner(keyCert.key, keyCert.certs) - if err != nil { - t.Fatalf("NewSigner() error = %v", err) - } - - sOpts := notation.SignerSignOptions{ - SignatureMediaType: envelopeType, - } - sig, _, err := s.SignBlob(context.Background(), getDescriptorFunc(false), sOpts) - if err != nil { - t.Fatalf("Sign() error = %v", err) - } - - // basic verification - basicVerification(t, sig, envelopeType, keyCert.certs[len(keyCert.certs)-1], nil) - }) - } - } -} - func TestSignWithoutExpiry(t *testing.T) { // sign with key for _, envelopeType := range signature.RegisteredEnvelopeTypes() { diff --git a/verifier/helpers_test.go b/verifier/helpers_test.go index 4803d4a1..fa0787b1 100644 --- a/verifier/helpers_test.go +++ b/verifier/helpers_test.go @@ -152,17 +152,3 @@ func dummyOCIPolicyDocument() (policyDoc trustpolicy.OCIDocument) { }, } } - -func dummyBlobPolicyDocument() (policyDoc trustpolicy.BlobDocument) { - return trustpolicy.BlobDocument{ - Version: "1.0", - TrustPolicies: []trustpolicy.BlobTrustPolicy{ - { - Name: "blob-test-statement-name", - SignatureVerification: trustpolicy.SignatureVerification{VerificationLevel: "strict"}, - TrustStores: []string{"ca:valid-trust-store", "signingAuthority:valid-trust-store"}, - TrustedIdentities: []string{"x509.subject:CN=Notation Test Root,O=Notary,L=Seattle,ST=WA,C=US"}, - }, - }, - } -} diff --git a/verifier/trustpolicy/blob.go b/verifier/trustpolicy/blob.go deleted file mode 100644 index b016c0ec..00000000 --- a/verifier/trustpolicy/blob.go +++ /dev/null @@ -1,151 +0,0 @@ -// Copyright The Notary Project Authors. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trustpolicy - -import ( - "errors" - "fmt" - "reflect" - "strings" - - "github.com/notaryproject/notation-go/dir" - set "github.com/notaryproject/notation-go/internal/container" - "github.com/notaryproject/notation-go/internal/slices" -) - -// BlobDocument represents a trustpolicy.blob.json document -type BlobDocument struct { - // Version of the policy document - Version string `json:"version"` - - // TrustPolicies include each policy statement - TrustPolicies []BlobTrustPolicy `json:"trustPolicies"` -} - -// BlobTrustPolicy represents a policy statement in the blob policy document -type BlobTrustPolicy struct { - // Name of the policy statement - Name string `json:"name"` - - // SignatureVerification setting for this policy statement - SignatureVerification SignatureVerification `json:"signatureVerification"` - - // TrustStores this policy statement uses - TrustStores []string `json:"trustStores"` - - // TrustedIdentities this policy statement pins - TrustedIdentities []string `json:"trustedIdentities"` - - // GlobalPolicy defines if policy statement is global or not - GlobalPolicy bool `json:"globalPolicy,omitempty"` -} - -var supportedBlobPolicyVersions = []string{"1.0"} - -// LoadBlobDocument loads a trust policy document from a local file system -func LoadBlobDocument() (*BlobDocument, error) { - var doc BlobDocument - err := getDocument(dir.PathBlobTrustPolicy, &doc) - return &doc, err -} - -// Validate validates a policy document according to its version's rule set. -// if any rule is violated, returns an error -func (policyDoc *BlobDocument) Validate() error { - // sanity check - if policyDoc == nil { - return errors.New("blob trust policy document cannot be nil") - } - - // Validate Version - if policyDoc.Version == "" { - return errors.New("blob trust policy has empty version, version must be specified") - } - if !slices.Contains(supportedBlobPolicyVersions, policyDoc.Version) { - return fmt.Errorf("blob trust policy document uses unsupported version %q", policyDoc.Version) - } - - // Validate the policy according to 1.0 rules - if len(policyDoc.TrustPolicies) == 0 { - return errors.New("blob trust policy document can not have zero trust policy statements") - } - - policyNames := set.New[string]() - var foundGlobalPolicy bool - for _, statement := range policyDoc.TrustPolicies { - // Verify unique policy statement names across the policy document - if policyNames.Contains(statement.Name) { - return fmt.Errorf("multiple blob trust policy statements use the same name %q, statement names must be unique", statement.Name) - } - - if err := validatePolicyCore(statement.Name, statement.SignatureVerification, statement.TrustStores, statement.TrustedIdentities); err != nil { - return fmt.Errorf("blob trust policy: %w", err) - } - - if statement.GlobalPolicy { - if foundGlobalPolicy { - return errors.New("multiple blob trust policy statements have globalPolicy set to true. Only one trust policy statement can be marked as global policy") - } - - // verificationLevel is skip - if reflect.DeepEqual(statement.SignatureVerification.VerificationLevel, LevelSkip) { - return errors.New("global blob trust policy statement cannot have verification level set to skip") - } - - foundGlobalPolicy = true - } - policyNames.Add(statement.Name) - } - - return nil -} - -// GetApplicableTrustPolicy returns a pointer to the deep copied TrustPolicy for given policy name -// see https://github.com/notaryproject/notaryproject/blob/v1.1.0/specs/trust-store-trust-policy.md#blob-trust-policy -func (policyDoc *BlobDocument) GetApplicableTrustPolicy(policyName string) (*BlobTrustPolicy, error) { - if strings.TrimSpace(policyName) == "" { - return nil, errors.New("policy name cannot be empty") - } - for _, policyStatement := range policyDoc.TrustPolicies { - // exact match - if policyStatement.Name == policyName { - return (&policyStatement).clone(), nil - } - } - - return nil, fmt.Errorf("no applicable blob trust policy with name %q", policyName) -} - -// GetGlobalTrustPolicy returns a pointer to the deep copy of the TrustPolicy that is marked as global policy -// see https://github.com/notaryproject/notaryproject/blob/v1.1.0/specs/trust-store-trust-policy.md#blob-trust-policy -func (policyDoc *BlobDocument) GetGlobalTrustPolicy() (*BlobTrustPolicy, error) { - for _, policyStatement := range policyDoc.TrustPolicies { - if policyStatement.GlobalPolicy { - return (&policyStatement).clone(), nil - } - } - - return nil, fmt.Errorf("no global blob trust policy") -} - -// clone returns a pointer to the deeply copied TrustPolicy -func (t *BlobTrustPolicy) clone() *BlobTrustPolicy { - return &BlobTrustPolicy{ - Name: t.Name, - SignatureVerification: t.SignatureVerification, - TrustedIdentities: append([]string(nil), t.TrustedIdentities...), - TrustStores: append([]string(nil), t.TrustStores...), - GlobalPolicy: t.GlobalPolicy, - } -} diff --git a/verifier/trustpolicy/blob_test.go b/verifier/trustpolicy/blob_test.go deleted file mode 100644 index 06ada681..00000000 --- a/verifier/trustpolicy/blob_test.go +++ /dev/null @@ -1,168 +0,0 @@ -// Copyright The Notary Project Authors. -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -package trustpolicy - -import ( - "encoding/json" - "os" - "path/filepath" - "reflect" - "testing" - - "github.com/notaryproject/notation-go/dir" -) - -func TestLoadBlobDocument(t *testing.T) { - tempRoot := t.TempDir() - dir.UserConfigDir = tempRoot - path := filepath.Join(tempRoot, "trustpolicy.blob.json") - policyJson, _ := json.Marshal(dummyBlobPolicyDocument()) - if err := os.WriteFile(path, policyJson, 0600); err != nil { - t.Fatalf("TestLoadBlobDocument write policy file failed. Error: %v", err) - } - t.Cleanup(func() { os.RemoveAll(tempRoot) }) - - if _, err := LoadBlobDocument(); err != nil { - t.Fatalf("LoadBlobDocument() should not throw error for an existing policy file. Error: %v", err) - } -} - -func TestValidate_BlobDocument(t *testing.T) { - policyDoc := dummyBlobPolicyDocument() - if err := policyDoc.Validate(); err != nil { - t.Fatalf("Validate() returned error: %v", err) - } -} - -func TestValidate_BlobDocument_Error(t *testing.T) { - // Sanity check - var nilPolicyDoc *BlobDocument - err := nilPolicyDoc.Validate() - if err == nil || err.Error() != "blob trust policy document cannot be nil" { - t.Fatalf("nil policyDoc should return error") - } - - // empty Version - policyDoc := dummyBlobPolicyDocument() - policyDoc.Version = "" - err = policyDoc.Validate() - if err == nil || err.Error() != "blob trust policy has empty version, version must be specified" { - t.Fatalf("empty version should return error") - } - - // Invalid Version - policyDoc = dummyBlobPolicyDocument() - policyDoc.Version = "invalid" - err = policyDoc.Validate() - if err == nil || err.Error() != "blob trust policy document uses unsupported version \"invalid\"" { - t.Fatalf("invalid version should return error") - } - - // No Policy Statements - policyDoc = dummyBlobPolicyDocument() - policyDoc.TrustPolicies = nil - err = policyDoc.Validate() - if err == nil || err.Error() != "blob trust policy document can not have zero trust policy statements" { - t.Fatalf("zero policy statements should return error") - } - - // No Policy Statement Name - policyDoc = dummyBlobPolicyDocument() - policyDoc.TrustPolicies[0].Name = "" - err = policyDoc.Validate() - if err == nil || err.Error() != "blob trust policy: a trust policy statement is missing a name, every statement requires a name" { - t.Fatalf("policy statement with no name should return an error") - } - - // multiple global rust policy - policyDoc = dummyBlobPolicyDocument() - policyStatement1 := policyDoc.TrustPolicies[0].clone() - policyStatement1.GlobalPolicy = true - policyStatement2 := policyDoc.TrustPolicies[0].clone() - policyStatement2.Name = "test-statement-name-2" - policyStatement2.GlobalPolicy = true - policyDoc.TrustPolicies = []BlobTrustPolicy{*policyStatement1, *policyStatement2} - err = policyDoc.Validate() - if err == nil || err.Error() != "multiple blob trust policy statements have globalPolicy set to true. Only one trust policy statement can be marked as global policy" { - t.Error(err) - t.Fatalf("multiple global blob policy should return error") - } - - // Policy Document with duplicate policy statement names - policyDoc = dummyBlobPolicyDocument() - policyStatement1 = policyDoc.TrustPolicies[0].clone() - policyStatement2 = policyDoc.TrustPolicies[0].clone() - policyDoc.TrustPolicies = []BlobTrustPolicy{*policyStatement1, *policyStatement2} - err = policyDoc.Validate() - if err == nil || err.Error() != "multiple blob trust policy statements use the same name \"test-statement-name\", statement names must be unique" { - t.Fatalf("policy statements with same name should return error") - } -} - -func TestGetApplicableTrustPolicy(t *testing.T) { - policyDoc := dummyBlobPolicyDocument() - - policyStatement := policyDoc.TrustPolicies[0].clone() - policyStatement1 := policyStatement.clone() - policyStatement1.Name = "test-statement-name-1" - policyStatement1.GlobalPolicy = true - policyStatement2 := policyStatement.clone() - policyStatement2.Name = "test-statement-name-2" - policyDoc.TrustPolicies = []BlobTrustPolicy{*policyStatement, *policyStatement1, *policyStatement2} - - validateGetApplicableTrustPolicy(t, policyDoc, "test-statement-name-2", policyStatement2) - validateGetApplicableTrustPolicy(t, policyDoc, "test-statement-name", policyStatement) -} - -func TestGetApplicableTrustPolicy_Error(t *testing.T) { - policyDoc := dummyBlobPolicyDocument() - t.Run("empty policy name", func(t *testing.T) { - _, err := policyDoc.GetApplicableTrustPolicy("") - if err == nil || err.Error() != "policy name cannot be empty" { - t.Fatalf("GetApplicableTrustPolicy() returned error: %v", err) - } - }) - - t.Run("non existent policy name", func(t *testing.T) { - _, err := policyDoc.GetApplicableTrustPolicy("blaah") - if err == nil || err.Error() != "no applicable blob trust policy with name \"blaah\"" { - t.Fatalf("GetApplicableTrustPolicy() returned error: %v", err) - } - }) -} - -func TestGetGlobalTrustPolicy(t *testing.T) { - policyDoc := dummyBlobPolicyDocument() - policyDoc.TrustPolicies[0].GlobalPolicy = true - - policy, err := policyDoc.GetGlobalTrustPolicy() - if err != nil { - t.Fatalf("GetGlobalTrustPolicy() returned error: %v", err) - } - - if !reflect.DeepEqual(*policy, policyDoc.TrustPolicies[0]) { - t.Fatalf("GetGlobalTrustPolicy() returned unexpected policy") - } -} - -func validateGetApplicableTrustPolicy(t *testing.T, policyDoc BlobDocument, policyName string, expectedPolicy *BlobTrustPolicy) { - policy, err := policyDoc.GetApplicableTrustPolicy(policyName) - if err != nil { - t.Fatalf("GetApplicableTrustPolicy() returned error: %v", err) - } - - if reflect.DeepEqual(policy, *expectedPolicy) { - t.Fatalf("GetApplicableTrustPolicy() returned unexpected policy for %s", policyName) - } -} diff --git a/verifier/trustpolicy/trustpolicy_test.go b/verifier/trustpolicy/trustpolicy_test.go index 381a9624..96b758e1 100644 --- a/verifier/trustpolicy/trustpolicy_test.go +++ b/verifier/trustpolicy/trustpolicy_test.go @@ -41,20 +41,6 @@ func dummyOCIPolicyDocument() OCIDocument { } } -func dummyBlobPolicyDocument() BlobDocument { - return BlobDocument{ - Version: "1.0", - TrustPolicies: []BlobTrustPolicy{ - { - Name: "test-statement-name", - SignatureVerification: SignatureVerification{VerificationLevel: "strict"}, - TrustStores: []string{"ca:valid-trust-store", "signingAuthority:valid-trust-store"}, - TrustedIdentities: []string{"x509.subject:CN=Notation Test Root,O=Notary,L=Seattle,ST=WA,C=US"}, - }, - }, - } -} - // create testcase for validatePolicyCore method func TestValidatePolicyCore(t *testing.T) { policyName := "test-statement-name" @@ -307,7 +293,6 @@ func TestGetDocument(t *testing.T) { } dir.UserConfigDir = "/" var ociDoc OCIDocument - var blobDoc BlobDocument tests := []struct { name string expectedDocument any @@ -318,11 +303,6 @@ func TestGetDocument(t *testing.T) { expectedDocument: dummyOCIPolicyDocument(), actualDocument: &ociDoc, }, - { - name: "valid Blob policy file", - expectedDocument: dummyBlobPolicyDocument(), - actualDocument: &blobDoc, - }, } for _, tt := range tests { diff --git a/verifier/verifier.go b/verifier/verifier.go index 30cc1ef5..7dc46f03 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -16,7 +16,6 @@ package verifier import ( "context" - "crypto" "crypto/x509" "encoding/json" "errors" @@ -46,20 +45,12 @@ import ( "github.com/notaryproject/notation-go/verifier/truststore" pluginframework "github.com/notaryproject/notation-plugin-framework-go/plugin" "github.com/notaryproject/tspclient-go" - "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) -var algorithms = map[crypto.Hash]digest.Algorithm{ - crypto.SHA256: digest.SHA256, - crypto.SHA384: digest.SHA384, - crypto.SHA512: digest.SHA512, -} - // verifier implements notation.Verifier, notation.BlobVerifier and notation.verifySkipper type verifier struct { - ociTrustPolicyDoc *trustpolicy.OCIDocument - blobTrustPolicyDoc *trustpolicy.BlobDocument + trustPolicyDoc *trustpolicy.OCIDocument trustStore truststore.X509TrustStore pluginManager plugin.Manager revocationClient revocation.Revocation @@ -88,38 +79,26 @@ func NewOCIVerifierFromConfig() (*verifier, error) { // load trust store x509TrustStore := truststore.NewX509TrustStore(dir.ConfigFS()) - return NewVerifier(policyDocument, nil, x509TrustStore, plugin.NewCLIManager(dir.PluginFS())) + return NewVerifier(policyDocument, x509TrustStore, plugin.NewCLIManager(dir.PluginFS())) } -// NewBlobVerifierFromConfig returns a Blob verifier based on local file system -func NewBlobVerifierFromConfig() (*verifier, error) { - // load trust policy - policyDocument, err := trustpolicy.LoadBlobDocument() - if err != nil { - return nil, err - } - // load trust store - x509TrustStore := truststore.NewX509TrustStore(dir.ConfigFS()) - - return NewVerifier(nil, policyDocument, x509TrustStore, plugin.NewCLIManager(dir.PluginFS())) -} - -// NewWithOptions creates a new verifier given ociTrustPolicy, trustStore, +// NewWithOptions creates a new verifier given trustPolicy, trustStore, // pluginManager, and VerifierOptions +// // Deprecated: NewWithOptions function exists for historical compatibility and should not be used. // To create verifier, use NewVerifierWithOptions function. -func NewWithOptions(ociTrustPolicy *trustpolicy.OCIDocument, trustStore truststore.X509TrustStore, pluginManager plugin.Manager, opts VerifierOptions) (notation.Verifier, error) { - return NewVerifierWithOptions(ociTrustPolicy, nil, trustStore, pluginManager, opts) +func NewWithOptions(trustPolicy *trustpolicy.OCIDocument, trustStore truststore.X509TrustStore, pluginManager plugin.Manager, opts VerifierOptions) (notation.Verifier, error) { + return NewVerifierWithOptions(trustPolicy, trustStore, pluginManager, opts) } -// NewVerifier creates a new verifier given ociTrustPolicy, trustStore and pluginManager -func NewVerifier(ociTrustPolicy *trustpolicy.OCIDocument, blobTrustPolicy *trustpolicy.BlobDocument, trustStore truststore.X509TrustStore, pluginManager plugin.Manager) (*verifier, error) { - return NewVerifierWithOptions(ociTrustPolicy, blobTrustPolicy, trustStore, pluginManager, VerifierOptions{}) +// NewVerifier creates a new verifier given trustPolicy, trustStore and pluginManager +func NewVerifier(trustPolicy *trustpolicy.OCIDocument, trustStore truststore.X509TrustStore, pluginManager plugin.Manager) (*verifier, error) { + return NewVerifierWithOptions(trustPolicy, trustStore, pluginManager, VerifierOptions{}) } -// NewVerifierWithOptions creates a new verifier given ociTrustPolicy, blobTrustPolicy, +// NewVerifierWithOptions creates a new verifier given trustPolicy, blobTrustPolicy, // trustStore, pluginManager, and verifierOptions -func NewVerifierWithOptions(ociTrustPolicy *trustpolicy.OCIDocument, blobTrustPolicy *trustpolicy.BlobDocument, trustStore truststore.X509TrustStore, pluginManager plugin.Manager, verifierOptions VerifierOptions) (*verifier, error) { +func NewVerifierWithOptions(trustPolicy *trustpolicy.OCIDocument, trustStore truststore.X509TrustStore, pluginManager plugin.Manager, verifierOptions VerifierOptions) (*verifier, error) { revocationClient := verifierOptions.RevocationClient if revocationClient == nil { var err error @@ -142,25 +121,16 @@ func NewVerifierWithOptions(ociTrustPolicy *trustpolicy.OCIDocument, blobTrustPo return nil, errors.New("trustStore cannot be nil") } - if ociTrustPolicy == nil && blobTrustPolicy == nil { - return nil, errors.New("ociTrustPolicy and blobTrustPolicy both cannot be nil") + if trustPolicy == nil { + return nil, errors.New("trustPolicy cannot be nil") } - if ociTrustPolicy != nil { - if err := ociTrustPolicy.Validate(); err != nil { - return nil, err - } - } - - if blobTrustPolicy != nil { - if err := blobTrustPolicy.Validate(); err != nil { - return nil, err - } + if err := trustPolicy.Validate(); err != nil { + return nil, err } return &verifier{ - ociTrustPolicyDoc: ociTrustPolicy, - blobTrustPolicyDoc: blobTrustPolicy, + trustPolicyDoc: trustPolicy, trustStore: trustStore, pluginManager: pluginManager, revocationClient: revocationClient, @@ -175,11 +145,11 @@ func NewFromConfig() (notation.Verifier, error) { return NewOCIVerifierFromConfig() } -// New creates a new verifier given ociTrustPolicy, trustStore and pluginManager +// New creates a new verifier given trustPolicy, trustStore and pluginManager // Deprecated: New function exists for historical compatibility and should not be used. // To create verifier, use NewVerifier function. -func New(ociTrustPolicy *trustpolicy.OCIDocument, trustStore truststore.X509TrustStore, pluginManager plugin.Manager) (notation.Verifier, error) { - return NewVerifier(ociTrustPolicy, nil, trustStore, pluginManager) +func New(trustPolicy *trustpolicy.OCIDocument, trustStore truststore.X509TrustStore, pluginManager plugin.Manager) (notation.Verifier, error) { + return NewVerifier(trustPolicy, trustStore, pluginManager) } // SkipVerify validates whether the verification level is skip. @@ -187,7 +157,7 @@ func (v *verifier) SkipVerify(ctx context.Context, opts notation.VerifierVerifyO logger := log.GetLogger(ctx) logger.Debugf("Check verification level against artifact %v", opts.ArtifactReference) - trustPolicy, err := v.ociTrustPolicyDoc.GetApplicableTrustPolicy(opts.ArtifactReference) + trustPolicy, err := v.trustPolicyDoc.GetApplicableTrustPolicy(opts.ArtifactReference) if err != nil { return false, nil, notation.ErrorNoApplicableTrustPolicy{Msg: err.Error()} } @@ -204,87 +174,6 @@ func (v *verifier) SkipVerify(ctx context.Context, opts notation.VerifierVerifyO return false, verificationLevel, nil } -// VerifyBlob verifies the signature of given blob , and returns the outcome upon -// successful verification. -func (v *verifier) VerifyBlob(ctx context.Context, descGenFunc notation.BlobDescriptorGenerator, signature []byte, opts notation.BlobVerifierVerifyOptions) (*notation.VerificationOutcome, error) { - logger := log.GetLogger(ctx) - logger.Debugf("Verify signature of media type %v", opts.SignatureMediaType) - if v.blobTrustPolicyDoc == nil { - return nil, errors.New("blobTrustPolicyDoc is nil") - } - - var trustPolicy *trustpolicy.BlobTrustPolicy - var err error - if opts.TrustPolicyName == "" { - trustPolicy, err = v.blobTrustPolicyDoc.GetGlobalTrustPolicy() - } else { - trustPolicy, err = v.blobTrustPolicyDoc.GetApplicableTrustPolicy(opts.TrustPolicyName) - } - if err != nil { - return nil, notation.ErrorNoApplicableTrustPolicy{Msg: err.Error()} - } - logger.Infof("Trust policy configuration: %+v", trustPolicy) - - // ignore the error since we already validated the policy document - verificationLevel, _ := trustPolicy.SignatureVerification.GetVerificationLevel() - outcome := ¬ation.VerificationOutcome{ - RawSignature: signature, - VerificationLevel: verificationLevel, - } - // verificationLevel is skip - if reflect.DeepEqual(verificationLevel, trustpolicy.LevelSkip) { - logger.Debug("Skipping signature verification") - return outcome, nil - } - err = v.processSignature(ctx, signature, opts.SignatureMediaType, trustPolicy.Name, trustPolicy.TrustedIdentities, trustPolicy.TrustStores, trustPolicy.SignatureVerification, opts.PluginConfig, outcome) - if err != nil { - outcome.Error = err - return outcome, err - } - - payload := &envelope.Payload{} - err = json.Unmarshal(outcome.EnvelopeContent.Payload.Content, payload) - if err != nil { - logger.Error("Failed to unmarshal the payload content in the signature blob to envelope.Payload") - outcome.Error = err - return outcome, err - } - - cryptoHash := outcome.EnvelopeContent.SignerInfo.SignatureAlgorithm.Hash() - digestAlgo, ok := algorithms[cryptoHash] - if !ok { - logger.Error("Unsupported hashing algorithm: %v", cryptoHash) - err := fmt.Errorf("unsupported hashing algorithm: %v", cryptoHash) - outcome.Error = err - return outcome, err - } - - desc, err := descGenFunc(digestAlgo) - if err != nil { - errMsg := fmt.Sprintf("failed to generate descriptor for given artifact. Error: %s", err) - logger.Error(errMsg) - descErr := errors.New(errMsg) - outcome.Error = descErr - return outcome, descErr - } - - if desc.Digest != payload.TargetArtifact.Digest || desc.Size != payload.TargetArtifact.Size || - (desc.MediaType != "" && desc.MediaType != payload.TargetArtifact.MediaType) { - logger.Infof("payload present in the signature: %+v", payload.TargetArtifact) - logger.Infof("payload derived from the blob: %+v", desc) - outcome.Error = errors.New("integrity check failed. signature does not match the given blob") - } - - if len(opts.UserMetadata) > 0 { - err := verifyUserMetadata(logger, payload, opts.UserMetadata) - if err != nil { - outcome.Error = err - } - } - - return outcome, outcome.Error -} - // Verify verifies the signature associated the target OCI // artifact with manifest descriptor `desc`, and returns the outcome upon // successful verification. @@ -297,11 +186,11 @@ func (v *verifier) Verify(ctx context.Context, desc ocispec.Descriptor, signatur logger := log.GetLogger(ctx) logger.Debugf("Verify signature against artifact %v referenced as %s in signature media type %v", desc.Digest, artifactRef, envelopeMediaType) - if v.ociTrustPolicyDoc == nil { - return nil, errors.New("ociTrustPolicyDoc is nil") + if v.trustPolicyDoc == nil { + return nil, errors.New("trustPolicyDoc is nil") } - trustPolicy, err := v.ociTrustPolicyDoc.GetApplicableTrustPolicy(artifactRef) + trustPolicy, err := v.trustPolicyDoc.GetApplicableTrustPolicy(artifactRef) if err != nil { return nil, notation.ErrorNoApplicableTrustPolicy{Msg: err.Error()} } diff --git a/verifier/verifier_test.go b/verifier/verifier_test.go index 9489dfae..da9b3244 100644 --- a/verifier/verifier_test.go +++ b/verifier/verifier_test.go @@ -16,7 +16,6 @@ package verifier import ( "context" "crypto/x509" - "encoding/pem" "errors" "fmt" "net/http" @@ -31,7 +30,6 @@ import ( "github.com/notaryproject/notation-core-go/revocation" "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-core-go/testhelper" corex509 "github.com/notaryproject/notation-core-go/x509" "github.com/notaryproject/notation-go" @@ -43,40 +41,10 @@ import ( "github.com/notaryproject/notation-go/signer" "github.com/notaryproject/notation-go/verifier/trustpolicy" "github.com/notaryproject/notation-go/verifier/truststore" - "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) -var testSig = `{"payload":"eyJ0YXJnZXRBcnRpZmFjdCI6eyJhbm5vdGF0aW9ucyI6eyJidWlsZElkIjoiMTAxIn0sImRpZ2VzdCI6InNoYTM4NDpiOGFiMjRkYWZiYTVjZjdlNGM4OWM1NjJmODExY2YxMDQ5M2Q0MjAzZGE5ODJkM2IxMzQ1ZjM2NmNhODYzZDljMmVkMzIzZGJkMGZiN2ZmODNhODAzMDJjZWZmYTVhNjEiLCJtZWRpYVR5cGUiOiJ2aWRlby9tcDQiLCJzaXplIjoxMn19","protected":"eyJhbGciOiJQUzM4NCIsImNyaXQiOlsiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSJdLCJjdHkiOiJhcHBsaWNhdGlvbi92bmQuY25jZi5ub3RhcnkucGF5bG9hZC52MStqc29uIiwiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSI6Im5vdGFyeS54NTA5IiwiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1RpbWUiOiIyMDI0LTA0LTA0VDE1OjAzOjA2LTA3OjAwIn0","header":{"x5c":["MIIEbTCCAtWgAwIBAgICAK0wDQYJKoZIhvcNAQELBQAwZDELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3RhcnkxJTAjBgNVBAMTHE5vdGF0aW9uIEV4YW1wbGUgc2VsZi1zaWduZWQwIBcNMjQwNDA0MjIwMzA1WhgPMjEyNDA0MDQyMjAzMDVaMGQxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJXQTEQMA4GA1UEBxMHU2VhdHRsZTEPMA0GA1UEChMGTm90YXJ5MSUwIwYDVQQDExxOb3RhdGlvbiBFeGFtcGxlIHNlbGYtc2lnbmVkMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEA0dXD9UqzZcGlBlvPHO2uf+Sel/xwf/eOMS6Q30GV6JPeu9czLmyR0YMfC6P0N4zDzVYYZtQLkS5lalTMGX9A3yj9aXtXvtoYtLx2mF1CfdQJMcrT63wVVTWiPPe2JT8KHkkiACzVY6LTwc4s+DIAw9Gv21Uu6bFy4WWlGMp8UwTucR0JqaFoXzB6vxVRTkK8RRLM9Pj0hM5NwobpuZ+pc+ZS/7PhdvQHVzHeLLV9S7fHxw3n1c0ti8VUjSPSqCIEqOL3Eu/0pWMXB2A1xzn3RBfnzZMD3Tw3ksFgLMVzblhv41c6gr4cgjaS4wWwUvq9Xndd7Io8QNvxyiRDX5cHwQSEOmDfmegTIaLR0dKfvjY4ZJq8Y1DnaXU4RD6XeihtZykMlx7nTUyZZXpQ1akjh3VMzPykJ4mIknHh02zGRT9ZE8E1kYzRWhU/0MAzVrTTFHpric6jO459ouTnQXFjKwAcoD5+bNY6TuhC18iar7+l4BPPI1mFuqETnMfkkJQZAgMBAAGjJzAlMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAYEAe5wyQPo+h1Yk2PkaA5aJKuU8azF2pTLfhQwAn/1XqPcmhNQuomOP0waoBsh+6sexfIDZaNuJ+zZUxqYHke/23+768SMiJCpuJfion3ak3Ka/IVNz48G0V+V+Vog+elkZzpdUQd30njLVcoQsihp0I/Gs3pnG2SeHmsdvYVuzycdYWTt5BFu4N8VWg4x4pfRMgDG7HGxRAacz2vTdqAx6rpWjO4xc0ZO8iUKjAeKHc7RuSx2dhUaRP9P8G8NBNtG6xNnbXIEjH6kP05srFRZ2jxm1an7sjsOpbBdIDztc0J+cb5yjBx7zo1OzWcmDUqMEXDR/WoygPzwhhHvWWvTqwVSEUvYnSaI6wxyHGxPFuX3+vCEZxU8NEGIuJtfYXWeo9cev5+PqjDgVu0uCWF53ZFsXNWbpff1qpG/CgrpFh3vN6uquMK9H5zaJBKr0GZFUsNRB1S8cUBgcjIZlWv3wrJQaOIFzF4RFO9dsYcG/b7ubdqSNGe4qfbsyuWf+1xsx"],"io.cncf.notary.signingAgent":"example signing agent"},"signature":"WMtF0u9GnQxJCpgrcxKZtNKNf3fvu2vnvOjd_2vQvjB4I9YKRYDQdr1q0AC0rU9b5aAGqP6Uh3jTbPkHHmOzGhXhRtidunfzOAeC6dPinR_RlnVMnVUY4cimZZG6Tg2tlgqGazgdzphnuZQpxUnK5mSInnWztXz_1-l_UJdPII49loJVE23hvWKDp8xOvMLftFXFlCYF9wE1ecTsYEAdrgB_XurFqbhhfeNcYie02aSMXfN0-ip9MHlIPhGrrOKLVm0w_S3nNBnuHHZ5lARgTm7tHtiNC0XxGCCk8qqteRZ4Vm2VM_UFMVOpdfh5KE_iTzmPCiHfNOJfgmvg5nysL1XUwGJ_KzCkPfY1Hq_4k73lia6RS6NSl1bSQ_s3uMBm3nx74WCmjK89RAihMIQ6s0PmUKQoWsIZ_5lWZ6uFW6LreoYyBFwvVVsSGSUx54-Gh76bwrt75va2VHpolSEXdhjcTK0KgscKLjU-LYDA_JD6AUaCi3WzMnpMSnO-9u_G"}` -var trustedCert = `-----BEGIN CERTIFICATE----- -MIIEbTCCAtWgAwIBAgICAK0wDQYJKoZIhvcNAQELBQAwZDELMAkGA1UEBhMCVVMx -CzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3Rhcnkx -JTAjBgNVBAMTHE5vdGF0aW9uIEV4YW1wbGUgc2VsZi1zaWduZWQwIBcNMjQwNDA0 -MjIwMzA1WhgPMjEyNDA0MDQyMjAzMDVaMGQxCzAJBgNVBAYTAlVTMQswCQYDVQQI -EwJXQTEQMA4GA1UEBxMHU2VhdHRsZTEPMA0GA1UEChMGTm90YXJ5MSUwIwYDVQQD -ExxOb3RhdGlvbiBFeGFtcGxlIHNlbGYtc2lnbmVkMIIBojANBgkqhkiG9w0BAQEF -AAOCAY8AMIIBigKCAYEA0dXD9UqzZcGlBlvPHO2uf+Sel/xwf/eOMS6Q30GV6JPe -u9czLmyR0YMfC6P0N4zDzVYYZtQLkS5lalTMGX9A3yj9aXtXvtoYtLx2mF1CfdQJ -McrT63wVVTWiPPe2JT8KHkkiACzVY6LTwc4s+DIAw9Gv21Uu6bFy4WWlGMp8UwTu -cR0JqaFoXzB6vxVRTkK8RRLM9Pj0hM5NwobpuZ+pc+ZS/7PhdvQHVzHeLLV9S7fH -xw3n1c0ti8VUjSPSqCIEqOL3Eu/0pWMXB2A1xzn3RBfnzZMD3Tw3ksFgLMVzblhv -41c6gr4cgjaS4wWwUvq9Xndd7Io8QNvxyiRDX5cHwQSEOmDfmegTIaLR0dKfvjY4 -ZJq8Y1DnaXU4RD6XeihtZykMlx7nTUyZZXpQ1akjh3VMzPykJ4mIknHh02zGRT9Z -E8E1kYzRWhU/0MAzVrTTFHpric6jO459ouTnQXFjKwAcoD5+bNY6TuhC18iar7+l -4BPPI1mFuqETnMfkkJQZAgMBAAGjJzAlMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUE -DDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAYEAe5wyQPo+h1Yk2PkaA5aJ -KuU8azF2pTLfhQwAn/1XqPcmhNQuomOP0waoBsh+6sexfIDZaNuJ+zZUxqYHke/2 -3+768SMiJCpuJfion3ak3Ka/IVNz48G0V+V+Vog+elkZzpdUQd30njLVcoQsihp0 -I/Gs3pnG2SeHmsdvYVuzycdYWTt5BFu4N8VWg4x4pfRMgDG7HGxRAacz2vTdqAx6 -rpWjO4xc0ZO8iUKjAeKHc7RuSx2dhUaRP9P8G8NBNtG6xNnbXIEjH6kP05srFRZ2 -jxm1an7sjsOpbBdIDztc0J+cb5yjBx7zo1OzWcmDUqMEXDR/WoygPzwhhHvWWvTq -wVSEUvYnSaI6wxyHGxPFuX3+vCEZxU8NEGIuJtfYXWeo9cev5+PqjDgVu0uCWF53 -ZFsXNWbpff1qpG/CgrpFh3vN6uquMK9H5zaJBKr0GZFUsNRB1S8cUBgcjIZlWv3w -rJQaOIFzF4RFO9dsYcG/b7ubdqSNGe4qfbsyuWf+1xsx ------END CERTIFICATE-----` - var ociPolicy = dummyOCIPolicyDocument() -var blobPolicy = dummyBlobPolicyDocument() var store = truststore.NewX509TrustStore(dir.ConfigFS()) var pm = mock.PluginManager{} @@ -91,8 +59,8 @@ func TestNewVerifier_Error(t *testing.T) { func TestInvalidArtifactUriValidations(t *testing.T) { verifier := verifier{ - ociTrustPolicyDoc: &ociPolicy, - pluginManager: mock.PluginManager{}, + trustPolicyDoc: &ociPolicy, + pluginManager: mock.PluginManager{}, } tests := []struct { @@ -122,8 +90,8 @@ func TestInvalidArtifactUriValidations(t *testing.T) { func TestErrorNoApplicableTrustPolicy_Error(t *testing.T) { verifier := verifier{ - ociTrustPolicyDoc: &ociPolicy, - pluginManager: mock.PluginManager{}, + trustPolicyDoc: &ociPolicy, + pluginManager: mock.PluginManager{}, } opts := notation.VerifierVerifyOptions{ArtifactReference: "non-existent-domain.com/repo@sha256:73c803930ea3ba1e54bc25c2bdc53edd0284c62ed651fe7b00369da519a3c333"} _, err := verifier.Verify(context.Background(), ocispec.Descriptor{}, []byte{}, opts) @@ -336,10 +304,10 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) { t.Fatalf("unexpected error while creating revocation object: %v", err) } verifier := verifier{ - ociTrustPolicyDoc: &tt.policyDocument, - trustStore: truststore.NewX509TrustStore(dir.ConfigFS()), - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &tt.policyDocument, + trustStore: truststore.NewX509TrustStore(dir.ConfigFS()), + pluginManager: pluginManager, + revocationClient: revocationClient, } outcome, _ := verifier.Verify(context.Background(), ocispec.Descriptor{}, tt.signatureBlob, tt.opts) verifyResult(outcome, expectedResult, tt.expectedErr, t) @@ -403,10 +371,10 @@ func TestVerifyRevocationEnvelope(t *testing.T) { dir.UserConfigDir = "testdata" verifier := verifier{ - ociTrustPolicyDoc: &policyDoc, - trustStore: truststore.NewX509TrustStore(dir.ConfigFS()), - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDoc, + trustStore: truststore.NewX509TrustStore(dir.ConfigFS()), + pluginManager: pluginManager, + revocationClient: revocationClient, } outcome, err := verifier.Verify(context.Background(), desc, envelopeBlob, opts) if err == nil || err.Error() != expectedErr.Error() { @@ -432,10 +400,10 @@ func TestVerifyRevocationEnvelope(t *testing.T) { dir.UserConfigDir = "testdata" verifier := verifier{ - ociTrustPolicyDoc: &policyDoc, - trustStore: truststore.NewX509TrustStore(dir.ConfigFS()), - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDoc, + trustStore: truststore.NewX509TrustStore(dir.ConfigFS()), + pluginManager: pluginManager, + revocationClient: revocationClient, } ctx := context.Background() outcome, err := verifier.Verify(ctx, desc, envelopeBlob, opts) @@ -456,10 +424,10 @@ func TestVerifyRevocationEnvelope(t *testing.T) { dir.UserConfigDir = "testdata" verifier := verifier{ - ociTrustPolicyDoc: &policyDoc, - trustStore: truststore.NewX509TrustStore(dir.ConfigFS()), - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDoc, + trustStore: truststore.NewX509TrustStore(dir.ConfigFS()), + pluginManager: pluginManager, + revocationClient: revocationClient, } outcome, err := verifier.Verify(context.Background(), desc, envelopeBlob, opts) if err != nil { @@ -686,12 +654,12 @@ func TestNewVerifierWithOptions(t *testing.T) { } opts := VerifierOptions{RevocationClient: r} - v, err := NewVerifierWithOptions(&ociPolicy, &blobPolicy, store, pm, opts) + v, err := NewVerifierWithOptions(&ociPolicy, store, pm, opts) if err != nil { t.Fatalf("expected NewVerifierWithOptions constructor to succeed, but got %v", err) } - if !(v.ociTrustPolicyDoc == &ociPolicy) { - t.Fatalf("expected ociTrustPolicyDoc %v, but got %v", v, v.ociTrustPolicyDoc) + if !(v.trustPolicyDoc == &ociPolicy) { + t.Fatalf("expected trustPolicyDoc %v, but got %v", v, v.trustPolicyDoc) } if !(v.trustStore == store) { t.Fatalf("expected trustStore %v, but got %v", store, v.trustStore) @@ -703,18 +671,18 @@ func TestNewVerifierWithOptions(t *testing.T) { t.Fatal("expected nonnil revocationClient") } - _, err = NewVerifierWithOptions(nil, &blobPolicy, store, pm, opts) + _, err = NewVerifierWithOptions(nil, store, pm, opts) if err != nil { t.Fatalf("expected NewVerifierWithOptions constructor to succeed, but got %v", err) } - _, err = NewVerifierWithOptions(&ociPolicy, nil, store, pm, opts) + _, err = NewVerifierWithOptions(&ociPolicy, store, pm, opts) if err != nil { t.Fatalf("expected NewVerifierWithOptions constructor to succeed, but got %v", err) } opts.RevocationClient = nil - _, err = NewVerifierWithOptions(&ociPolicy, nil, store, pm, opts) + _, err = NewVerifierWithOptions(&ociPolicy, store, pm, opts) if err != nil { t.Fatalf("expected NewVerifierWithOptions constructor to succeed, but got %v", err) } @@ -734,119 +702,17 @@ func TestNewVerifierWithOptionsError(t *testing.T) { RevocationTimestampClient: rt, } - _, err = NewVerifierWithOptions(nil, nil, store, pm, opts) - if err == nil || err.Error() != "ociTrustPolicy and blobTrustPolicy both cannot be nil" { + _, err = NewVerifierWithOptions(nil, store, pm, opts) + if err == nil || err.Error() != "trustPolicy cannot be nil" { t.Errorf("expected err but not found.") } - _, err = NewVerifierWithOptions(&ociPolicy, &blobPolicy, nil, pm, opts) + _, err = NewVerifierWithOptions(&ociPolicy, nil, pm, opts) if err == nil || err.Error() != "trustStore cannot be nil" { t.Errorf("expected err but not found.") } } -func TestVerifyBlob(t *testing.T) { - policy := &trustpolicy.BlobDocument{ - Version: "1.0", - TrustPolicies: []trustpolicy.BlobTrustPolicy{ - { - Name: "blob-test-policy", - SignatureVerification: trustpolicy.SignatureVerification{VerificationLevel: "strict"}, - TrustStores: []string{"ca:dummy-ts"}, - TrustedIdentities: []string{"*"}, - }, - }, - } - v, err := NewVerifier(nil, policy, &testTrustStore{}, pm) - if err != nil { - t.Fatalf("unexpected error while creating verifier: %v", err) - } - - opts := notation.BlobVerifierVerifyOptions{ - SignatureMediaType: jws.MediaTypeEnvelope, - TrustPolicyName: "blob-test-policy", - } - descGenFunc := getTestDescGenFunc(false, "") - - t.Run("without user defined metadata", func(t *testing.T) { - // verify with - if _, err = v.VerifyBlob(context.Background(), descGenFunc, []byte(testSig), opts); err != nil { - t.Fatalf("VerifyBlob() returned unexpected error: %v", err) - } - }) - - t.Run("with user defined metadata", func(t *testing.T) { - opts.UserMetadata = map[string]string{"buildId": "101"} - if _, err = v.VerifyBlob(context.Background(), descGenFunc, []byte(testSig), opts); err != nil { - t.Fatalf("VerifyBlob() with user metadata returned unexpected error: %v", err) - } - }) - - t.Run("trust policy set to skip", func(t *testing.T) { - policy.TrustPolicies[0].SignatureVerification = trustpolicy.SignatureVerification{VerificationLevel: "skip"} - opts.UserMetadata = map[string]string{"buildId": "101"} - if _, err = v.VerifyBlob(context.Background(), descGenFunc, []byte(testSig), opts); err != nil { - t.Fatalf("VerifyBlob() with user metadata returned unexpected error: %v", err) - } - }) -} - -func TestVerifyBlob_Error(t *testing.T) { - policy := &trustpolicy.BlobDocument{ - Version: "1.0", - TrustPolicies: []trustpolicy.BlobTrustPolicy{ - { - Name: "blob-test-policy", - SignatureVerification: trustpolicy.SignatureVerification{VerificationLevel: "strict"}, - TrustStores: []string{"ca:dummy-ts"}, - TrustedIdentities: []string{"*"}, - }, - }, - } - v, err := NewVerifier(nil, policy, &testTrustStore{}, pm) - if err != nil { - t.Fatalf("unexpected error while creating verifier: %v", err) - } - - opts := notation.BlobVerifierVerifyOptions{ - SignatureMediaType: jws.MediaTypeEnvelope, - TrustPolicyName: "blob-test-policy", - } - - t.Run("BlobDescriptorGenerator returns error", func(t *testing.T) { - descGenFunc := getTestDescGenFunc(true, "") - _, err = v.VerifyBlob(context.Background(), descGenFunc, []byte(testSig), opts) - if err == nil || err.Error() != "failed to generate descriptor for given artifact. Error: intentional test desc generation error" { - t.Errorf("VerifyBlob() didn't return error or didnt returned expected error: %v", err) - } - }) - - t.Run("descriptor mismatch returns error", func(t *testing.T) { - descGenFunc := getTestDescGenFunc(false, "sha384:b8ab24dafba5cf7e4c89c562f811cf10493d4203da982d3b1345f366ca863d9c2ed323dbd0fb7ff83a80302ceffa5a62") - _, err = v.VerifyBlob(context.Background(), descGenFunc, []byte(testSig), opts) - if err == nil || err.Error() != "integrity check failed. signature does not match the given blob" { - t.Errorf("VerifyBlob() didn't return error or didnt returned expected error: %v", err) - } - }) - - t.Run("signature malformed returns error", func(t *testing.T) { - descGenFunc := getTestDescGenFunc(false, "") - _, err = v.VerifyBlob(context.Background(), descGenFunc, []byte(""), opts) - if err == nil || err.Error() != "unable to parse the digital signature, error : unexpected end of JSON input" { - t.Errorf("VerifyBlob() didn't return error or didnt returned expected error: %v", err) - } - }) - - t.Run("user defined metadata mismatch returns error", func(t *testing.T) { - descGenFunc := getTestDescGenFunc(false, "") - opts.UserMetadata = map[string]string{"buildId": "zzz"} - _, err = v.VerifyBlob(context.Background(), descGenFunc, []byte(testSig), opts) - if err == nil || err.Error() != "unable to find specified metadata in the signature" { - t.Fatalf("VerifyBlob() with user metadata returned unexpected error: %v", err) - } - }) -} - func TestVerificationPluginInteractions(t *testing.T) { assertPluginVerification(signature.SigningSchemeX509, t) assertPluginVerification(signature.SigningSchemeX509SigningAuthority, t) @@ -873,10 +739,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { t.Fatalf("unexpected error while creating revocation object: %v", err) } v := verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: x509TrustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: x509TrustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, } opts := notation.VerifierVerifyOptions{ArtifactReference: mock.SampleArtifactUri, SignatureMediaType: "application/jose+json"} outcome, err := v.Verify(context.Background(), ocispec.Descriptor{}, pluginSigEnv, opts) @@ -889,10 +755,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { pluginManager.PluginCapabilities = []proto.Capability{proto.CapabilitySignatureGenerator} v = verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: x509TrustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: x509TrustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, } opts = notation.VerifierVerifyOptions{ArtifactReference: mock.SampleArtifactUri, SignatureMediaType: "application/jose+json"} outcome, err = v.Verify(context.Background(), ocispec.Descriptor{}, pluginSigEnv, opts) @@ -913,10 +779,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { } v = verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: x509TrustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: x509TrustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, } opts = notation.VerifierVerifyOptions{ArtifactReference: mock.SampleArtifactUri, SignatureMediaType: "application/jose+json"} outcome, err = v.Verify(context.Background(), mock.ImageDescriptor, pluginSigEnv, opts) @@ -938,10 +804,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { } v = verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: x509TrustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: x509TrustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, } opts = notation.VerifierVerifyOptions{ArtifactReference: mock.SampleArtifactUri, SignatureMediaType: "application/jose+json"} outcome, err = v.Verify(context.Background(), ocispec.Descriptor{}, pluginSigEnv, opts) @@ -962,10 +828,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { } v = verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: x509TrustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: x509TrustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, } opts = notation.VerifierVerifyOptions{ArtifactReference: mock.SampleArtifactUri, SignatureMediaType: "application/jose+json"} outcome, err = v.Verify(context.Background(), mock.ImageDescriptor, pluginSigEnv, opts) @@ -987,10 +853,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { } v = verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: x509TrustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: x509TrustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, } opts = notation.VerifierVerifyOptions{ArtifactReference: mock.SampleArtifactUri, SignatureMediaType: "application/jose+json"} outcome, err = v.Verify(context.Background(), ocispec.Descriptor{}, pluginSigEnv, opts) @@ -1014,10 +880,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { } v = verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: x509TrustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: x509TrustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, } opts = notation.VerifierVerifyOptions{ArtifactReference: mock.SampleArtifactUri, SignatureMediaType: "application/jose+json"} outcome, err = v.Verify(context.Background(), mock.ImageDescriptor, pluginSigEnv, opts) @@ -1032,10 +898,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { pluginManager.PluginRunnerExecuteError = errors.New("revocation plugin should not be invoked when the trust policy skips revocation check") v = verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: x509TrustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: x509TrustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, } opts = notation.VerifierVerifyOptions{ArtifactReference: mock.SampleArtifactUri, SignatureMediaType: "application/jose+json"} trustPolicy, err := (&policyDocument).GetApplicableTrustPolicy(opts.ArtifactReference) @@ -1059,10 +925,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { pluginManager.PluginRunnerExecuteError = errors.New("invalid plugin response") v = verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: x509TrustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: x509TrustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, } opts = notation.VerifierVerifyOptions{ArtifactReference: mock.SampleArtifactUri, SignatureMediaType: "application/jose+json"} trustPolicy, err = (&policyDocument).GetApplicableTrustPolicy(opts.ArtifactReference) @@ -1092,10 +958,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { } v = verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: x509TrustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: x509TrustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, } opts = notation.VerifierVerifyOptions{ArtifactReference: mock.SampleArtifactUri, SignatureMediaType: "application/jose+json"} outcome, err = v.Verify(context.Background(), mock.ImageDescriptor, pluginSigEnv, opts) @@ -1112,10 +978,10 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { } v = verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: x509TrustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: x509TrustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, } opts = notation.VerifierVerifyOptions{ArtifactReference: mock.SampleArtifactUri, SignatureMediaType: "application/jose+json"} outcome, err = v.Verify(context.Background(), mock.ImageDescriptor, pluginSigEnv, opts) @@ -1174,10 +1040,10 @@ func TestVerifyUserMetadata(t *testing.T) { t.Fatalf("unexpected error while creating revocation object: %v", err) } verifier := verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: truststore.NewX509TrustStore(dir.ConfigFS()), - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: truststore.NewX509TrustStore(dir.ConfigFS()), + pluginManager: pluginManager, + revocationClient: revocationClient, } tests := []struct { @@ -1243,10 +1109,10 @@ func TestPluginVersionCompatibility(t *testing.T) { t.Fatalf("unexpected error while creating revocation object: %v", err) } v := verifier{ - ociTrustPolicyDoc: &policyDocument, - trustStore: x509TrustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + trustPolicyDoc: &policyDocument, + trustStore: x509TrustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, } opts := notation.VerifierVerifyOptions{ArtifactReference: "localhost:5000/net-monitor@sha256:fe7e9333395060c2f5e63cf36a38fba10176f183b4163a5794e081a480abba5f", SignatureMediaType: "application/jose+json"} @@ -1320,32 +1186,3 @@ func verifyResult(outcome *notation.VerificationOutcome, expectedResult notation t.Fatalf("assertion failed. expected : %v got : %v", expectedErr, outcome.Error) } } - -// testTrustStore implements truststore.X509TrustStore and returns the trusted certificates for a given trust-store. -type testTrustStore struct{} - -func (ts *testTrustStore) GetCertificates(_ context.Context, _ truststore.Type, _ string) ([]*x509.Certificate, error) { - block, _ := pem.Decode([]byte(trustedCert)) - cert, _ := x509.ParseCertificate(block.Bytes) - return []*x509.Certificate{cert}, nil -} - -func getTestDescGenFunc(returnErr bool, customDigest digest.Digest) notation.BlobDescriptorGenerator { - return func(digest.Algorithm) (ocispec.Descriptor, error) { - var err error = nil - if returnErr { - err = errors.New("intentional test desc generation error") - } - - var expDigest digest.Digest = "sha384:b8ab24dafba5cf7e4c89c562f811cf10493d4203da982d3b1345f366ca863d9c2ed323dbd0fb7ff83a80302ceffa5a61" - if customDigest != "" { - expDigest = customDigest - } - - return ocispec.Descriptor{ - MediaType: "video/mp4", - Digest: expDigest, - Size: 12, - }, err - } -} From 093e9d06a9ce825b8a3eaf83d41fee6129e78ddb Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 9 Aug 2024 09:48:03 +0800 Subject: [PATCH 02/11] updated comments Signed-off-by: Patrick Zheng --- verifier/verifier.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 7dc46f03..903e8095 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -48,7 +48,7 @@ import ( ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) -// verifier implements notation.Verifier, notation.BlobVerifier and notation.verifySkipper +// verifier implements notation.Verifier and notation.verifySkipper type verifier struct { trustPolicyDoc *trustpolicy.OCIDocument trustStore truststore.X509TrustStore @@ -96,8 +96,8 @@ func NewVerifier(trustPolicy *trustpolicy.OCIDocument, trustStore truststore.X50 return NewVerifierWithOptions(trustPolicy, trustStore, pluginManager, VerifierOptions{}) } -// NewVerifierWithOptions creates a new verifier given trustPolicy, blobTrustPolicy, -// trustStore, pluginManager, and verifierOptions +// NewVerifierWithOptions creates a new verifier given trustPolicy, trustStore, +// pluginManager, and verifierOptions func NewVerifierWithOptions(trustPolicy *trustpolicy.OCIDocument, trustStore truststore.X509TrustStore, pluginManager plugin.Manager, verifierOptions VerifierOptions) (*verifier, error) { revocationClient := verifierOptions.RevocationClient if revocationClient == nil { @@ -139,6 +139,7 @@ func NewVerifierWithOptions(trustPolicy *trustpolicy.OCIDocument, trustStore tru } // NewFromConfig returns a OCI verifier based on local file system +// // Deprecated: NewFromConfig function exists for historical compatibility and should not be used. // To create an OCI verifier, use NewOCIVerifierFromConfig function. func NewFromConfig() (notation.Verifier, error) { @@ -146,6 +147,7 @@ func NewFromConfig() (notation.Verifier, error) { } // New creates a new verifier given trustPolicy, trustStore and pluginManager +// // Deprecated: New function exists for historical compatibility and should not be used. // To create verifier, use NewVerifier function. func New(trustPolicy *trustpolicy.OCIDocument, trustStore truststore.X509TrustStore, pluginManager plugin.Manager) (notation.Verifier, error) { From ea2eacc4403fe1d987355b6fd9cb55f2373d5bee Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 14 Aug 2024 10:28:57 +0800 Subject: [PATCH 03/11] update for v1.2.0-rc.1 release Signed-off-by: Patrick Zheng --- dir/path.go | 1 + plugin/plugin.go | 4 ++++ signer/plugin.go | 1 + signer/signer.go | 1 + verifier/trustpolicy/oci.go | 3 +++ 5 files changed, 10 insertions(+) diff --git a/dir/path.go b/dir/path.go index 28c1db4a..2f1110e9 100644 --- a/dir/path.go +++ b/dir/path.go @@ -58,6 +58,7 @@ const ( // PathSigningKeys is the signingkeys file relative path. PathSigningKeys = "signingkeys.json" // PathTrustPolicy is the OCI trust policy file relative path. + // // Deprecated: PathTrustPolicy exists for historical compatibility and should not be used. // To get OCI trust policy path, use PathOCITrustPolicy. PathTrustPolicy = "trustpolicy.json" diff --git a/plugin/plugin.go b/plugin/plugin.go index 8b8959a3..e4579d85 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -36,21 +36,25 @@ import ( var executor commander = &execCommander{} // for unit test // GenericPlugin is the base requirement to be a plugin. +// // Deprecated: GenericPlugin exists for historical compatibility and should not be used. // To access GenericPlugin, use the notation-plugin-framework-go's plugin.GenericPlugin type. type GenericPlugin = plugin.GenericPlugin // SignPlugin defines the required methods to be a SignPlugin. +// // Deprecated: SignPlugin exists for historical compatibility and should not be used. // To access SignPlugin, use the notation-plugin-framework-go's plugin.SignPlugin type. type SignPlugin = plugin.SignPlugin // VerifyPlugin defines the required method to be a VerifyPlugin. +// // Deprecated: VerifyPlugin exists for historical compatibility and should not be used. // To access VerifyPlugin, use the notation-plugin-framework-go's plugin.VerifyPlugin type. type VerifyPlugin = plugin.VerifyPlugin // Plugin defines required methods to be a Plugin. +// // Deprecated: Plugin exists for historical compatibility and should not be used. // To access Plugin, use the notation-plugin-framework-go's plugin.Plugin type. type Plugin = plugin.Plugin diff --git a/signer/plugin.go b/signer/plugin.go index 5768f7b1..1fd13afa 100644 --- a/signer/plugin.go +++ b/signer/plugin.go @@ -44,6 +44,7 @@ type PluginSigner struct { // NewFromPlugin creates a notation.Signer 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) { diff --git a/signer/signer.go b/signer/signer.go index fe710942..ff2f83e7 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -42,6 +42,7 @@ type GenericSigner struct { } // New returns a builtinSigner 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) { diff --git a/verifier/trustpolicy/oci.go b/verifier/trustpolicy/oci.go index 1203d2b8..74157dd2 100644 --- a/verifier/trustpolicy/oci.go +++ b/verifier/trustpolicy/oci.go @@ -53,16 +53,19 @@ type OCITrustPolicy struct { } // Document represents a trustPolicy.json document +// // Deprecated: Document exists for historical compatibility and should not be used. // To create OCI Document, use OCIDocument. type Document = OCIDocument // TrustPolicy represents a policy statement in the policy document +// // Deprecated: TrustPolicy exists for historical compatibility and should not be used. // To create OCI TrustPolicy, use OCITrustPolicy. type TrustPolicy = OCITrustPolicy // LoadDocument loads a trust policy document from a local file system +// // Deprecated: LoadDocument function exists for historical compatibility and should not be used. // To load OCI Document, use LoadOCIDocument function. var LoadDocument = LoadOCIDocument From fc35e626e87f657c66090a81fe1b2261db5397c4 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 14 Aug 2024 10:42:21 +0800 Subject: [PATCH 04/11] update for v1.2.0-rc.1 release Signed-off-by: Patrick Zheng --- verifier/verifier_test.go | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/verifier/verifier_test.go b/verifier/verifier_test.go index e1502ff2..2a6cd07e 100644 --- a/verifier/verifier_test.go +++ b/verifier/verifier_test.go @@ -57,6 +57,21 @@ func TestNewVerifier_Error(t *testing.T) { } } +func TestNewFromConfig(t *testing.T) { + _, err := NewFromConfig() + if err != nil { + t.Fatal(err) + } + + tempRoot := t.TempDir() + dir.UserConfigDir = tempRoot + expectedErrMsg := "trust policy is not present. To create a trust policy, see: https://notaryproject.dev/docs/quickstart/#create-a-trust-policy" + _, err = NewFromConfig() + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } +} + func TestInvalidArtifactUriValidations(t *testing.T) { verifier := verifier{ trustPolicyDoc: &ociPolicy, From d52b619525d2b6de741b7bccb12fa83e76fb5494 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 14 Aug 2024 10:59:53 +0800 Subject: [PATCH 05/11] update for v1.2.0-rc.1 release Signed-off-by: Patrick Zheng --- dir/path.go | 9 +-------- verifier/trustpolicy/oci.go | 15 +-------------- verifier/trustpolicy/oci_test.go | 2 +- verifier/verifier_test.go | 20 ++++++++++++++------ 4 files changed, 17 insertions(+), 29 deletions(-) diff --git a/dir/path.go b/dir/path.go index 2f1110e9..37aafe56 100644 --- a/dir/path.go +++ b/dir/path.go @@ -57,15 +57,8 @@ const ( PathConfigFile = "config.json" // PathSigningKeys is the signingkeys file relative path. PathSigningKeys = "signingkeys.json" - // PathTrustPolicy is the OCI trust policy file relative path. - // - // Deprecated: PathTrustPolicy exists for historical compatibility and should not be used. - // To get OCI trust policy path, use PathOCITrustPolicy. + // PathTrustPolicy is the trust policy file relative path. PathTrustPolicy = "trustpolicy.json" - // PathOCITrustPolicy is the OCI trust policy file relative path. - PathOCITrustPolicy = "trustpolicy.oci.json" - // PathBlobTrustPolicy is the Blob trust policy file relative path. - PathBlobTrustPolicy = "trustpolicy.blob.json" // PathPlugins is the plugins directory relative path. PathPlugins = "plugins" // LocalKeysDir is the directory name for local key relative path. diff --git a/verifier/trustpolicy/oci.go b/verifier/trustpolicy/oci.go index 74157dd2..e236171a 100644 --- a/verifier/trustpolicy/oci.go +++ b/verifier/trustpolicy/oci.go @@ -73,24 +73,11 @@ var LoadDocument = LoadOCIDocument var supportedOCIPolicyVersions = []string{"1.0"} // LoadOCIDocument retrieves a trust policy document from the local file system. -// It attempts to read from dir.PathOCITrustPolicy first; if not found, it tries dir.PathTrustPolicy. -// If both dir.PathOCITrustPolicy and dir.PathTrustPolicy exist, dir.PathOCITrustPolicy will be read. func LoadOCIDocument() (*OCIDocument, error) { - var doc OCIDocument - // attempt to load the document from dir.PathOCITrustPolicy - if err := getDocument(dir.PathOCITrustPolicy, &doc); err != nil { - // if the document is not found at the first path, try the second path - if errors.As(err, &errPolicyNotExist{}) { - if err := getDocument(dir.PathTrustPolicy, &doc); err != nil { - return nil, err - } - return &doc, nil - } - // if an error occurred other than the document not found, return it + if err := getDocument(dir.PathTrustPolicy, &doc); err != nil { return nil, err } - return &doc, nil } diff --git a/verifier/trustpolicy/oci_test.go b/verifier/trustpolicy/oci_test.go index e0d6beb5..d72ff9f7 100644 --- a/verifier/trustpolicy/oci_test.go +++ b/verifier/trustpolicy/oci_test.go @@ -41,7 +41,7 @@ func TestLoadOCIDocumentFromOldFileLocation(t *testing.T) { func TestLoadOCIDocumentFromNewFileLocation(t *testing.T) { tempRoot := t.TempDir() dir.UserConfigDir = tempRoot - path := filepath.Join(tempRoot, "trustpolicy.oci.json") + path := filepath.Join(tempRoot, "trustpolicy.json") policyJson, _ := json.Marshal(dummyOCIPolicyDocument()) if err := os.WriteFile(path, policyJson, 0600); err != nil { t.Fatalf("TestLoadOCIDocument write policy file failed. Error: %v", err) diff --git a/verifier/verifier_test.go b/verifier/verifier_test.go index 2a6cd07e..089091c3 100644 --- a/verifier/verifier_test.go +++ b/verifier/verifier_test.go @@ -16,9 +16,11 @@ package verifier import ( "context" "crypto/x509" + "encoding/json" "errors" "fmt" "net/http" + "os" "path/filepath" "strconv" "testing" @@ -58,18 +60,24 @@ func TestNewVerifier_Error(t *testing.T) { } func TestNewFromConfig(t *testing.T) { - _, err := NewFromConfig() - if err != nil { - t.Fatal(err) - } - tempRoot := t.TempDir() dir.UserConfigDir = tempRoot expectedErrMsg := "trust policy is not present. To create a trust policy, see: https://notaryproject.dev/docs/quickstart/#create-a-trust-policy" - _, err = NewFromConfig() + _, err := NewFromConfig() if err == nil || err.Error() != expectedErrMsg { t.Fatalf("expected %s, but got %s", expectedErrMsg, err) } + + path := filepath.Join(tempRoot, "trustpolicy.json") + policyJson, _ := json.Marshal(dummyOCIPolicyDocument()) + if err := os.WriteFile(path, policyJson, 0600); err != nil { + t.Fatal(err) + } + t.Cleanup(func() { os.RemoveAll(tempRoot) }) + _, err = NewFromConfig() + if err != nil { + t.Fatal(err) + } } func TestInvalidArtifactUriValidations(t *testing.T) { From 25744605bc773c296ff227bab26e8ab02f2f05e7 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 14 Aug 2024 15:08:02 +0800 Subject: [PATCH 06/11] update for v1.2.0-rc.1 release Signed-off-by: Patrick Zheng --- notation_test.go | 2 +- verifier/helpers_test.go | 14 +++---- verifier/trustpolicy/oci.go | 48 ++++++++---------------- verifier/trustpolicy/oci_test.go | 20 +++++----- verifier/trustpolicy/trustpolicy_test.go | 16 ++++---- verifier/verifier.go | 8 ++-- verifier/verifier_test.go | 40 ++++++++++---------- 7 files changed, 65 insertions(+), 83 deletions(-) diff --git a/notation_test.go b/notation_test.go index 6e31a31d..64fbe07a 100644 --- a/notation_test.go +++ b/notation_test.go @@ -490,7 +490,7 @@ func (s *verifyMetadataSigner) Sign(_ context.Context, desc ocispec.Descriptor, } type dummyVerifier struct { - TrustPolicyDoc *trustpolicy.OCIDocument + TrustPolicyDoc *trustpolicy.Document PluginManager plugin.Manager FailVerify bool VerificationLevel trustpolicy.VerificationLevel diff --git a/verifier/helpers_test.go b/verifier/helpers_test.go index fea0c65e..c1f445e6 100644 --- a/verifier/helpers_test.go +++ b/verifier/helpers_test.go @@ -60,7 +60,7 @@ func TestLoadX509TrustStore(t *testing.T) { // load "ca" and "signingAuthority" trust store caStore := "ca:valid-trust-store" signingAuthorityStore := "signingAuthority:valid-trust-store" - dummyPolicy := dummyOCIPolicyDocument().TrustPolicies[0] + dummyPolicy := dummyPolicyDocument().TrustPolicies[0] dummyPolicy.TrustStores = []string{caStore, signingAuthorityStore} dir.UserConfigDir = "testdata" x509truststore := truststore.NewX509TrustStore(dir.ConfigFS()) @@ -138,10 +138,10 @@ func getArtifactDigestFromReference(artifactReference string) (string, error) { return artifactReference[i+1:], nil } -func dummyOCIPolicyDocument() (policyDoc trustpolicy.OCIDocument) { - return trustpolicy.OCIDocument{ +func dummyPolicyDocument() (policyDoc trustpolicy.Document) { + return trustpolicy.Document{ Version: "1.0", - TrustPolicies: []trustpolicy.OCITrustPolicy{ + TrustPolicies: []trustpolicy.TrustPolicy{ { Name: "test-statement-name", RegistryScopes: []string{"registry.acme-rockets.io/software/net-monitor"}, @@ -153,9 +153,9 @@ func dummyOCIPolicyDocument() (policyDoc trustpolicy.OCIDocument) { } } -func dummyInvalidOCIPolicyDocument() (policyDoc trustpolicy.OCIDocument) { - return trustpolicy.OCIDocument{ - TrustPolicies: []trustpolicy.OCITrustPolicy{ +func dummyInvalidPolicyDocument() (policyDoc trustpolicy.Document) { + return trustpolicy.Document{ + TrustPolicies: []trustpolicy.TrustPolicy{ { Name: "invalid", }, diff --git a/verifier/trustpolicy/oci.go b/verifier/trustpolicy/oci.go index e236171a..78c846a4 100644 --- a/verifier/trustpolicy/oci.go +++ b/verifier/trustpolicy/oci.go @@ -25,17 +25,17 @@ import ( "github.com/notaryproject/notation-go/internal/trustpolicy" ) -// OCIDocument represents a trustPolicy.json document for OCI artifacts -type OCIDocument struct { +// Document represents a trustpolicy.json document +type Document struct { // Version of the policy document Version string `json:"version"` // TrustPolicies include each policy statement - TrustPolicies []OCITrustPolicy `json:"trustPolicies"` + TrustPolicies []TrustPolicy `json:"trustPolicies"` } -// OCITrustPolicy represents a policy statement in the policy document for OCI artifacts -type OCITrustPolicy struct { +// TrustPolicy represents a policy statement in the policy document +type TrustPolicy struct { // Name of the policy statement Name string `json:"name"` @@ -52,29 +52,11 @@ type OCITrustPolicy struct { RegistryScopes []string `json:"registryScopes"` } -// Document represents a trustPolicy.json document -// -// Deprecated: Document exists for historical compatibility and should not be used. -// To create OCI Document, use OCIDocument. -type Document = OCIDocument - -// TrustPolicy represents a policy statement in the policy document -// -// Deprecated: TrustPolicy exists for historical compatibility and should not be used. -// To create OCI TrustPolicy, use OCITrustPolicy. -type TrustPolicy = OCITrustPolicy - -// LoadDocument loads a trust policy document from a local file system -// -// Deprecated: LoadDocument function exists for historical compatibility and should not be used. -// To load OCI Document, use LoadOCIDocument function. -var LoadDocument = LoadOCIDocument - var supportedOCIPolicyVersions = []string{"1.0"} -// LoadOCIDocument retrieves a trust policy document from the local file system. -func LoadOCIDocument() (*OCIDocument, error) { - var doc OCIDocument +// LoadDocument retrieves a trust policy document from the local file system. +func LoadDocument() (*Document, error) { + var doc Document if err := getDocument(dir.PathTrustPolicy, &doc); err != nil { return nil, err } @@ -83,7 +65,7 @@ func LoadOCIDocument() (*OCIDocument, error) { // Validate validates a policy document according to its version's rule set. // if any rule is violated, returns an error -func (policyDoc *OCIDocument) Validate() error { +func (policyDoc *Document) Validate() error { // sanity check if policyDoc == nil { return errors.New("oci trust policy document cannot be nil") @@ -128,14 +110,14 @@ func (policyDoc *OCIDocument) Validate() error { // statement that applies to the given registry scope. If no applicable trust // policy is found, returns an error // see https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/trust-store-trust-policy.md#selecting-a-trust-policy-based-on-artifact-uri -func (policyDoc *OCIDocument) GetApplicableTrustPolicy(artifactReference string) (*OCITrustPolicy, error) { +func (policyDoc *Document) GetApplicableTrustPolicy(artifactReference string) (*TrustPolicy, error) { artifactPath, err := getArtifactPathFromReference(artifactReference) if err != nil { return nil, err } - var wildcardPolicy *OCITrustPolicy - var applicablePolicy *OCITrustPolicy + var wildcardPolicy *TrustPolicy + var applicablePolicy *TrustPolicy for _, policyStatement := range policyDoc.TrustPolicies { if slices.Contains(policyStatement.RegistryScopes, trustpolicy.Wildcard) { // we need to deep copy because we can't use the loop variable @@ -158,8 +140,8 @@ func (policyDoc *OCIDocument) GetApplicableTrustPolicy(artifactReference string) } // clone returns a pointer to the deeply copied TrustPolicy -func (t *OCITrustPolicy) clone() *OCITrustPolicy { - return &OCITrustPolicy{ +func (t *TrustPolicy) clone() *TrustPolicy { + return &TrustPolicy{ Name: t.Name, SignatureVerification: t.SignatureVerification, TrustedIdentities: append([]string(nil), t.TrustedIdentities...), @@ -170,7 +152,7 @@ func (t *OCITrustPolicy) clone() *OCITrustPolicy { // validateRegistryScopes validates if the policy document is following the // Notary Project spec rules for registry scopes -func validateRegistryScopes(policyDoc *OCIDocument) error { +func validateRegistryScopes(policyDoc *Document) error { registryScopeCount := make(map[string]int) for _, statement := range policyDoc.TrustPolicies { // Verify registry scopes are valid diff --git a/verifier/trustpolicy/oci_test.go b/verifier/trustpolicy/oci_test.go index d72ff9f7..541bb26a 100644 --- a/verifier/trustpolicy/oci_test.go +++ b/verifier/trustpolicy/oci_test.go @@ -33,7 +33,7 @@ func TestLoadOCIDocumentFromOldFileLocation(t *testing.T) { } t.Cleanup(func() { os.RemoveAll(tempRoot) }) - if _, err := LoadOCIDocument(); err != nil { + if _, err := LoadDocument(); err != nil { t.Fatalf("LoadOCIDocument() should not throw error for an existing policy file. Error: %v", err) } } @@ -48,7 +48,7 @@ func TestLoadOCIDocumentFromNewFileLocation(t *testing.T) { } t.Cleanup(func() { os.RemoveAll(tempRoot) }) - if _, err := LoadOCIDocument(); err != nil { + if _, err := LoadDocument(); err != nil { t.Fatalf("LoadOCIDocument() should not throw error for an existing policy file. Error: %v", err) } } @@ -56,7 +56,7 @@ func TestLoadOCIDocumentFromNewFileLocation(t *testing.T) { func TestLoadOCIDocumentError(t *testing.T) { tempRoot := t.TempDir() dir.UserConfigDir = tempRoot - if _, err := LoadOCIDocument(); err == nil { + if _, err := LoadDocument(); err == nil { t.Fatalf("LoadOCIDocument() should throw error if OCI trust policy is not found") } } @@ -72,7 +72,7 @@ func TestApplicableTrustPolicy(t *testing.T) { policyStatement.RegistryScopes = []string{registryScope} policyStatement.SignatureVerification = SignatureVerification{VerificationLevel: "strict"} - policyDoc.TrustPolicies = []OCITrustPolicy{ + policyDoc.TrustPolicies = []TrustPolicy{ policyStatement, } // existing Registry Scope @@ -88,7 +88,7 @@ func TestApplicableTrustPolicy(t *testing.T) { } // wildcard registry scope - wildcardStatement := OCITrustPolicy{ + wildcardStatement := TrustPolicy{ Name: "test-statement-name-2", SignatureVerification: SignatureVerification{VerificationLevel: "skip"}, TrustStores: []string{}, @@ -96,7 +96,7 @@ func TestApplicableTrustPolicy(t *testing.T) { RegistryScopes: []string{"*"}, } - policyDoc.TrustPolicies = []OCITrustPolicy{ + policyDoc.TrustPolicies = []TrustPolicy{ policyStatement, wildcardStatement, } @@ -110,7 +110,7 @@ func TestApplicableTrustPolicy(t *testing.T) { // and tests various validations on policy elements func TestValidateInvalidPolicyDocument(t *testing.T) { // Sanity check - var nilPolicyDoc *OCIDocument + var nilPolicyDoc *Document err := nilPolicyDoc.Validate() if err == nil || err.Error() != "oci trust policy document cannot be nil" { t.Fatalf("nil policyDoc should return error") @@ -153,7 +153,7 @@ func TestValidateInvalidPolicyDocument(t *testing.T) { policyStatement1 := policyDoc.TrustPolicies[0].clone() policyStatement2 := policyDoc.TrustPolicies[0].clone() policyStatement2.Name = "test-statement-name-2" - policyDoc.TrustPolicies = []OCITrustPolicy{*policyStatement1, *policyStatement2} + policyDoc.TrustPolicies = []TrustPolicy{*policyStatement1, *policyStatement2} err = policyDoc.Validate() if err == nil || err.Error() != "registry scope \"registry.acme-rockets.io/software/net-monitor\" is present in multiple oci trust policy statements, one registry scope value can only be associated with one statement" { t.Fatalf("Policy statements with same registry scope should return error %q", err) @@ -279,7 +279,7 @@ func TestValidateInvalidPolicyDocument(t *testing.T) { policyStatement1 = policyDoc.TrustPolicies[0].clone() policyStatement2 = policyDoc.TrustPolicies[0].clone() policyStatement2.RegistryScopes = []string{"registry.acme-rockets.io/software/legacy/metrics"} - policyDoc.TrustPolicies = []OCITrustPolicy{*policyStatement1, *policyStatement2} + policyDoc.TrustPolicies = []TrustPolicy{*policyStatement1, *policyStatement2} err = policyDoc.Validate() if err == nil || err.Error() != "multiple oci trust policy statements use the same name \"test-statement-name\", statement names must be unique" { t.Fatalf("policy statements with same name should return error") @@ -376,7 +376,7 @@ func TestValidateValidPolicyDocument(t *testing.T) { policyStatement8.RegistryScopes = []string{"registry.acme-rockets.io/software/net-monitor8"} policyStatement8.SignatureVerification.VerifyTimestamp = OptionAfterCertExpiry - policyDoc.TrustPolicies = []OCITrustPolicy{ + policyDoc.TrustPolicies = []TrustPolicy{ *policyStatement1, *policyStatement2, *policyStatement3, diff --git a/verifier/trustpolicy/trustpolicy_test.go b/verifier/trustpolicy/trustpolicy_test.go index 96b758e1..ff948621 100644 --- a/verifier/trustpolicy/trustpolicy_test.go +++ b/verifier/trustpolicy/trustpolicy_test.go @@ -26,10 +26,10 @@ import ( "github.com/notaryproject/notation-go/dir" ) -func dummyOCIPolicyDocument() OCIDocument { - return OCIDocument{ +func dummyOCIPolicyDocument() Document { + return Document{ Version: "1.0", - TrustPolicies: []OCITrustPolicy{ + TrustPolicies: []TrustPolicy{ { Name: "test-statement-name", RegistryScopes: []string{"registry.acme-rockets.io/software/net-monitor"}, @@ -292,7 +292,7 @@ func TestGetDocument(t *testing.T) { t.Skip("skipping test on Windows") } dir.UserConfigDir = "/" - var ociDoc OCIDocument + var ociDoc Document tests := []struct { name string expectedDocument any @@ -325,7 +325,7 @@ func TestGetDocument(t *testing.T) { func TestGetDocumentErrors(t *testing.T) { dir.UserConfigDir = "/" t.Run("non-existing policy file", func(t *testing.T) { - var doc OCIDocument + var doc Document if err := getDocument("blaah", &doc); err == nil || err.Error() != fmt.Sprintf("trust policy is not present. To create a trust policy, see: %s", trustPolicyLink) { t.Fatalf("getDocument() should throw error for non existent policy") } @@ -342,7 +342,7 @@ func TestGetDocumentErrors(t *testing.T) { } t.Cleanup(func() { os.RemoveAll(tempRoot) }) - var doc OCIDocument + var doc Document if err := getDocument(path, &doc); err == nil || err.Error() != fmt.Sprintf("malformed trust policy. To create a trust policy, see: %s", trustPolicyLink) { t.Fatalf("getDocument() should throw error for invalid policy file. Error: %v", err) } @@ -359,7 +359,7 @@ func TestGetDocumentErrors(t *testing.T) { t.Fatalf("creation of invalid permission policy file failed. Error: %v", err) } expectedErrMsg := fmt.Sprintf("unable to read trust policy due to file permissions, please verify the permissions of %s", path) - var doc OCIDocument + var doc Document if err := getDocument(path, &doc); err == nil || err.Error() != expectedErrMsg { t.Errorf("getDocument() should throw error for a policy file with bad permissions. "+ "Expected error: '%v'qq but found '%v'", expectedErrMsg, err.Error()) @@ -380,7 +380,7 @@ func TestGetDocumentErrors(t *testing.T) { if err := os.Symlink(path, symlinkPath); err != nil { t.Fatalf("creation of symlink for policy file failed. Error: %v", err) } - var doc OCIDocument + var doc Document if err := getDocument(symlinkPath, &doc); err == nil || !strings.HasPrefix(err.Error(), "trust policy is not a regular file (symlinks are not supported)") { t.Fatalf("getDocument() should throw error for a symlink policy file. Error: %v", err) } diff --git a/verifier/verifier.go b/verifier/verifier.go index 2c1e3f7d..4570bb90 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -51,7 +51,7 @@ import ( // verifier implements notation.Verifier and notation.verifySkipper type verifier struct { - trustPolicyDoc *trustpolicy.OCIDocument + trustPolicyDoc *trustpolicy.Document trustStore truststore.X509TrustStore pluginManager plugin.Manager revocationClient revocation.Revocation @@ -82,7 +82,7 @@ type VerifierOptions struct { // NewFromConfig returns a verifier based on local file system. func NewFromConfig() (notation.Verifier, error) { // load trust policy - policyDocument, err := trustpolicy.LoadOCIDocument() + policyDocument, err := trustpolicy.LoadDocument() if err != nil { return nil, err } @@ -93,13 +93,13 @@ func NewFromConfig() (notation.Verifier, error) { } // New creates a new verifier given trustPolicy, trustStore and pluginManager -func New(trustPolicy *trustpolicy.OCIDocument, trustStore truststore.X509TrustStore, pluginManager plugin.Manager) (notation.Verifier, error) { +func New(trustPolicy *trustpolicy.Document, trustStore truststore.X509TrustStore, pluginManager plugin.Manager) (notation.Verifier, error) { return NewWithOptions(trustPolicy, trustStore, pluginManager, VerifierOptions{}) } // NewWithOptions creates a new verifier given trustPolicy, trustStore, // pluginManager, and verifierOptions -func NewWithOptions(trustPolicy *trustpolicy.OCIDocument, trustStore truststore.X509TrustStore, pluginManager plugin.Manager, verifierOptions VerifierOptions) (notation.Verifier, error) { +func NewWithOptions(trustPolicy *trustpolicy.Document, trustStore truststore.X509TrustStore, pluginManager plugin.Manager, verifierOptions VerifierOptions) (notation.Verifier, error) { if trustStore == nil { return nil, errors.New("trustStore cannot be nil") } diff --git a/verifier/verifier_test.go b/verifier/verifier_test.go index 089091c3..39793c56 100644 --- a/verifier/verifier_test.go +++ b/verifier/verifier_test.go @@ -45,13 +45,13 @@ import ( ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) -var ociPolicy = dummyOCIPolicyDocument() -var invalidPolicy = dummyInvalidOCIPolicyDocument() +var ociPolicy = dummyPolicyDocument() +var invalidPolicy = dummyInvalidPolicyDocument() var store = truststore.NewX509TrustStore(dir.ConfigFS()) var pm = mock.PluginManager{} func TestNewVerifier_Error(t *testing.T) { - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() _, err := New(&policyDocument, nil, nil) expectedErr := errors.New("trustStore cannot be nil") if err == nil || err.Error() != expectedErr.Error() { @@ -69,7 +69,7 @@ func TestNewFromConfig(t *testing.T) { } path := filepath.Join(tempRoot, "trustpolicy.json") - policyJson, _ := json.Marshal(dummyOCIPolicyDocument()) + policyJson, _ := json.Marshal(dummyPolicyDocument()) if err := os.WriteFile(path, policyJson, 0600); err != nil { t.Fatal(err) } @@ -157,7 +157,7 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) { // Unsupported Signature Envelope for _, level := range verificationLevels { - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() expectedErr := fmt.Errorf("unable to parse the digital signature, error : signature envelope format with media type \"application/unsupported+json\" is not supported") testCases = append(testCases, testCase{ verificationType: trustpolicy.TypeIntegrity, @@ -170,7 +170,7 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) { // Integrity Success for _, level := range verificationLevels { - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() testCases = append(testCases, testCase{ signatureBlob: validSigEnv, verificationType: trustpolicy.TypeIntegrity, @@ -182,7 +182,7 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) { // Integrity Failure for _, level := range verificationLevels { - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() expectedErr := fmt.Errorf("signature is invalid. Error: illegal base64 data at input byte 242") testCases = append(testCases, testCase{ signatureBlob: invalidSigEnv, @@ -196,7 +196,7 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) { // Authenticity Success for _, level := range verificationLevels { - policyDocument := dummyOCIPolicyDocument() // trust store is configured with the root certificate of the signature by default + policyDocument := dummyPolicyDocument() // trust store is configured with the root certificate of the signature by default testCases = append(testCases, testCase{ signatureBlob: validSigEnv, verificationType: trustpolicy.TypeAuthenticity, @@ -208,7 +208,7 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) { // Authenticity Failure for _, level := range verificationLevels { - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() policyDocument.TrustPolicies[0].TrustStores = []string{"ca:valid-trust-store-2", "signingAuthority:valid-trust-store-2"} // trust store is not configured with the root certificate of the signature expectedErr := fmt.Errorf("signature is not produced by a trusted signer") testCases = append(testCases, testCase{ @@ -223,7 +223,7 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) { // Authenticity Failure with trust store missing separator for _, level := range verificationLevels { - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() policyDocument.TrustPolicies[0].TrustStores = []string{"ca:valid-trust-store-2", "signingAuthority"} expectedErr := fmt.Errorf("error while loading the trust store, trust policy statement \"test-statement-name\" is missing separator in trust store value \"signingAuthority\". The required format is :") testCases = append(testCases, testCase{ @@ -238,7 +238,7 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) { // TrustedIdentity Failure for _, level := range verificationLevels { - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() policyDocument.TrustPolicies[0].TrustedIdentities = []string{"x509.subject:CN=LOL,O=DummyOrg,L=Hyderabad,ST=TG,C=IN"} // configure policy to not trust "CN=Notation Test Leaf Cert,O=Notary,L=Seattle,ST=WA,C=US" which is the subject of the signature's signing certificate expectedErr := fmt.Errorf("signing certificate from the digital signature does not match the X.509 trusted identities [map[\"C\":\"IN\" \"CN\":\"LOL\" \"L\":\"Hyderabad\" \"O\":\"DummyOrg\" \"ST\":\"TG\"]] defined in the trust policy \"test-statement-name\"") testCases = append(testCases, testCase{ @@ -253,7 +253,7 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) { // TrustedIdentity Failure without separator for _, level := range verificationLevels { - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() policyDocument.TrustPolicies[0].TrustedIdentities = []string{"x509.subject"} expectedErr := fmt.Errorf("trust policy statement \"test-statement-name\" has trusted identity \"x509.subject\" missing separator") testCases = append(testCases, testCase{ @@ -268,7 +268,7 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) { // TrustedIdentity Failure with empty value for _, level := range verificationLevels { - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() policyDocument.TrustPolicies[0].TrustedIdentities = []string{"x509.subject:"} expectedErr := fmt.Errorf("trust policy statement \"test-statement-name\" has trusted identity \"x509.subject:\" without an identity value") testCases = append(testCases, testCase{ @@ -283,7 +283,7 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) { // Expiry Success for _, level := range verificationLevels { - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() testCases = append(testCases, testCase{ signatureBlob: validSigEnv, verificationType: trustpolicy.TypeExpiry, @@ -295,7 +295,7 @@ func assertNotationVerification(t *testing.T, scheme signature.SigningScheme) { // Expiry Failure for _, level := range verificationLevels { - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() expectedErr := fmt.Errorf("digital signature has expired on \"Fri, 29 Jul 2022 23:59:00 +0000\"") testCases = append(testCases, testCase{ signatureBlob: expiredSigEnv, @@ -378,7 +378,7 @@ func TestVerifyRevocationEnvelope(t *testing.T) { t.Run("enforced revoked cert", func(t *testing.T) { testedLevel := trustpolicy.LevelStrict - policyDoc := dummyOCIPolicyDocument() + policyDoc := dummyPolicyDocument() policyDoc.TrustPolicies[0].SignatureVerification.VerificationLevel = testedLevel.Name policyDoc.TrustPolicies[0].SignatureVerification.Override = map[trustpolicy.ValidationType]trustpolicy.ValidationAction{ trustpolicy.TypeAuthenticity: trustpolicy.ActionLog, @@ -407,7 +407,7 @@ func TestVerifyRevocationEnvelope(t *testing.T) { }) t.Run("log revoked cert", func(t *testing.T) { testedLevel := trustpolicy.LevelStrict - policyDoc := dummyOCIPolicyDocument() + policyDoc := dummyPolicyDocument() policyDoc.TrustPolicies[0].SignatureVerification.VerificationLevel = testedLevel.Name policyDoc.TrustPolicies[0].SignatureVerification.Override = map[trustpolicy.ValidationType]trustpolicy.ValidationAction{ trustpolicy.TypeAuthenticity: trustpolicy.ActionLog, @@ -437,7 +437,7 @@ func TestVerifyRevocationEnvelope(t *testing.T) { }) t.Run("skip revoked cert", func(t *testing.T) { testedLevel := trustpolicy.LevelStrict - policyDoc := dummyOCIPolicyDocument() + policyDoc := dummyPolicyDocument() policyDoc.TrustPolicies[0].SignatureVerification.VerificationLevel = testedLevel.Name policyDoc.TrustPolicies[0].SignatureVerification.Override = map[trustpolicy.ValidationType]trustpolicy.ValidationAction{ trustpolicy.TypeAuthenticity: trustpolicy.ActionLog, @@ -797,7 +797,7 @@ func assertPluginVerification(scheme signature.SigningScheme, t *testing.T) { pluginSigEnv = mock.MockSaPluginSigEnv } - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() dir.UserConfigDir = "testdata" x509TrustStore := truststore.NewX509TrustStore(dir.ConfigFS()) @@ -1100,7 +1100,7 @@ func TestVerifyX509TrustedIdentities(t *testing.T) { } func TestVerifyUserMetadata(t *testing.T) { - policyDocument := dummyOCIPolicyDocument() + policyDocument := dummyPolicyDocument() policyDocument.TrustPolicies[0].SignatureVerification.VerificationLevel = trustpolicy.LevelAudit.Name pluginManager := mock.PluginManager{} From 6702623e4a068145986532b364b9ddc840d34216 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 14 Aug 2024 15:19:43 +0800 Subject: [PATCH 07/11] update for v1.2.0-rc.1 release Signed-off-by: Patrick Zheng --- verifier/trustpolicy/oci.go | 24 ++--- verifier/trustpolicy/oci_test.go | 117 ++++++++++------------- verifier/trustpolicy/trustpolicy_test.go | 10 +- verifier/verifier_test.go | 22 ++--- 4 files changed, 79 insertions(+), 94 deletions(-) diff --git a/verifier/trustpolicy/oci.go b/verifier/trustpolicy/oci.go index 78c846a4..f04c9d3e 100644 --- a/verifier/trustpolicy/oci.go +++ b/verifier/trustpolicy/oci.go @@ -52,7 +52,7 @@ type TrustPolicy struct { RegistryScopes []string `json:"registryScopes"` } -var supportedOCIPolicyVersions = []string{"1.0"} +var supportedPolicyVersions = []string{"1.0"} // LoadDocument retrieves a trust policy document from the local file system. func LoadDocument() (*Document, error) { @@ -68,31 +68,31 @@ func LoadDocument() (*Document, error) { func (policyDoc *Document) Validate() error { // sanity check if policyDoc == nil { - return errors.New("oci trust policy document cannot be nil") + return errors.New("trust policy document cannot be nil") } // Validate Version if policyDoc.Version == "" { - return errors.New("oci trust policy document has empty version, version must be specified") + return errors.New("trust policy document has empty version, version must be specified") } - if !slices.Contains(supportedOCIPolicyVersions, policyDoc.Version) { - return fmt.Errorf("oci trust policy document uses unsupported version %q", policyDoc.Version) + if !slices.Contains(supportedPolicyVersions, policyDoc.Version) { + return fmt.Errorf("trust policy document uses unsupported version %q", policyDoc.Version) } // Validate the policy according to 1.0 rules if len(policyDoc.TrustPolicies) == 0 { - return errors.New("oci trust policy document can not have zero trust policy statements") + return errors.New("trust policy document can not have zero trust policy statements") } policyNames := set.New[string]() for _, statement := range policyDoc.TrustPolicies { // Verify unique policy statement names across the policy document if policyNames.Contains(statement.Name) { - return fmt.Errorf("multiple oci trust policy statements use the same name %q, statement names must be unique", statement.Name) + return fmt.Errorf("multiple trust policy statements use the same name %q, statement names must be unique", statement.Name) } if err := validatePolicyCore(statement.Name, statement.SignatureVerification, statement.TrustStores, statement.TrustedIdentities); err != nil { - return fmt.Errorf("oci trust policy: %w", err) + return fmt.Errorf("trust policy: %w", err) } policyNames.Add(statement.Name) @@ -135,7 +135,7 @@ func (policyDoc *Document) GetApplicableTrustPolicy(artifactReference string) (* } else if wildcardPolicy != nil { return wildcardPolicy, nil } else { - return nil, fmt.Errorf("artifact %q has no applicable oci trust policy statement. Trust policy applicability for a given artifact is determined by registryScopes. To create a trust policy, see: %s", artifactReference, trustPolicyLink) + return nil, fmt.Errorf("artifact %q has no applicable trust policy statement. Trust policy applicability for a given artifact is determined by registryScopes. To create a trust policy, see: %s", artifactReference, trustPolicyLink) } } @@ -157,10 +157,10 @@ func validateRegistryScopes(policyDoc *Document) error { for _, statement := range policyDoc.TrustPolicies { // Verify registry scopes are valid if len(statement.RegistryScopes) == 0 { - return fmt.Errorf("oci trust policy statement %q has zero registry scopes, it must specify registry scopes with at least one value", statement.Name) + return fmt.Errorf("trust policy statement %q has zero registry scopes, it must specify registry scopes with at least one value", statement.Name) } if len(statement.RegistryScopes) > 1 && slices.Contains(statement.RegistryScopes, trustpolicy.Wildcard) { - return fmt.Errorf("oci trust policy statement %q uses wildcard registry scope '*', a wildcard scope cannot be used in conjunction with other scope values", statement.Name) + return fmt.Errorf("trust policy statement %q uses wildcard registry scope '*', a wildcard scope cannot be used in conjunction with other scope values", statement.Name) } for _, scope := range statement.RegistryScopes { if scope != trustpolicy.Wildcard { @@ -175,7 +175,7 @@ func validateRegistryScopes(policyDoc *Document) error { // Verify one policy statement per registry scope for key := range registryScopeCount { if registryScopeCount[key] > 1 { - return fmt.Errorf("registry scope %q is present in multiple oci trust policy statements, one registry scope value can only be associated with one statement", key) + return fmt.Errorf("registry scope %q is present in multiple trust policy statements, one registry scope value can only be associated with one statement", key) } } diff --git a/verifier/trustpolicy/oci_test.go b/verifier/trustpolicy/oci_test.go index 541bb26a..e9ba7024 100644 --- a/verifier/trustpolicy/oci_test.go +++ b/verifier/trustpolicy/oci_test.go @@ -23,47 +23,32 @@ import ( "github.com/notaryproject/notation-go/dir" ) -func TestLoadOCIDocumentFromOldFileLocation(t *testing.T) { +func TestLoadDocumentFromFileLocation(t *testing.T) { tempRoot := t.TempDir() dir.UserConfigDir = tempRoot path := filepath.Join(tempRoot, "trustpolicy.json") - policyJson, _ := json.Marshal(dummyOCIPolicyDocument()) + policyJson, _ := json.Marshal(dummyPolicyDocument()) if err := os.WriteFile(path, policyJson, 0600); err != nil { - t.Fatalf("TestLoadOCIDocument write policy file failed. Error: %v", err) + t.Fatalf("TestLoadDocument write policy file failed. Error: %v", err) } t.Cleanup(func() { os.RemoveAll(tempRoot) }) if _, err := LoadDocument(); err != nil { - t.Fatalf("LoadOCIDocument() should not throw error for an existing policy file. Error: %v", err) + t.Fatalf("LoadDocument() should not throw error for an existing policy file. Error: %v", err) } } -func TestLoadOCIDocumentFromNewFileLocation(t *testing.T) { - tempRoot := t.TempDir() - dir.UserConfigDir = tempRoot - path := filepath.Join(tempRoot, "trustpolicy.json") - policyJson, _ := json.Marshal(dummyOCIPolicyDocument()) - if err := os.WriteFile(path, policyJson, 0600); err != nil { - t.Fatalf("TestLoadOCIDocument write policy file failed. Error: %v", err) - } - t.Cleanup(func() { os.RemoveAll(tempRoot) }) - - if _, err := LoadDocument(); err != nil { - t.Fatalf("LoadOCIDocument() should not throw error for an existing policy file. Error: %v", err) - } -} - -func TestLoadOCIDocumentError(t *testing.T) { +func TestLoadDocumentError(t *testing.T) { tempRoot := t.TempDir() dir.UserConfigDir = tempRoot if _, err := LoadDocument(); err == nil { - t.Fatalf("LoadOCIDocument() should throw error if OCI trust policy is not found") + t.Fatalf("LoadDocument() should throw error if trust policy is not found") } } // TestApplicableTrustPolicy tests filtering policies against registry scopes func TestApplicableTrustPolicy(t *testing.T) { - policyDoc := dummyOCIPolicyDocument() + policyDoc := dummyPolicyDocument() policyStatement := policyDoc.TrustPolicies[0] policyStatement.Name = "test-statement-name-1" @@ -83,7 +68,7 @@ func TestApplicableTrustPolicy(t *testing.T) { // non-existing Registry Scope policy, err = (&policyDoc).GetApplicableTrustPolicy("non.existing.scope/repo@sha256:hash") - if policy != nil || err == nil || err.Error() != "artifact \"non.existing.scope/repo@sha256:hash\" has no applicable oci trust policy statement. Trust policy applicability for a given artifact is determined by registryScopes. To create a trust policy, see: https://notaryproject.dev/docs/quickstart/#create-a-trust-policy" { + if policy != nil || err == nil || err.Error() != "artifact \"non.existing.scope/repo@sha256:hash\" has no applicable trust policy statement. Trust policy applicability for a given artifact is determined by registryScopes. To create a trust policy, see: https://notaryproject.dev/docs/quickstart/#create-a-trust-policy" { t.Fatalf("GetApplicableTrustPolicy() should return nil for non existing registry scope") } @@ -112,128 +97,128 @@ func TestValidateInvalidPolicyDocument(t *testing.T) { // Sanity check var nilPolicyDoc *Document err := nilPolicyDoc.Validate() - if err == nil || err.Error() != "oci trust policy document cannot be nil" { + if err == nil || err.Error() != "trust policy document cannot be nil" { t.Fatalf("nil policyDoc should return error") } // Invalid Version - policyDoc := dummyOCIPolicyDocument() + policyDoc := dummyPolicyDocument() policyDoc.Version = "invalid" err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy document uses unsupported version \"invalid\"" { + if err == nil || err.Error() != "trust policy document uses unsupported version \"invalid\"" { t.Fatalf("invalid version should return error") } // No Policy Statements - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies = nil err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy document can not have zero trust policy statements" { + if err == nil || err.Error() != "trust policy document can not have zero trust policy statements" { t.Fatalf("zero policy statements should return error") } // No Policy Statement Name - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].Name = "" err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy: a trust policy statement is missing a name, every statement requires a name" { + if err == nil || err.Error() != "trust policy: a trust policy statement is missing a name, every statement requires a name" { t.Fatalf("policy statement with no name should return an error") } // No Registry Scopes - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].RegistryScopes = nil err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy statement \"test-statement-name\" has zero registry scopes, it must specify registry scopes with at least one value" { + if err == nil || err.Error() != "trust policy statement \"test-statement-name\" has zero registry scopes, it must specify registry scopes with at least one value" { t.Fatalf("policy statement with registry scopes should return error") } // Multiple policy statements with same registry scope - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyStatement1 := policyDoc.TrustPolicies[0].clone() policyStatement2 := policyDoc.TrustPolicies[0].clone() policyStatement2.Name = "test-statement-name-2" policyDoc.TrustPolicies = []TrustPolicy{*policyStatement1, *policyStatement2} err = policyDoc.Validate() - if err == nil || err.Error() != "registry scope \"registry.acme-rockets.io/software/net-monitor\" is present in multiple oci trust policy statements, one registry scope value can only be associated with one statement" { + if err == nil || err.Error() != "registry scope \"registry.acme-rockets.io/software/net-monitor\" is present in multiple trust policy statements, one registry scope value can only be associated with one statement" { t.Fatalf("Policy statements with same registry scope should return error %q", err) } // Registry scopes with a wildcard - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].RegistryScopes = []string{"*", "registry.acme-rockets.io/software/net-monitor"} err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy statement \"test-statement-name\" uses wildcard registry scope '*', a wildcard scope cannot be used in conjunction with other scope values" { + if err == nil || err.Error() != "trust policy statement \"test-statement-name\" uses wildcard registry scope '*', a wildcard scope cannot be used in conjunction with other scope values" { t.Fatalf("policy statement with more than a wildcard registry scope should return error") } // Invalid SignatureVerification - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].SignatureVerification = SignatureVerification{VerificationLevel: "invalid"} err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy: trust policy statement \"test-statement-name\" has invalid signatureVerification: invalid signature verification level \"invalid\"" { + if err == nil || err.Error() != "trust policy: trust policy statement \"test-statement-name\" has invalid signatureVerification: invalid signature verification level \"invalid\"" { t.Fatalf("policy statement with invalid SignatureVerification should return error") } // Invalid SignatureVerification VerifyTimestamp - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].SignatureVerification.VerifyTimestamp = "invalid" - expectedErrMsg := "oci trust policy: trust policy statement \"test-statement-name\" has invalid signatureVerification: verifyTimestamp must be \"always\" or \"afterCertExpiry\", but got \"invalid\"" + expectedErrMsg := "trust policy: trust policy statement \"test-statement-name\" has invalid signatureVerification: verifyTimestamp must be \"always\" or \"afterCertExpiry\", but got \"invalid\"" err = policyDoc.Validate() if err == nil || err.Error() != expectedErrMsg { t.Fatalf("expected %s, but got %s", expectedErrMsg, err) } // strict SignatureVerification should have a trust store - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].TrustStores = []string{} err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy: trust policy statement \"test-statement-name\" is either missing trust stores or trusted identities, both must be specified" { + if err == nil || err.Error() != "trust policy: trust policy statement \"test-statement-name\" is either missing trust stores or trusted identities, both must be specified" { t.Fatalf("strict SignatureVerification should have a trust store") } // strict SignatureVerification should have trusted identities - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].TrustedIdentities = []string{} err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy: trust policy statement \"test-statement-name\" is either missing trust stores or trusted identities, both must be specified" { + if err == nil || err.Error() != "trust policy: trust policy statement \"test-statement-name\" is either missing trust stores or trusted identities, both must be specified" { t.Fatalf("strict SignatureVerification should have trusted identities") } // skip SignatureVerification should not have trust store or trusted identities - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].SignatureVerification = SignatureVerification{VerificationLevel: "skip"} err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy: trust policy statement \"test-statement-name\" is set to skip signature verification but configured with trust stores and/or trusted identities, remove them if signature verification needs to be skipped" { + if err == nil || err.Error() != "trust policy: trust policy statement \"test-statement-name\" is set to skip signature verification but configured with trust stores and/or trusted identities, remove them if signature verification needs to be skipped" { t.Fatalf("strict SignatureVerification should have trusted identities") } // Empty Trusted Identity should throw error - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].TrustedIdentities = []string{""} err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy: trust policy statement \"test-statement-name\" has an empty trusted identity" { + if err == nil || err.Error() != "trust policy: trust policy statement \"test-statement-name\" has an empty trusted identity" { t.Fatalf("policy statement with empty trusted identity should return error") } // Trusted Identity without separator should throw error - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].TrustedIdentities = []string{"x509.subject"} err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy: trust policy statement \"test-statement-name\" has trusted identity \"x509.subject\" missing separator" { + if err == nil || err.Error() != "trust policy: trust policy statement \"test-statement-name\" has trusted identity \"x509.subject\" missing separator" { t.Fatalf("policy statement with trusted identity missing separator should return error") } // Empty Trusted Identity value should throw error - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].TrustedIdentities = []string{"x509.subject:"} err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy: trust policy statement \"test-statement-name\" has trusted identity \"x509.subject:\" without an identity value" { + if err == nil || err.Error() != "trust policy: trust policy statement \"test-statement-name\" has trusted identity \"x509.subject:\" without an identity value" { t.Fatalf("policy statement with trusted identity missing identity value should return error") } // trust store/trusted identities are optional for skip SignatureVerification - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].SignatureVerification = SignatureVerification{VerificationLevel: "skip"} policyDoc.TrustPolicies[0].TrustStores = []string{} policyDoc.TrustPolicies[0].TrustedIdentities = []string{} @@ -243,52 +228,52 @@ func TestValidateInvalidPolicyDocument(t *testing.T) { } // Trust Store missing separator - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].TrustStores = []string{"ca"} err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy: trust policy statement \"test-statement-name\" has malformed trust store value \"ca\". The required format is :" { + if err == nil || err.Error() != "trust policy: trust policy statement \"test-statement-name\" has malformed trust store value \"ca\". The required format is :" { t.Fatalf("policy statement with trust store missing separator should return error") } // Invalid Trust Store type - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].TrustStores = []string{"invalid:test-trust-store"} err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy: trust policy statement \"test-statement-name\" uses an unsupported trust store type \"invalid\" in trust store value \"invalid:test-trust-store\"" { + if err == nil || err.Error() != "trust policy: trust policy statement \"test-statement-name\" uses an unsupported trust store type \"invalid\" in trust store value \"invalid:test-trust-store\"" { t.Fatalf("policy statement with invalid trust store type should return error") } // Empty Named Store - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].TrustStores = []string{"ca:"} err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy: trust policy statement \"test-statement-name\" uses an unsupported trust store name \"\" in trust store value \"ca:\". Named store name needs to follow [a-zA-Z0-9_.-]+ format" { + if err == nil || err.Error() != "trust policy: trust policy statement \"test-statement-name\" uses an unsupported trust store name \"\" in trust store value \"ca:\". Named store name needs to follow [a-zA-Z0-9_.-]+ format" { t.Fatalf("policy statement with trust store missing named store should return error") } // trusted identities with a wildcard - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyDoc.TrustPolicies[0].TrustedIdentities = []string{"*", "test-identity"} err = policyDoc.Validate() - if err == nil || err.Error() != "oci trust policy: trust policy statement \"test-statement-name\" uses a wildcard trusted identity '*', a wildcard identity cannot be used in conjunction with other values" { + if err == nil || err.Error() != "trust policy: trust policy statement \"test-statement-name\" uses a wildcard trusted identity '*', a wildcard identity cannot be used in conjunction with other values" { t.Fatalf("policy statement with more than a wildcard trusted identity should return error") } // Policy Document with duplicate policy statement names - policyDoc = dummyOCIPolicyDocument() + policyDoc = dummyPolicyDocument() policyStatement1 = policyDoc.TrustPolicies[0].clone() policyStatement2 = policyDoc.TrustPolicies[0].clone() policyStatement2.RegistryScopes = []string{"registry.acme-rockets.io/software/legacy/metrics"} policyDoc.TrustPolicies = []TrustPolicy{*policyStatement1, *policyStatement2} err = policyDoc.Validate() - if err == nil || err.Error() != "multiple oci trust policy statements use the same name \"test-statement-name\", statement names must be unique" { + if err == nil || err.Error() != "multiple trust policy statements use the same name \"test-statement-name\", statement names must be unique" { t.Fatalf("policy statements with same name should return error") } } // TestValidRegistryScopes tests valid scopes are accepted func TestValidRegistryScopes(t *testing.T) { - policyDoc := dummyOCIPolicyDocument() + policyDoc := dummyPolicyDocument() validScopes := []string{ "*", "example.com/rep", "example.com:8080/rep/rep2", "example.com/rep/subrep/subsub", "10.10.10.10:8080/rep/rep2", "domain/rep", "domain:1234/rep", @@ -305,7 +290,7 @@ func TestValidRegistryScopes(t *testing.T) { // TestInvalidRegistryScopes tests invalid scopes are rejected func TestInvalidRegistryScopes(t *testing.T) { - policyDoc := dummyOCIPolicyDocument() + policyDoc := dummyPolicyDocument() invalidScopes := []string{ "", "1:1", "a,b", "abcd", "1111", "1,2", "example.com/rep:tag", "example.com/rep/subrep/sub:latest", "example.com", "rep/rep2:latest", @@ -333,7 +318,7 @@ func TestInvalidRegistryScopes(t *testing.T) { // TestValidateValidPolicyDocument tests a happy policy document func TestValidateValidPolicyDocument(t *testing.T) { - policyDoc := dummyOCIPolicyDocument() + policyDoc := dummyPolicyDocument() policyStatement1 := policyDoc.TrustPolicies[0].clone() diff --git a/verifier/trustpolicy/trustpolicy_test.go b/verifier/trustpolicy/trustpolicy_test.go index ff948621..07cf8455 100644 --- a/verifier/trustpolicy/trustpolicy_test.go +++ b/verifier/trustpolicy/trustpolicy_test.go @@ -26,7 +26,7 @@ import ( "github.com/notaryproject/notation-go/dir" ) -func dummyOCIPolicyDocument() Document { +func dummyPolicyDocument() Document { return Document{ Version: "1.0", TrustPolicies: []TrustPolicy{ @@ -292,16 +292,16 @@ func TestGetDocument(t *testing.T) { t.Skip("skipping test on Windows") } dir.UserConfigDir = "/" - var ociDoc Document + var doc Document tests := []struct { name string expectedDocument any actualDocument any }{ { - name: "valid OCI policy file", - expectedDocument: dummyOCIPolicyDocument(), - actualDocument: &ociDoc, + name: "valid policy file", + expectedDocument: dummyPolicyDocument(), + actualDocument: &doc, }, } diff --git a/verifier/verifier_test.go b/verifier/verifier_test.go index 39793c56..32576c77 100644 --- a/verifier/verifier_test.go +++ b/verifier/verifier_test.go @@ -45,7 +45,7 @@ import ( ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) -var ociPolicy = dummyPolicyDocument() +var policy = dummyPolicyDocument() var invalidPolicy = dummyInvalidPolicyDocument() var store = truststore.NewX509TrustStore(dir.ConfigFS()) var pm = mock.PluginManager{} @@ -82,7 +82,7 @@ func TestNewFromConfig(t *testing.T) { func TestInvalidArtifactUriValidations(t *testing.T) { verifier := verifier{ - trustPolicyDoc: &ociPolicy, + trustPolicyDoc: &policy, pluginManager: mock.PluginManager{}, } @@ -113,12 +113,12 @@ func TestInvalidArtifactUriValidations(t *testing.T) { func TestErrorNoApplicableTrustPolicy_Error(t *testing.T) { verifier := verifier{ - trustPolicyDoc: &ociPolicy, + trustPolicyDoc: &policy, pluginManager: mock.PluginManager{}, } opts := notation.VerifierVerifyOptions{ArtifactReference: "non-existent-domain.com/repo@sha256:73c803930ea3ba1e54bc25c2bdc53edd0284c62ed651fe7b00369da519a3c333"} _, err := verifier.Verify(context.Background(), ocispec.Descriptor{}, []byte{}, opts) - if !errors.Is(err, notation.ErrorNoApplicableTrustPolicy{Msg: "artifact \"non-existent-domain.com/repo@sha256:73c803930ea3ba1e54bc25c2bdc53edd0284c62ed651fe7b00369da519a3c333\" has no applicable oci trust policy statement. Trust policy applicability for a given artifact is determined by registryScopes. To create a trust policy, see: https://notaryproject.dev/docs/quickstart/#create-a-trust-policy"}) { + if !errors.Is(err, notation.ErrorNoApplicableTrustPolicy{Msg: "artifact \"non-existent-domain.com/repo@sha256:73c803930ea3ba1e54bc25c2bdc53edd0284c62ed651fe7b00369da519a3c333\" has no applicable trust policy statement. Trust policy applicability for a given artifact is determined by registryScopes. To create a trust policy, see: https://notaryproject.dev/docs/quickstart/#create-a-trust-policy"}) { t.Fatalf("no applicable trust policy must throw error") } } @@ -699,13 +699,13 @@ func TestVerifyRevocation(t *testing.T) { } func TestNew(t *testing.T) { - if _, err := New(&ociPolicy, store, pm); err != nil { + if _, err := New(&policy, store, pm); err != nil { t.Fatalf("expected New constructor to succeed, but got %v", err) } } func TestNewWithOptions(t *testing.T) { - if _, err := NewWithOptions(&ociPolicy, store, pm, VerifierOptions{}); err != nil { + if _, err := NewWithOptions(&policy, store, pm, VerifierOptions{}); err != nil { t.Fatalf("expected NewWithOptions constructor to succeed, but got %v", err) } @@ -715,7 +715,7 @@ func TestNewWithOptions(t *testing.T) { } opts := VerifierOptions{RevocationClient: r} - _, err = NewWithOptions(&ociPolicy, store, pm, opts) + _, err = NewWithOptions(&policy, store, pm, opts) if err != nil { t.Fatalf("expected NewWithOptions constructor to succeed, but got %v", err) } @@ -736,13 +736,13 @@ func TestNewWithOptions(t *testing.T) { } opts.RevocationCodeSigningValidator = revocationCodeSigningValidator opts.RevocationTimestampingValidator = revocationTimestampingValidator - _, err = NewWithOptions(&ociPolicy, store, pm, opts) + _, err = NewWithOptions(&policy, store, pm, opts) if err != nil { t.Fatalf("expected NewWithOptions constructor to succeed, but got %v", err) } opts.RevocationClient = nil - _, err = NewWithOptions(&ociPolicy, store, pm, opts) + _, err = NewWithOptions(&policy, store, pm, opts) if err != nil { t.Fatalf("expected NewWithOptions constructor to succeed, but got %v", err) } @@ -771,14 +771,14 @@ func TestNewWithOptionsError(t *testing.T) { t.Errorf("expected %s, but got %s", expectedErrMsg, err) } - _, err = NewWithOptions(&ociPolicy, nil, pm, opts) + _, err = NewWithOptions(&policy, nil, pm, opts) expectedErrMsg = "trustStore cannot be nil" if err == nil || err.Error() != expectedErrMsg { t.Errorf("expected %s, but got %s", expectedErrMsg, err) } _, err = NewWithOptions(&invalidPolicy, store, pm, opts) - expectedErrMsg = "oci trust policy document has empty version, version must be specified" + expectedErrMsg = "trust policy document has empty version, version must be specified" if err == nil || err.Error() != expectedErrMsg { t.Errorf("expected %s, but got %s", expectedErrMsg, err) } From a7ba8fdd4b731688f071a65c0255f43ff15d07f0 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 15 Aug 2024 09:22:20 +0800 Subject: [PATCH 08/11] updated per code review Signed-off-by: Patrick Zheng --- verifier/trustpolicy/oci.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/verifier/trustpolicy/oci.go b/verifier/trustpolicy/oci.go index f04c9d3e..2ba79f7d 100644 --- a/verifier/trustpolicy/oci.go +++ b/verifier/trustpolicy/oci.go @@ -39,6 +39,9 @@ type TrustPolicy struct { // Name of the policy statement Name string `json:"name"` + // RegistryScopes that this policy statement affects + RegistryScopes []string `json:"registryScopes"` + // SignatureVerification setting for this policy statement SignatureVerification SignatureVerification `json:"signatureVerification"` @@ -47,9 +50,6 @@ type TrustPolicy struct { // TrustedIdentities this policy statement pins TrustedIdentities []string `json:"trustedIdentities"` - - // RegistryScopes that this policy statement affects - RegistryScopes []string `json:"registryScopes"` } var supportedPolicyVersions = []string{"1.0"} From 1b664290c008f610314904fcb1700e2c29fd3e04 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 15 Aug 2024 11:09:54 +0800 Subject: [PATCH 09/11] updated for v1.2.0 release Signed-off-by: Patrick Zheng --- signer/signer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signer/signer.go b/signer/signer.go index ff2f83e7..1e72c4c3 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -34,7 +34,7 @@ import ( ) // signingAgent is the unprotected header field used by signature. -const signingAgent = "Notation/1.0.0" +const signingAgent = "Notation/1.2.0" // GenericSigner implements notation.Signer and embeds signature.Signer type GenericSigner struct { From f11626a62ee431ab6d5994272a714fefea8cfd32 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 15 Aug 2024 14:08:09 +0800 Subject: [PATCH 10/11] update signingAgent Signed-off-by: Patrick Zheng --- signer/signer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signer/signer.go b/signer/signer.go index 1e72c4c3..a6754c26 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -34,7 +34,7 @@ import ( ) // signingAgent is the unprotected header field used by signature. -const signingAgent = "Notation/1.2.0" +const signingAgent = "Notation/1.2.0-rc.1" // GenericSigner implements notation.Signer and embeds signature.Signer type GenericSigner struct { From d5e876aecb1dcd2fc2d8dfd7a5cda00674fa05e1 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 15 Aug 2024 14:15:30 +0800 Subject: [PATCH 11/11] update signingAgent Signed-off-by: Patrick Zheng --- signer/signer.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/signer/signer.go b/signer/signer.go index a6754c26..d51f8cd9 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -34,7 +34,7 @@ import ( ) // signingAgent is the unprotected header field used by signature. -const signingAgent = "Notation/1.2.0-rc.1" +const signingAgent = "notation-go/1.2.0-rc.1" // GenericSigner implements notation.Signer and embeds signature.Signer type GenericSigner struct {