From b52583166f2b98c75899356aaf4964e98c261c48 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 15 Jul 2024 12:40:11 +0800 Subject: [PATCH] feat: Timestamp (#418) Signed-off-by: Patrick Zheng --- config/base_test.go | 4 + example_localVerify_test.go | 6 +- example_remoteVerify_test.go | 10 +- example_signWithTimestmap_test.go | 99 ++++ example_verifyWithTimestamp_test.go | 192 ++++++++ go.mod | 5 +- go.sum | 10 +- internal/mock/ocilayout/ocilayout_test.go | 6 +- notation.go | 19 +- registry/repository_test.go | 4 + signer/signer.go | 13 +- signer/signer_test.go | 70 ++- signer/testdata/DigiCertTSARootSHA384.cer | Bin 0 -> 1428 bytes verifier/helpers.go | 79 ++-- verifier/helpers_test.go | 35 +- .../countersignature/TimeStampToken.p7s | Bin 0 -> 6595 bytes .../TimeStampTokenWithInvalidTSTInfo.p7s | Bin 0 -> 6578 bytes .../TimeStampTokenWithInvalideContentType.p7s | Bin 0 -> 6593 bytes .../TimeStampTokenWithoutCertificate.p7s | Bin 0 -> 1117 bytes .../sigEnv/coseExpiredWithTimestamp.sig | Bin 0 -> 7365 bytes .../timestamp/sigEnv/coseWithTimestamp.sig | Bin 0 -> 7362 bytes .../sigEnv/jwsExpiredWithTimestamp.sig | 1 + .../timestamp/sigEnv/jwsWithTimestamp.sig | 1 + .../sigEnv/timestampAfterNotAfter.sig | Bin 0 -> 7365 bytes .../sigEnv/timestampBeforeNotBefore.sig | 1 + .../timestamp/sigEnv/withoutTimestamp.sig | 1 + .../ca/valid-trust-store/TestTimestamp.crt | 20 + .../TestTimestampNotYetValid.crt | 20 + .../tsa/test-mismatch/wabbit-networks.io.crt | 20 + .../tsa/test-timestamp/globalsignRoot.cer | Bin 0 -> 1415 bytes verifier/timestamp_test.go | 421 ++++++++++++++++++ verifier/trustpolicy/oci_test.go | 28 ++ verifier/trustpolicy/trustpolicy.go | 19 + verifier/trustpolicy/trustpolicy_test.go | 10 +- verifier/truststore/truststore.go | 2 + verifier/truststore/truststore_test.go | 5 +- verifier/verifier.go | 285 +++++++++--- verifier/verifier_test.go | 14 +- 38 files changed, 1258 insertions(+), 142 deletions(-) create mode 100644 example_signWithTimestmap_test.go create mode 100644 example_verifyWithTimestamp_test.go create mode 100644 signer/testdata/DigiCertTSARootSHA384.cer create mode 100644 verifier/testdata/timestamp/countersignature/TimeStampToken.p7s create mode 100644 verifier/testdata/timestamp/countersignature/TimeStampTokenWithInvalidTSTInfo.p7s create mode 100644 verifier/testdata/timestamp/countersignature/TimeStampTokenWithInvalideContentType.p7s create mode 100644 verifier/testdata/timestamp/countersignature/TimeStampTokenWithoutCertificate.p7s create mode 100644 verifier/testdata/timestamp/sigEnv/coseExpiredWithTimestamp.sig create mode 100644 verifier/testdata/timestamp/sigEnv/coseWithTimestamp.sig create mode 100644 verifier/testdata/timestamp/sigEnv/jwsExpiredWithTimestamp.sig create mode 100644 verifier/testdata/timestamp/sigEnv/jwsWithTimestamp.sig create mode 100644 verifier/testdata/timestamp/sigEnv/timestampAfterNotAfter.sig create mode 100644 verifier/testdata/timestamp/sigEnv/timestampBeforeNotBefore.sig create mode 100644 verifier/testdata/timestamp/sigEnv/withoutTimestamp.sig create mode 100644 verifier/testdata/truststore/x509/ca/valid-trust-store/TestTimestamp.crt create mode 100644 verifier/testdata/truststore/x509/ca/valid-trust-store/TestTimestampNotYetValid.crt create mode 100644 verifier/testdata/truststore/x509/tsa/test-mismatch/wabbit-networks.io.crt create mode 100644 verifier/testdata/truststore/x509/tsa/test-timestamp/globalsignRoot.cer create mode 100644 verifier/timestamp_test.go diff --git a/config/base_test.go b/config/base_test.go index 7fb8d8ff..1241ec38 100644 --- a/config/base_test.go +++ b/config/base_test.go @@ -17,6 +17,7 @@ import ( "fmt" "os" "path/filepath" + "runtime" "testing" "github.com/notaryproject/notation-go/dir" @@ -33,6 +34,9 @@ func TestLoadNonExistentFile(t *testing.T) { } func TestLoadSymlink(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } root := t.TempDir() dir.UserConfigDir = root fileName := "symlink" diff --git a/example_localVerify_test.go b/example_localVerify_test.go index f5248d26..50426763 100644 --- a/example_localVerify_test.go +++ b/example_localVerify_test.go @@ -31,7 +31,7 @@ import ( // examplePolicyDocument is an example of a valid trust policy document. // trust policy document should follow this spec: -// https://github.com/notaryproject/notaryproject/blob/v1.0.0-rc.1/specs/trust-store-trust-policy.md#trust-policy +// https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-policy var examplePolicyDocument = trustpolicy.Document{ Version: "1.0", TrustPolicies: []trustpolicy.TrustPolicy{ @@ -75,7 +75,7 @@ func Example_localVerify() { // createTrustStore 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-rc.1/specs/trust-store-trust-policy.md#trust-store + // https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-store if err := createTrustStore(); err != nil { panic(err) // Handle error } @@ -173,7 +173,7 @@ func createTrustStore() error { // 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-rc.1/specs/signature-specification.md#certificate-requirements + // https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/signature-specification.md#certificate-requirements exampleX509Certificate := `-----BEGIN CERTIFICATE----- MIIDQDCCAiigAwIBAgIBUTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEL MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEP diff --git a/example_remoteVerify_test.go b/example_remoteVerify_test.go index 4289b450..1fffed34 100644 --- a/example_remoteVerify_test.go +++ b/example_remoteVerify_test.go @@ -37,7 +37,7 @@ func Example_remoteVerify() { // examplePolicyDocument is an example of a valid trust policy document. // trust policy document should follow this spec: - // https://github.com/notaryproject/notaryproject/blob/v1.0.0-rc.1/specs/trust-store-trust-policy.md#trust-policy + // https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-policy examplePolicyDocument := trustpolicy.Document{ Version: "1.0", TrustPolicies: []trustpolicy.TrustPolicy{ @@ -52,9 +52,9 @@ func Example_remoteVerify() { } // generateTrustStore generates 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-rc.1/specs/trust-store-trust-policy.md#trust-store + // Users should configure their own trust store 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 := generateTrustStore(); err != nil { panic(err) // Handle error } @@ -102,7 +102,7 @@ func generateTrustStore() error { // 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-rc.1/specs/signature-specification.md#certificate-requirements + // https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/signature-specification.md#certificate-requirements exampleX509Certificate := `-----BEGIN CERTIFICATE----- MIIDQDCCAiigAwIBAgIBUTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEL MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEP diff --git a/example_signWithTimestmap_test.go b/example_signWithTimestmap_test.go new file mode 100644 index 00000000..8e0ebe5c --- /dev/null +++ b/example_signWithTimestmap_test.go @@ -0,0 +1,99 @@ +// 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" + "crypto/x509" + "encoding/pem" + "fmt" + + "oras.land/oras-go/v2/registry/remote" + + "github.com/notaryproject/notation-core-go/testhelper" + "github.com/notaryproject/notation-go" + "github.com/notaryproject/notation-go/registry" + "github.com/notaryproject/notation-go/signer" + "github.com/notaryproject/tspclient-go" +) + +// Example_signWithTimestamp demonstrates how to use notation.Sign to sign an +// artifact with a RFC 3161 compliant timestamp countersignature and +// user trusted TSA root certificate +func Example_signWithTimestamp() { + // exampleArtifactReference is an example of the target artifact reference + var exampleArtifactReference = "localhost:5000/software@sha256:60043cf45eaebc4c0867fea485a039b598f52fd09fd5b07b0b2d2f88fad9d74e" + + // exampleCertTuple contains a RSA privateKey and a self-signed X509 + // certificate generated for demo purpose ONLY. + exampleCertTuple := testhelper.GetRSASelfSignedSigningCertTuple("Notation Example self-signed") + exampleCerts := []*x509.Certificate{exampleCertTuple.Cert} + + // exampleSigner is a notation.Signer given key and X509 certificate chain. + // Users should replace `exampleCertTuple.PrivateKey` with their own private + // key and replace `exampleCerts` with the corresponding full certificate + // chain, following the Notary certificate requirements: + // https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/signature-specification.md#certificate-requirements + exampleSigner, err := signer.NewGenericSigner(exampleCertTuple.PrivateKey, exampleCerts) + if err != nil { + panic(err) // Handle error + } + + // exampleRepo is an example of registry.Repository. + remoteRepo, err := remote.NewRepository(exampleArtifactReference) + if err != nil { + panic(err) // Handle error + } + exampleRepo := registry.NewRepository(remoteRepo) + + // replace exampleRFC3161TSAServer with your trusted TSA server URL. + exampleRFC3161TSAServer := "" + httpTimestamper, err := tspclient.NewHTTPTimestamper(nil, exampleRFC3161TSAServer) + if err != nil { + panic(err) // Handle error + } + + // replace exampleTSARootCertPem with your trusted TSA root cert. + exampleTSARootCertPem := "" + block, _ := pem.Decode([]byte(exampleTSARootCertPem)) + if block == nil { + panic("failed to parse tsa root certificate PEM") + } + tsaRootCert, err := x509.ParseCertificate(block.Bytes) + if err != nil { + panic("failed to parse tsa root certificate: " + err.Error()) + } + tsaRootCAs := x509.NewCertPool() + tsaRootCAs.AddCert(tsaRootCert) + + // exampleSignOptions is an example of notation.SignOptions. + exampleSignOptions := notation.SignOptions{ + SignerSignOptions: notation.SignerSignOptions{ + SignatureMediaType: exampleSignatureMediaType, + Timestamper: httpTimestamper, + TSARootCAs: tsaRootCAs, + }, + ArtifactReference: exampleArtifactReference, + } + + targetDesc, err := notation.Sign(context.Background(), exampleSigner, exampleRepo, exampleSignOptions) + if err != nil { + panic(err) // Handle error + } + + fmt.Println("Successfully signed") + fmt.Println("targetDesc MediaType:", targetDesc.MediaType) + fmt.Println("targetDesc Digest:", targetDesc.Digest) + fmt.Println("targetDesc Size:", targetDesc.Size) +} diff --git a/example_verifyWithTimestamp_test.go b/example_verifyWithTimestamp_test.go new file mode 100644 index 00000000..56c21d59 --- /dev/null +++ b/example_verifyWithTimestamp_test.go @@ -0,0 +1,192 @@ +// 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" + + _ "github.com/notaryproject/notation-core-go/signature/cose" + _ "github.com/notaryproject/notation-core-go/signature/jws" + "github.com/notaryproject/notation-go" + "github.com/notaryproject/notation-go/dir" + "github.com/notaryproject/notation-go/registry" + "github.com/notaryproject/notation-go/verifier" + "github.com/notaryproject/notation-go/verifier/trustpolicy" + "github.com/notaryproject/notation-go/verifier/truststore" + "oras.land/oras-go/v2/registry/remote" +) + +// Example_verifyWithTimestamp demonstrates how to use notation.Verify to verify +// signature of an artifact including RFC 3161 compliant timestamp countersignature +func Example_verifyWithTimestamp() { + // exampleArtifactReference is an example of the target artifact reference + exampleArtifactReference := "localhost:5000/software@sha256:60043cf45eaebc4c0867fea485a039b598f52fd09fd5b07b0b2d2f88fad9d74e" + + // examplePolicyDocument is an example of a valid trust policy document with + // timestamping configurations. + // trust policy document should follow this spec: + // https://github.com/notaryproject/notaryproject/blob/v1.0.0/specs/trust-store-trust-policy.md#trust-policy + examplePolicyDocument := trustpolicy.Document{ + Version: "1.0", + TrustPolicies: []trustpolicy.TrustPolicy{ + { + Name: "test-statement-name", + RegistryScopes: []string{"*"}, + SignatureVerification: trustpolicy.SignatureVerification{ + VerificationLevel: trustpolicy.LevelStrict.Name, + + // verify timestamp countersignature only if the signing + // certificate chain has expired. + // Default: trustpolicy.OptionAlways + VerifyTimestamp: trustpolicy.OptionAfterCertExpiry, + }, + + // `tsa` trust store type MUST be configured to enable + // timestamp verification + TrustStores: []string{"ca:valid-trust-store", "tsa:valid-tsa"}, + + // TrustedIdentities only contains trusted identities of `ca` + // and `signingAuthority` + TrustedIdentities: []string{"*"}, + }, + }, + } + + // generateTrustStoreWithTimestamp generates a trust store directory for demo purpose. + // Users should configure their own trust store 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 := generateTrustStoreWithTimestamp(); err != nil { + panic(err) // Handle error + } + + // exampleVerifier is an example of notation.Verifier given + // trust policy document and X509 trust store. + exampleVerifier, err := verifier.New(&examplePolicyDocument, truststore.NewX509TrustStore(dir.ConfigFS()), nil) + if err != nil { + panic(err) // Handle error + } + + // exampleRepo is an example of registry.Repository. + remoteRepo, err := remote.NewRepository(exampleArtifactReference) + if err != nil { + panic(err) // Handle error + } + exampleRepo := registry.NewRepository(remoteRepo) + + // exampleVerifyOptions is an example of notation.VerifyOptions. + exampleVerifyOptions := notation.VerifyOptions{ + ArtifactReference: exampleArtifactReference, + MaxSignatureAttempts: 50, + } + + // remote verify core process + // upon successful verification, the target manifest descriptor + // and signature verification outcome are returned. + targetDesc, _, err := notation.Verify(context.Background(), exampleVerifier, exampleRepo, exampleVerifyOptions) + if err != nil { + panic(err) // Handle error + } + + fmt.Println("Successfully verified") + fmt.Println("targetDesc MediaType:", targetDesc.MediaType) + fmt.Println("targetDesc Digest:", targetDesc.Digest) + fmt.Println("targetDesc Size:", targetDesc.Size) +} + +func generateTrustStoreWithTimestamp() 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. + // 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----- +MIIDQDCCAiigAwIBAgIBUTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEL +MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEP +MA0GA1UEAxMGYWxwaW5lMCAXDTAwMDgyOTEzNTAwMFoYDzIxMjMwODI5MTM1MDAw +WjBOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUx +DzANBgNVBAoTBk5vdGFyeTEPMA0GA1UEAxMGYWxwaW5lMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEAocg3qEsyNDDLfB8OHD4dhi+M1NPK1Asy5NX84c+g +vacZuoPLTwmpOfm6nPt7GPPB9G7S6xxhFNbRxTYfYUjK+kaCj38XjBRf5lGewbSJ +KVkxQ82/axU70ceSW3JpazrageN9JUTZ/Jfi4MfnipITwcmMoiij8eGrHskjyVyZ +bJd0WMMKRDWVhLPUiPMVWt/4d7YtZItzacaQKtXmXgsTCTWpIols3gftNYjrQoMs +UelUdD8vOAWN9J28/SyC+uSh/K1KfyUlbqufn4di8DEBxntP5wnXYbJL1jtjsUgE +xAVjQxT1zI59X36m3t3YKqCQh1cud02L5onObY6zj57N6QIDAQABoycwJTAOBgNV +HQ8BAf8EBAMCB4AwEwYDVR0lBAwwCgYIKwYBBQUHAwMwDQYJKoZIhvcNAQELBQAD +ggEBAC8AjBLy7EsRpi6oguCdFSb6nRGjvF17N+b6mDb3sARnB8T1pxvzTT26ya+A +yWR+jjodEwbMIS+13lV+9qT2LwqlbOUNY519Pa2GRRY72JjeowWI3iKkKaMzfZUB +7lRTGXdEuZApLbTO/3JVcR9ffu00N1UaAP9YGElSt4JDJYA9M+d/Qto+HiIsE0Kj ++jdnwIYovPPOlryKOLfFb/r1GEq7n63xFZz83iyWNaZdsJ5N3YHxdOpkbBbCalOE +BDJTjQKqeAYBLoANNU0OBslmqHCSBTEnhbqJHN6QKyF09ScOl5LwM1QsTl0UY5si +GLAfj/jSf9OH9VLTPHOS8/N0Ka4= +-----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 + } + if err := os.WriteFile("tmp/truststore/x509/ca/valid-trust-store/NotationExample.pem", []byte(exampleX509Certificate), 0600); err != nil { + return err + } + + // an example of a valid TSA root certificate for demo purpose ONLY. + // Users should replace `exampleTSARootCertificate` with their own trusted + // TSA root 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 + exampleTSARootCertificate := `-----BEGIN CERTIFICATE----- + MIIFkDCCA3igAwIBAgIQBZsbV56OITLiOQe9p3d1XDANBgkqhkiG9w0BAQwFADBi + MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3 + d3cuZGlnaWNlcnQuY29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3Qg + RzQwHhcNMTMwODAxMTIwMDAwWhcNMzgwMTE1MTIwMDAwWjBiMQswCQYDVQQGEwJV + UzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3d3cuZGlnaWNlcnQu + Y29tMSEwHwYDVQQDExhEaWdpQ2VydCBUcnVzdGVkIFJvb3QgRzQwggIiMA0GCSqG + SIb3DQEBAQUAA4ICDwAwggIKAoICAQC/5pBzaN675F1KPDAiMGkz7MKnJS7JIT3y + ithZwuEppz1Yq3aaza57G4QNxDAf8xukOBbrVsaXbR2rsnnyyhHS5F/WBTxSD1If + xp4VpX6+n6lXFllVcq9ok3DCsrp1mWpzMpTREEQQLt+C8weE5nQ7bXHiLQwb7iDV + ySAdYyktzuxeTsiT+CFhmzTrBcZe7FsavOvJz82sNEBfsXpm7nfISKhmV1efVFiO + DCu3T6cw2Vbuyntd463JT17lNecxy9qTXtyOj4DatpGYQJB5w3jHtrHEtWoYOAMQ + jdjUN6QuBX2I9YI+EJFwq1WCQTLX2wRzKm6RAXwhTNS8rhsDdV14Ztk6MUSaM0C/ + CNdaSaTC5qmgZ92kJ7yhTzm1EVgX9yRcRo9k98FpiHaYdj1ZXUJ2h4mXaXpI8OCi + EhtmmnTK3kse5w5jrubU75KSOp493ADkRSWJtppEGSt+wJS00mFt6zPZxd9LBADM + fRyVw4/3IbKyEbe7f/LVjHAsQWCqsWMYRJUadmJ+9oCw++hkpjPRiQfhvbfmQ6QY + uKZ3AeEPlAwhHbJUKSWJbOUOUlFHdL4mrLZBdd56rF+NP8m800ERElvlEFDrMcXK + chYiCd98THU/Y+whX8QgUWtvsauGi0/C1kVfnSD8oR7FwI+isX4KJpn15GkvmB0t + 9dmpsh3lGwIDAQABo0IwQDAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB + hjAdBgNVHQ4EFgQU7NfjgtJxXWRM3y5nP+e6mK4cD08wDQYJKoZIhvcNAQEMBQAD + ggIBALth2X2pbL4XxJEbw6GiAI3jZGgPVs93rnD5/ZpKmbnJeFwMDF/k5hQpVgs2 + SV1EY+CtnJYYZhsjDT156W1r1lT40jzBQ0CuHVD1UvyQO7uYmWlrx8GnqGikJ9yd + +SeuMIW59mdNOj6PWTkiU0TryF0Dyu1Qen1iIQqAyHNm0aAFYF/opbSnr6j3bTWc + fFqK1qI4mfN4i/RN0iAL3gTujJtHgXINwBQy7zBZLq7gcfJW5GqXb5JQbZaNaHqa + sjYUegbyJLkJEVDXCLG4iXqEI2FCKeWjzaIgQdfRnGTZ6iahixTXTBmyUEFxPT9N + cCOGDErcgdLMMpSEDQgJlxxPwO5rIHQw0uA5NBCFIRUBCOhVMt5xSdkoF1BN5r5N + 0XWs0Mr7QbhDparTwwVETyw2m+L64kW4I1NsBm9nVX9GtUw/bihaeSbSpKhil9Ie + 4u1Ki7wb/UdKDd9nZn6yW0HQO+T0O/QEY+nvwlQAUaCKKsnOeMzV6ocEGLPOr0mI + r/OSmbaz5mEP0oUA51Aa5BuVnRmhuZyxm7EAHu/QD09CbMkKvO5D+jpxpchNJqU1 + /YldvIViHTLSoCtU7ZpXwdv6EM8Zt4tKG48BtieVU+i2iW1bvGjUI+iLUaJW+fCm + gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ + -----END CERTIFICATE-----` + + // Adding the tsa root certificate into the trust store. + if err := os.MkdirAll("tmp/truststore/x509/tsa/valid-tsa", 0700); err != nil { + return err + } + return os.WriteFile("tmp/truststore/x509/tsa/valid-tsa/NotationTSAExample.pem", []byte(exampleTSARootCertificate), 0600) +} diff --git a/go.mod b/go.mod index 73b5dbd5..61e27ab5 100644 --- a/go.mod +++ b/go.mod @@ -4,8 +4,9 @@ go 1.21 require ( github.com/go-ldap/ldap/v3 v3.4.8 - github.com/notaryproject/notation-core-go v1.0.3 + github.com/notaryproject/notation-core-go v1.0.4-0.20240708015912-faac9b7f3f10 github.com/notaryproject/notation-plugin-framework-go v1.0.0 + github.com/notaryproject/tspclient-go v0.1.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/veraison/go-cose v1.1.0 @@ -16,7 +17,7 @@ require ( require ( github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect - github.com/fxamacker/cbor/v2 v2.6.0 // indirect + github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/golang-jwt/jwt/v4 v4.5.0 // indirect github.com/google/uuid v1.6.0 // indirect diff --git a/go.sum b/go.sum index 239c4b75..de10e43d 100644 --- a/go.sum +++ b/go.sum @@ -5,8 +5,8 @@ github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1L github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= -github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA= -github.com/fxamacker/cbor/v2 v2.6.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= +github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E= +github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ= github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA= github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0= github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ= @@ -32,10 +32,12 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6 github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/notaryproject/notation-core-go v1.0.3 h1:FCgvULSypEFrrNgvDRdHbKAGAgbXK43n/jKD9q2WECA= -github.com/notaryproject/notation-core-go v1.0.3/go.mod h1:eDo5/LTUp23mB7w0CckJLnl+p93oGdyiKDzzggpqTH4= +github.com/notaryproject/notation-core-go v1.0.4-0.20240708015912-faac9b7f3f10 h1:kXRTRPpJqj7DuSxYxfrVKcfQ3CijRisPdQQrt/+Y1bE= +github.com/notaryproject/notation-core-go v1.0.4-0.20240708015912-faac9b7f3f10/go.mod h1:6DN+zUYRhXx7swFMVSrai5J+7jqyuOCru1q9G+SbFno= github.com/notaryproject/notation-plugin-framework-go v1.0.0 h1:6Qzr7DGXoCgXEQN+1gTZWuJAZvxh3p8Lryjn5FaLzi4= github.com/notaryproject/notation-plugin-framework-go v1.0.0/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics= +github.com/notaryproject/tspclient-go v0.1.0 h1:kmtQuN32iwBAizOhPr+NZsxCErydoGcrfQy1ppJi5Vo= +github.com/notaryproject/tspclient-go v0.1.0/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= diff --git a/internal/mock/ocilayout/ocilayout_test.go b/internal/mock/ocilayout/ocilayout_test.go index 81b464f7..ad4bcb9f 100644 --- a/internal/mock/ocilayout/ocilayout_test.go +++ b/internal/mock/ocilayout/ocilayout_test.go @@ -15,6 +15,7 @@ package ocilayout import ( "os" + "runtime" "testing" ) @@ -26,7 +27,10 @@ func TestCopy(t *testing.T) { } }) - t.Run("invalid target path", func(t *testing.T) { + t.Run("invalid target path permission", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } tempDir := t.TempDir() // change the permission of the tempDir to make it invalid if err := os.Chmod(tempDir, 0); err != nil { diff --git a/notation.go b/notation.go index 1a6290e3..fcad813c 100644 --- a/notation.go +++ b/notation.go @@ -18,6 +18,7 @@ package notation import ( "context" "crypto/sha256" + "crypto/x509" "encoding/hex" "encoding/json" "errors" @@ -37,6 +38,7 @@ import ( "github.com/notaryproject/notation-go/log" "github.com/notaryproject/notation-go/registry" "github.com/notaryproject/notation-go/verifier/trustpolicy" + "github.com/notaryproject/tspclient-go" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) @@ -61,6 +63,12 @@ type SignerSignOptions struct { // SigningAgent sets the signing agent name SigningAgent string + + // Timestamper denotes the timestamper for RFC 3161 timestamping + Timestamper tspclient.Timestamper + + // TSARootCAs is the cert pool holding caller's TSA trust anchor + TSARootCAs *x509.CertPool } // Signer is a generic interface for signing an OCI artifact. @@ -84,11 +92,12 @@ type SignBlobOptions struct { // 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 -// } +// +// { +// "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. diff --git a/registry/repository_test.go b/registry/repository_test.go index 50ea6885..708a974a 100644 --- a/registry/repository_test.go +++ b/registry/repository_test.go @@ -23,6 +23,7 @@ import ( "os" "path/filepath" "reflect" + "runtime" "strings" "testing" @@ -607,6 +608,9 @@ func TestNewOCIRepositoryFailed(t *testing.T) { }) t.Run("no permission to create new path", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } // create a directory in the temp dir dirPath := filepath.Join(t.TempDir(), "dir") err := os.Mkdir(dirPath, 0000) diff --git a/signer/signer.go b/signer/signer.go index 05d0ea8c..4bd995cd 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -113,6 +113,12 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts } else { signingAgentId = signingAgent } + if opts.Timestamper != nil && opts.TSARootCAs == nil { + return nil, nil, errors.New("timestamping: got Timestamper but nil TSARootCAs") + } + if opts.TSARootCAs != nil && opts.Timestamper == nil { + return nil, nil, errors.New("timestamping: got TSARootCAs but nil Timestamper") + } signReq := &signature.SignRequest{ Payload: signature.Payload{ ContentType: envelope.MediaTypePayloadV1, @@ -122,6 +128,8 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts SigningTime: time.Now(), SigningScheme: signature.SigningSchemeX509, SigningAgent: signingAgentId, + Timestamper: opts.Timestamper, + TSARootCAs: opts.TSARootCAs, } // Add expiry only if ExpiryDuration is not zero @@ -136,6 +144,9 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts logger.Debugf(" SigningScheme: %v", signReq.SigningScheme) logger.Debugf(" SigningAgent: %v", signReq.SigningAgent) + // Add ctx to the SignRequest + signReq = signReq.WithContext(ctx) + // perform signing sigEnv, err := signature.NewEnvelope(opts.SignatureMediaType) if err != nil { @@ -154,8 +165,6 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts if err := envelope.ValidatePayloadContentType(&envContent.Payload); err != nil { return nil, nil, err } - - // TODO: re-enable timestamping https://github.com/notaryproject/notation-go/issues/78 return sig, &envContent.SignerInfo, nil } diff --git a/signer/signer_test.go b/signer/signer_test.go index 31e16ca5..fd1f4fb5 100644 --- a/signer/signer_test.go +++ b/signer/signer_test.go @@ -34,13 +34,17 @@ import ( _ "github.com/notaryproject/notation-core-go/signature/cose" _ "github.com/notaryproject/notation-core-go/signature/jws" "github.com/notaryproject/notation-core-go/testhelper" + nx509 "github.com/notaryproject/notation-core-go/x509" "github.com/notaryproject/notation-go" "github.com/notaryproject/notation-go/internal/envelope" "github.com/notaryproject/notation-go/plugin/proto" + "github.com/notaryproject/tspclient-go" "github.com/opencontainers/go-digest" ocispec "github.com/opencontainers/image-spec/specs-go/v1" ) +const rfc3161URL = "http://timestamp.digicert.com" + type keyCertPair struct { keySpecName string key crypto.PrivateKey @@ -117,7 +121,7 @@ func generateKeyBytes(key crypto.PrivateKey) (keyBytes []byte, err error) { return keyBytes, nil } -func prepareTestKeyCertFile(keyCert *keyCertPair, envelopeType, dir string) (string, string, error) { +func prepareTestKeyCertFile(keyCert *keyCertPair, dir string) (string, string, error) { keyPath, certPath := filepath.Join(dir, keyCert.keySpecName+".key"), filepath.Join(dir, keyCert.keySpecName+".cert") keyBytes, err := generateKeyBytes(keyCert.key) if err != nil { @@ -138,7 +142,7 @@ func prepareTestKeyCertFile(keyCert *keyCertPair, envelopeType, dir string) (str } func testSignerFromFile(t *testing.T, keyCert *keyCertPair, envelopeType, dir string) { - keyPath, certPath, err := prepareTestKeyCertFile(keyCert, envelopeType, dir) + keyPath, certPath, err := prepareTestKeyCertFile(keyCert, dir) if err != nil { t.Fatalf("prepareTestKeyCertFile() failed: %v", err) } @@ -208,10 +212,51 @@ func TestSignWithCertChain(t *testing.T) { for _, envelopeType := range signature.RegisteredEnvelopeTypes() { for _, keyCert := range keyCertPairCollections { t.Run(fmt.Sprintf("envelopeType=%v_keySpec=%v", envelopeType, keyCert.keySpecName), func(t *testing.T) { - validateSignWithCerts(t, envelopeType, keyCert.key, keyCert.certs) + validateSignWithCerts(t, envelopeType, keyCert.key, keyCert.certs, false) + }) + } + } +} + +func TestSignWithTimestamping(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) { + validateSignWithCerts(t, envelopeType, keyCert.key, keyCert.certs, true) }) } } + + // timestamping without timestamper + envelopeType := signature.RegisteredEnvelopeTypes()[0] + keyCert := keyCertPairCollections[0] + s, err := New(keyCert.key, keyCert.certs) + if err != nil { + t.Fatalf("NewSigner() error = %v", err) + } + ctx := context.Background() + desc, sOpts := generateSigningContent() + sOpts.SignatureMediaType = envelopeType + sOpts.TSARootCAs = x509.NewCertPool() + _, _, err = s.Sign(ctx, desc, sOpts) + expectedErrMsg := "timestamping: got TSARootCAs but nil Timestamper" + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + + // timestamping without TSARootCAs + desc, sOpts = generateSigningContent() + sOpts.SignatureMediaType = envelopeType + sOpts.Timestamper, err = tspclient.NewHTTPTimestamper(nil, rfc3161URL) + if err != nil { + t.Fatal(err) + } + _, _, err = s.Sign(ctx, desc, sOpts) + expectedErrMsg = "timestamping: got Timestamper but nil TSARootCAs" + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } } func TestSignBlobWithCertChain(t *testing.T) { @@ -269,7 +314,7 @@ func signRSA(digest []byte, hash crypto.Hash, pk *rsa.PrivateKey) ([]byte, error return rsa.SignPSS(rand.Reader, pk, hash, digest, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}) } -func signECDSA(digest []byte, hash crypto.Hash, pk *ecdsa.PrivateKey) ([]byte, error) { +func signECDSA(digest []byte, pk *ecdsa.PrivateKey) ([]byte, error) { r, s, err := ecdsa.Sign(rand.Reader, pk, digest) if err != nil { return nil, err @@ -289,7 +334,7 @@ func localSign(payload []byte, hash crypto.Hash, pk crypto.PrivateKey) ([]byte, case *rsa.PrivateKey: return signRSA(digest, hash, key) case *ecdsa.PrivateKey: - return signECDSA(digest, hash, key) + return signECDSA(digest, key) default: return nil, errors.New("signing private key not supported") } @@ -354,7 +399,7 @@ func verifySigningAgent(t *testing.T, signingAgentId string, metadata *proto.Get } } -func validateSignWithCerts(t *testing.T, envelopeType string, key crypto.PrivateKey, certs []*x509.Certificate) { +func validateSignWithCerts(t *testing.T, envelopeType string, key crypto.PrivateKey, certs []*x509.Certificate, timestamp bool) { s, err := New(key, certs) if err != nil { t.Fatalf("NewSigner() error = %v", err) @@ -363,6 +408,19 @@ func validateSignWithCerts(t *testing.T, envelopeType string, key crypto.Private ctx := context.Background() desc, sOpts := generateSigningContent() sOpts.SignatureMediaType = envelopeType + if timestamp { + sOpts.Timestamper, err = tspclient.NewHTTPTimestamper(nil, rfc3161URL) + if err != nil { + t.Fatal(err) + } + rootCerts, err := nx509.ReadCertificateFile("./testdata/DigiCertTSARootSHA384.cer") + if err != nil { + t.Fatal(err) + } + rootCAs := x509.NewCertPool() + rootCAs.AddCert(rootCerts[0]) + sOpts.TSARootCAs = rootCAs + } sig, _, err := s.Sign(ctx, desc, sOpts) if err != nil { t.Fatalf("Sign() error = %v", err) diff --git a/signer/testdata/DigiCertTSARootSHA384.cer b/signer/testdata/DigiCertTSARootSHA384.cer new file mode 100644 index 0000000000000000000000000000000000000000..99bcc84b7e68b5b28e4444f6fa21bc7c2baf497d GIT binary patch literal 1428 zcmXqLVx3^n#9Xm}nTe5!Nq}{>bojhJMWaWS?0c7&m&O?IvTn?JkswJuAWqo zP1e*s_a@Ho#N;1}iL*^!vmT3k6D_sp^~v*R*O)lOZ>&mtSAN1{MOt|H{E&z~9_{V^ z%MEUZy*pJM`*`h1|G1~7&kaxCnjCkhufO5ewuv(wCR84-IKFM;k*!%07R&;@H?Ej3 z(PORc_}XMAFtK2DXp^JS_1i4PT6q&0YZQI1>{%zxTpC-EcGJqxWtOqSeva!=o=Xlr zTe%?p?h^Gq3;iv(3Py;3SBY`!Px*c@v!iTAnQdgOQ(1fG^vo)c4-XazNvF*!Id#ul z?m1ubx@TA3Pnu*k&-M<(6Ia#FZL?e?wd)Q{*>Wi{_qFlOqxZd87|ztnOg-HHU2)SU z!R@>2KV9u9&~Z#ywJ}-3WvWzJQr)+P4ZmNcEHl2?$^LNf_GivZBz7z-XMD&%g-20# zQ;4Q&XUw*5U*l71pZrEK z{)j?gcK*iIZQcHduDQm~Rrs?|?&yL3MH}n5)MkEtlBqvKR`=`8m78RrN;5GtGB7T7 zGH@{92PS7(VMfOPEUX61K+1p*B)|_6U;*Z-HUn7@pN~b1MdZ!($4!?CV^e(Y>!sU2 z-!)^M48K2eDg$OPU@Bu|*qwN@c4f{!@gozZ4=-HA(EB(ggFozi`MQFie`k5k+~v@ z;|G_o$XKF&XYNn+bq1|Fzoq+H+4VTN((ZIU8a!-?Xwiwjs2;$JM? zvV8rD@42RPYNEQXEwY&TxuW}v?-ZoX1m*e!D1M{-ku zW1+3RZ-H_fkJp{XOJ|IxwD59pPM7gN@Ge`S#Ng5cOA~=sMNvkM7okS?3O#RXhzIyS z+vj_+bj^iRza4itFI{!{FsqBdj@j%-zaF{nP!7&v%TEujciZY?pQjO3sdj0}ilph6 zfR&$*WHWvetKHnrfA0t)=$1ze_=^}`TkG{L*Rlgt&`^}&Rl)f&LXk-+o%1iN!lfsC)s~w6 z?Tp>inj~vqxWQ7QGU@KxG3!Bhh+^5 ouE}lQ!_OaFs=4ZwaQTyaJ&lTM*#+DM*S6cTUo72o{&QL#0GZBIfB*mh literal 0 HcmV?d00001 diff --git a/verifier/helpers.go b/verifier/helpers.go index 03753fa2..f1835f8d 100644 --- a/verifier/helpers.go +++ b/verifier/helpers.go @@ -57,31 +57,7 @@ func loadX509TrustStores(ctx context.Context, scheme signature.SigningScheme, po default: return nil, truststore.TrustStoreError{Msg: fmt.Sprintf("error while loading the trust store, unrecognized signing scheme %q", scheme)} } - - processedStoreSet := set.New[string]() - var certificates []*x509.Certificate - for _, trustStore := range trustStores { - if processedStoreSet.Contains(trustStore) { - // we loaded this trust store already - continue - } - - storeType, name, found := strings.Cut(trustStore, ":") - if !found { - return nil, truststore.TrustStoreError{Msg: fmt.Sprintf("error while loading the trust store, trust policy statement %q is missing separator in trust store value %q. The required format is :", policyName, trustStore)} - } - if typeToLoad != truststore.Type(storeType) { - continue - } - - certs, err := x509TrustStore.GetCertificates(ctx, typeToLoad, name) - if err != nil { - return nil, err - } - certificates = append(certificates, certs...) - processedStoreSet.Add(trustStore) - } - return certificates, nil + return loadX509TrustStoresWithType(ctx, typeToLoad, policyName, trustStores, x509TrustStore) } // isCriticalFailure checks whether a VerificationResult fails the entire @@ -154,3 +130,56 @@ func getVerificationPluginMinVersion(signerInfo *signature.SignerInfo) (string, } return version, nil } + +func loadX509TSATrustStores(ctx context.Context, scheme signature.SigningScheme, policyName string, trustStores []string, x509TrustStore truststore.X509TrustStore) ([]*x509.Certificate, error) { + var typeToLoad truststore.Type + switch scheme { + case signature.SigningSchemeX509: + typeToLoad = truststore.TypeTSA + default: + return nil, truststore.TrustStoreError{Msg: fmt.Sprintf("error while loading the TSA trust store, signing scheme must be notary.x509, but got %s", scheme)} + } + return loadX509TrustStoresWithType(ctx, typeToLoad, policyName, trustStores, x509TrustStore) +} + +func loadX509TrustStoresWithType(ctx context.Context, trustStoreType truststore.Type, policyName string, trustStores []string, x509TrustStore truststore.X509TrustStore) ([]*x509.Certificate, error) { + processedStoreSet := set.New[string]() + var certificates []*x509.Certificate + for _, trustStore := range trustStores { + if processedStoreSet.Contains(trustStore) { + // we loaded this trust store already + continue + } + + storeType, name, found := strings.Cut(trustStore, ":") + if !found { + return nil, truststore.TrustStoreError{Msg: fmt.Sprintf("error while loading the trust store, trust policy statement %q is missing separator in trust store value %q. The required format is :", policyName, trustStore)} + } + if trustStoreType != truststore.Type(storeType) { + continue + } + + certs, err := x509TrustStore.GetCertificates(ctx, trustStoreType, name) + if err != nil { + return nil, err + } + certificates = append(certificates, certs...) + processedStoreSet.Add(trustStore) + } + return certificates, nil +} + +// isTSATrustStoreInPolicy checks if tsa trust store is configured in +// trust policy +func isTSATrustStoreInPolicy(policyName string, trustStores []string) (bool, error) { + for _, trustStore := range trustStores { + storeType, _, found := strings.Cut(trustStore, ":") + if !found { + return false, truststore.TrustStoreError{Msg: fmt.Sprintf("invalid trust policy statement: %q is missing separator in trust store value %q. The required format is :", policyName, trustStore)} + } + if truststore.Type(storeType) == truststore.TypeTSA { + return true, nil + } + } + return false, nil +} diff --git a/verifier/helpers_test.go b/verifier/helpers_test.go index ee785258..4803d4a1 100644 --- a/verifier/helpers_test.go +++ b/verifier/helpers_test.go @@ -64,17 +64,14 @@ func TestLoadX509TrustStore(t *testing.T) { dummyPolicy.TrustStores = []string{caStore, signingAuthorityStore} dir.UserConfigDir = "testdata" x509truststore := truststore.NewX509TrustStore(dir.ConfigFS()) - caCerts, err := loadX509TrustStores(context.Background(), signature.SigningSchemeX509, dummyPolicy.Name, dummyPolicy.TrustStores, x509truststore) + _, err := loadX509TrustStores(context.Background(), signature.SigningSchemeX509, dummyPolicy.Name, dummyPolicy.TrustStores, x509truststore) if err != nil { t.Fatalf("TestLoadX509TrustStore should not throw error for a valid trust store. Error: %v", err) } - saCerts, err := loadX509TrustStores(context.Background(), signature.SigningSchemeX509SigningAuthority, dummyPolicy.Name, dummyPolicy.TrustStores, x509truststore) + _, err = loadX509TrustStores(context.Background(), signature.SigningSchemeX509SigningAuthority, dummyPolicy.Name, dummyPolicy.TrustStores, x509truststore) if err != nil { t.Fatalf("TestLoadX509TrustStore should not throw error for a valid trust store. Error: %v", err) } - if len(caCerts) != 4 || len(saCerts) != 3 { - t.Fatalf("ca store should have 4 certs and signingAuthority store should have 3 certs") - } } func TestIsCriticalFailure(t *testing.T) { @@ -98,6 +95,34 @@ func TestIsCriticalFailure(t *testing.T) { } } +func TestLoadX509TSATrustStores(t *testing.T) { + policyDoc := trustpolicy.Document{ + Version: "1.0", + TrustPolicies: []trustpolicy.TrustPolicy{ + { + Name: "testTSA", + RegistryScopes: []string{"*"}, + SignatureVerification: trustpolicy.SignatureVerification{VerificationLevel: "strict"}, + TrustStores: []string{"tsa:test-timestamp"}, + TrustedIdentities: []string{"*"}, + }, + }, + } + dir.UserConfigDir = "testdata" + x509truststore := truststore.NewX509TrustStore(dir.ConfigFS()) + policyStatement := policyDoc.TrustPolicies[0] + _, err := loadX509TSATrustStores(context.Background(), signature.SigningSchemeX509, policyStatement.Name, policyStatement.TrustStores, x509truststore) + if err != nil { + t.Fatalf("TestLoadX509TrustStore should not throw error for a valid trust store. Error: %v", err) + } + + _, err = loadX509TSATrustStores(context.Background(), signature.SigningSchemeX509SigningAuthority, policyStatement.Name, policyStatement.TrustStores, x509truststore) + expectedErrMsg := "error while loading the TSA trust store, signing scheme must be notary.x509, but got notary.x509.signingAuthority" + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } +} + func getArtifactDigestFromReference(artifactReference string) (string, error) { invalidUriErr := fmt.Errorf("artifact URI %q could not be parsed, make sure it is the fully qualified OCI artifact URI without the scheme/protocol. e.g domain.com:80/my/repository@sha256:digest", artifactReference) i := strings.LastIndex(artifactReference, "@") diff --git a/verifier/testdata/timestamp/countersignature/TimeStampToken.p7s b/verifier/testdata/timestamp/countersignature/TimeStampToken.p7s new file mode 100644 index 0000000000000000000000000000000000000000..c036aac23cb9bcb4b30960ba940c41a1bdda1805 GIT binary patch literal 6595 zcmc(jcUV)~vcQuN0-*$fNRtwfs+66CUX&uzu>jIUi1dyjbQBVlF1?5fL`6{qgoq#q z5LAjHf(U|$R8gdNkp6-m&*hZ&-SY1FUj9h3%B)#y_L}+49)QGM3xgks)QwzW2Gc>v zB<>P`#9ash)1X-ZW*FQqQWxw<1BHNTK>+b1jPci*@I7ECnb-m)z66Mk5HJ`9KL`Uu z!DI}C20;Ho4vLBpUG<=Uc1IkAST6_LJwrb@SBKpRv^>h<|WzJkbO}TEY<1QL3WO z2hu?EM&vX?Q1lf97Yhc!paCVc0$P^(4Ojs*R83^_JTt%q%?Q9@G-gm3J490(%?)tw zG#Hrn=y-Ua#d(;xI(wnK{H1(xXbC`UXNZOg^<&6)XUNn<1Lfq6M`<|tMl%lHL!}Z-?szsb23v;FNaY8l;q?vSSwCu zEC!IrD1L8Zto{}o03`6u-G`(;bs7>l5k&2eg^<8R&;a0iB_xyC>y~MmlC6WKA5>_| z*wy+syI#IczA>4%Vm4kdrP8u~_S!|wlwgeE>f$`_w=3Gmv2cDSjoq=URIR8COWNlm0p0cEb#f{_}op?HoH{CmK6uBr8asf zhtG?$UPLEDEd9r-)Tex2^YPaw1m$wJ6RS%uJiDlP;Y+qduqb&BRa!mt{(wj}*U1sj zPD6kputn- zq(YDT#8Ra55Mk<*9!A#cv})|*%uRa*igG~=6{k*1;-UL6oJj`V2g5~Z1wLaJzt*`N z2;wBqKxn`q@GTPf8uf`}0to7z;$s1Wx1mrP2wgb9vC|gWX)^%~FnX#>($dn=&;xus z{Rk)r6j^-1hZu-LN)*ipezOGiwA>MfBmjmx!zidWpap3B=Ez`vKo-FKTm%B<5OpCC ze0-H!Jx^SWpBiO zPbsV>9(n9Y8nI>~9ujR>7}jL-x}skAYE>54g~4iE8`n`H*?peOIc*a@$1^;-Q98hf zfr_)pU+jh-l`6kbr@mK+CkW@9SRN^Vbp zC~9~~a>4gw;^60I2mKHoR>KcBJ1gc!P6U5ZDiNgP9-NJ@Jm+&hc}g}n4xPhX-*`y= zpi@_!#yiS>J)w>#wlVVYR$UFp3l1ZUP2uHR%*j3H-sj4z$|l4_RE#V*>9;B*#n}Xp zAG-C4j!rF&8=13K>TEDkPN|^xPRY==F`PzNTE#i};P?@S{peghpS+ zGn(zMWrRG0#quGL6DgO$Wj2?ZzCG9Q>vM>oU$`S!* zN?!9SpLW|5iC+OxFqxKtImX`}I&D5UxDiwCcQcJaA%&ePzjRo+IR9>$W=GHU6KwPI z!CeO@a|}g#Jg+A&3V@I4Hcck3S{F>Noo2<`6;CRhOM7x!FUC;9bHQAN2V`FTBuQEm zM|wA~4I*ZQg3VGNpLO^Oi@a~9?~QF(_+UYMxevUgY9@GTD?~1+A&j#AzNjX9)r>*d zfq;uWm?>|2s%E}>a58jrbt0vc3KmN$STufsg&91_o1)&oDXnf3szca)Uzn&=F+`&P ze(EiRGO}~-qQyyXZ^92soRmki1FSnU7}y#9G2>?^&F;<}jG(Dk83X+I>|jI|O$E!Z z&A*pnB#6-N(|yMYgoTO|2m@rtEoLFZ!2Y$teM46X4R3JdMMje_?&4X+{v?DT>q(LRi)27zBqm*%gV;Txc121 zPz~XP#9tbYZOd!i&zIT^G}emVO6BJ4nMSu&$EtX_)kn`xXD)wS;36Aj@gkz~MTeqa zl0Rn+=PX_~JZxh#=E8>|Jz<%6#zo4TQx2(QT;2gWr*K zpi{6ZZA&vlWsb2lEbQnNM3h>v<3#(Zd(t)Q7HW?!t(jyQSrex41~-{W3fxR@?vGnN zond*GRe5;vnB3fTmJS8>lRYA`QyDYgoX6>(Bz(|#Lvico6782^r#A>%!NO8j*naMjbz0dYDDmdNTkud(Yk5JNlFHb^3P6F;3Ym(SL($!0WpPxNyDq!3}w1aHUXh(>R` zpcwT!%xdTU^7OFjt@r+rbPu=7%|fS_nV_E})(lE`I}`{Pd-$C0%lanrpAS8g(WS;+ zk~toKJlXSsdE|vX3ViN7$bp|Ylc3^EG!`a``iyHNI*(R+7z zFZQ6lmC8PRb9A_yx2tJ3?1i%l894M4B2*&n_=NP&HkC(0yLg28W30zh-48Dh$p65D z3?Ky@BukLRB1QgpJnV=_;pM5^@c?voLIo!F`^+f3TN3N}O)o%RJ0;~sdN{>wG3`bP7H>~htTxROd<^i0hR@;y@B1I71D z>MLX8WzYEXb5kb;w+=1m<|^?N7rvDVMwKoW7Vr&AA+y&q-1r(*n-_X`YfX&ubSy*D z>$NmiMTRB!Tp+G8r{$lYe*|B8Z--Yuo{s9&I`U+VoIZ-OEDvnVb1M*{=7O|3RJh3e zgv-3Trh4n9Q16(>xsBc7_g{kx_9sXFMYt#dm|bweC;?cs;t#x7{g+Yp&uEfP_tm%A zX>}6W9HP3yOg~qq%_vDK(`}rvRxOTrtdW96=6Q#W9cXDRiFR)&k7;kDY$IDwAO$D& z`}SEic12AaDer|%IXE$UrUX1QVpMp%ND z#%~H7c)LwSLJ(cT;yF5i{q)=GCVs@sSm)$(I zyr1%I_)>-M&Bt;D+Vg|i@;AIqW9RUvyriQWPG}z4n>Kx`K{4Z+v9T4S&H_wcF94`M zr||jCq#(WD#upsN;edBN$(a`!JUSspggWHZrqX)E{2Am8XbI!k)^y^K7bAuKA;qFyGz8vL9T2M}Jc$diPN7@`QOGAGp>+#jwH{M6E zv~LdptgDyWu)0glo(@RKV2fiN2K0Ij=?*;hh#o(2zUu!YO0fR{O0a(~O2A-{ zUg4RBhy|-xxC2I+`ge3X!}#$iu}9IoQtVcU)LcF8M9 zm4v6W@|Hmhmx*nJWv;xDA(yt9Fh@(xv1T)+>W&7{>2r!}-GVeM6~;Z*c5Yf_=izVc zaD4?+pfko8{y~aIjwDUe>c}6o{x89K3E)k`z#Kl-)g$9IHp3!=*Pg?%NQym zHdiRx#%l8AW8*MR4zt+W7x9T(dE%MNEj;Lju&VK66V+1A`(NZFS35K%zS!E)6l&t` zl$yI?H3#I-k5rxE~5Nmvv|%Xtv_o+Q8a$zC`7A?5}OUR6@DdcFl0wMI&|_r z6H&*uGgtSD;dN68J? zPDaiYqx3e4)c5MPL(n+xGmkT8iUKMet_IiIK4qV|c6OcFW6;!<;~vciud#^KbN-F4 zmq?sH0*NM|{_g~lzl;&Pto*$cKsBy`dT-tFf~^-!GbaXM_X z`xipxFCeMnJcf>?xjB~DT3=`Vh^8YUfrAgcJiKWn60l0z&l5%}%{>Y>*fJ(f8l^^r zJu1`e*FT!LIG;Kc@wiP+@cB!Zt=13EObS|(V#j7}j>f0=1zU*o$nf>Q1}SJHP95>= zHWAOfu;2{k-`gFVQP$CKD3)iq&)3&~ku&R=KrrHy6nzl`ujIDseKQ10@&);c=jM7( zhNPuJ?c$zmoM7Ld-MWHtPXpi08kNKfD65FPjZ|+{k&Fy{iIYM8GTm$DJ#cZF7H(7{ z{vO}jarU?)|3pe=1iI(pqh=k8!?tJ=jS3-52v*!Ctq)_5Nw;4^-@}SqkMXQj+7IXGF7cMWTG9+Z)>#8ytefgr$vecxc%``7;M?Vv zGl^#@Ba%{8T_s3UZ6}WO^3-eZaPleXuLi5%E@ZdWr?OH=lW#nQM-`xCKf@9vP@kS| z(KX^a7LBOb=hl#e8W{Joje@uAJ3VGVTHWqG9RD>uV&I;XQ{>fgDHQ7V*4AdW0j!?j z7;DOUT_{|2#a3i>=9sGG(8H3h8so+2-q!Z2I#5YMh)EhR+g1Di`mWP?$q9o)9$lE* F{{ssj24?^O literal 0 HcmV?d00001 diff --git a/verifier/testdata/timestamp/countersignature/TimeStampTokenWithInvalidTSTInfo.p7s b/verifier/testdata/timestamp/countersignature/TimeStampTokenWithInvalidTSTInfo.p7s new file mode 100644 index 0000000000000000000000000000000000000000..153ea92f420c97b73ca803085d437cbf20b75c94 GIT binary patch literal 6578 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 sQMDesSKe1|{558%HALhpY0LlUassI20 literal 0 HcmV?d00001 diff --git a/verifier/testdata/timestamp/countersignature/TimeStampTokenWithInvalideContentType.p7s b/verifier/testdata/timestamp/countersignature/TimeStampTokenWithInvalideContentType.p7s new file mode 100644 index 0000000000000000000000000000000000000000..07522e1964033896420b890ec53b8fa203e3ddad GIT binary patch literal 6593 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 literal 0 HcmV?d00001 diff --git a/verifier/testdata/timestamp/sigEnv/coseExpiredWithTimestamp.sig b/verifier/testdata/timestamp/sigEnv/coseExpiredWithTimestamp.sig new file mode 100644 index 0000000000000000000000000000000000000000..450ef17e8c008d50f9142ee97b8965df19649d4a GIT binary patch literal 7365 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 literal 0 HcmV?d00001 diff --git a/verifier/testdata/timestamp/sigEnv/jwsExpiredWithTimestamp.sig b/verifier/testdata/timestamp/sigEnv/jwsExpiredWithTimestamp.sig new file mode 100644 index 00000000..bcf35a74 --- /dev/null +++ b/verifier/testdata/timestamp/sigEnv/jwsExpiredWithTimestamp.sig @@ -0,0 +1 @@ +{"payload":"eyJ0YXJnZXRBcnRpZmFjdCI6eyJkaWdlc3QiOiJzaGEyNTY6YzA2NjllZjM0Y2RjMTQzMzJjMGYxYWIwYzJjMDFhY2I5MWQ5NjAxNGIxNzJmMWE3NmYzYTM5ZTYzZDFmMGJkYSIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuZGlzdHJpYnV0aW9uLm1hbmlmZXN0LnYyK2pzb24iLCJzaXplIjo1Mjh9fQ","protected":"eyJhbGciOiJQUzI1NiIsImNyaXQiOlsiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSJdLCJjdHkiOiJhcHBsaWNhdGlvbi92bmQuY25jZi5ub3RhcnkucGF5bG9hZC52MStqc29uIiwiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSI6Im5vdGFyeS54NTA5IiwiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1RpbWUiOiIyMDI0LTA2LTE4VDE1OjIxOjM4KzA4OjAwIn0","header":{"io.cncf.notary.timestampSignature":"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","x5c":["MIIDQTCCAimgAwIBAgICALAwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3RhcnkxEDAOBgNVBAMTB3Rlc3RUU0EwHhcNMjQwNjE4MDcyMDMxWhcNMjQwNjE4MDczMDMxWjBPMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEQMA4GA1UEAxMHdGVzdFRTQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAM0yrldn1SFss6NnamscsDwjzZmUbCxy+8D11AucTnB9fo5bC2kaQIbe2s0DTD+g1c9TCHi9eB/PZT0izXirhImLnvxXwJTXgUV2Xf+6R8GbEGrK7v5nMXeZ0MJbaJIUqIhE1DCJOkzUDlYQoR2eV00D+BmOkEGIUbxGeKj7eXJuKbI8jB1iUniNKRpMuAz2T7QFLvB5Ma9QIIf2ewsVK8gVFlblbJ5F8qis8Uu6woRoC01ZaZhLxEuguJ5gnZJKfNxbMP4rReZm/PnRx84t+G0rbzsSJEQ8IPT1X0752jjs/6eyhlbdhP155CdVrGYYNgJ0nCBk52KrsD2z2RfDesUCAwEAAaMnMCUwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBAQC+r05Jwr32pWQRt9snm6FCYnLdBnPdthB0QOG27NmBaV3zaL/NkFsxpsy64AYa8pPG3169/6OR5lzfxjwAr8zAdc5ZGfNscdH3zjdQb4VEnhAwbl2vgD3kGE0P6hFwISqjip9OqdlwAWTrX3RSANoam7n6kMjMlIf+ewN3NCg9O+GqFqAGqKkPb7FJJMiQgnUWITxqQ7VD7C7vIe1EYQxsAlNE5ly/hG1MlyqV95U2kFoCilgyCgXpKVo+F5w+wRe22a7v0h8bFRYPdbwMczfg8ugGjUF7MgV6ysuUe1qVEhNGdsZAlrX60rxWokU2XCic/SD52xrggPxNVyhNXxwV"],"io.cncf.notary.signingAgent":"Notation/1.0.0"},"signature":"xH1dvv-SMS8AlDKBzkG6zKKu9VztmCPCGma4HjIUqpohrx1_bVDn-IXU9311cWZcArNNw_UtfbaHYMSFjWVTi_p4brPrPb97tCHV-DeTVhNXrVb_2vf-6EWvDuOOPDyHFN-caVRxz7nBQkKQ4W0N2R-jex8eBXzHzRvY2VTNpowKWPYJKKmTt67zvnCcfnc4tbTPR_IT1bxe75oaxYJw3VwVV5B3-tETw7pczzNSgpeGw9TV2EY0_4Q8_TSk-eV6l0s3DFf-iI_zlhRA4UvpxT2m5LWsJJQuIsXg9or--vD7PmSVYRiM8x8EhkaZUBPen6sUolRXroOchaW4jg0wIQ"} \ No newline at end of file diff --git a/verifier/testdata/timestamp/sigEnv/jwsWithTimestamp.sig b/verifier/testdata/timestamp/sigEnv/jwsWithTimestamp.sig new file mode 100644 index 00000000..ec1c0f4e --- /dev/null +++ b/verifier/testdata/timestamp/sigEnv/jwsWithTimestamp.sig @@ -0,0 +1 @@ +{"payload":"eyJ0YXJnZXRBcnRpZmFjdCI6eyJkaWdlc3QiOiJzaGEyNTY6YzA2NjllZjM0Y2RjMTQzMzJjMGYxYWIwYzJjMDFhY2I5MWQ5NjAxNGIxNzJmMWE3NmYzYTM5ZTYzZDFmMGJkYSIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuZGlzdHJpYnV0aW9uLm1hbmlmZXN0LnYyK2pzb24iLCJzaXplIjo1Mjh9fQ","protected":"eyJhbGciOiJQUzI1NiIsImNyaXQiOlsiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSJdLCJjdHkiOiJhcHBsaWNhdGlvbi92bmQuY25jZi5ub3RhcnkucGF5bG9hZC52MStqc29uIiwiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSI6Im5vdGFyeS54NTA5IiwiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1RpbWUiOiIyMDI0LTA2LTE4VDE0OjI5OjMzKzA4OjAwIn0","header":{"io.cncf.notary.timestampSignature":"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","x5c":["MIIDPjCCAiagAwIBAgIBeTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEPMA0GA1UEAxMGYWxwaW5lMB4XDTIzMDUwOTA0NTUxMloXDTMzMDUxMDA0NTUxMlowTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3RhcnkxDzANBgNVBAMTBmFscGluZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK5hpq1229GGLjMK6i9KZhuUO+SV7rUFnWIDiIPO5yWxYDkl+bGroeAvJYu6MVCMQ6FMRXD9jhnG6R+sAHwY7gVgcJ1OXak87PkLp/Ii1Cr7XkkySZeD+Br1vSQzfxs3pFG+iBCeVVkeZdsg+xqwnAlqAILXwIbTGRyJP1Xiu9nwOeuX1YmxPl2m29Pt1EtfVCL9COsVKt5LgOVyWP/9ISWevOBqSCU9bk35HFo9VTeUf6+ffhSMjv0Y9uwkFFOKXpcV8Sa3ArqyBmgQlUfGg1iwYlqiDE0fTYxiB3gLgETAlmTm50J+WB9LoDrnrQpbXFLoegm+JV+uSD8J8H7DL2sCAwEAAaMnMCUwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBAQAt0Nvna1c4pPn8kzoN5VvmFmeIgdO/BJpmdhdg0WIQ9aeN/xPXXaVjPp1Mk7edXHAvBwQr0Gyzqyy7g/h0gdnAFG7f6blrRNzbrRBCq6cNqX8iwgK/9+2OYKxk1QWj8Gx0cvu1DN1aXjPPGgQ2j3tHjJvJv32J/zuZa8gU40RPPSLaBlc5ZjpFmyi29sKlTeeZ+F/Ssic51qXXw2CsYGGWK5yQ3xSCxbw6bb2G/s/YI7/KlWg9BktBJHzRu04ZNR77W7/dyJ3Lj17PlW1XKmMOFHsQivagXeRCbmYZ43fX4ugFRFKL7KE0EgmGOWpJ0xv+6ig93sqHzQ/0uv1YgFov"],"io.cncf.notary.signingAgent":"Notation/1.0.0"},"signature":"AkYX74o641U6t8_UOmbvykR6UJBI5VdYjFeY7Z3ESggszqbUMA4qhwuYjVuIF-hGEOLj52J4TwjZ-EJ1lxaz249-7LEhwI8N3VC2z_IyCnB4tsam4FfyR7J0lVZcP3haKemuaY5uAM1YYRouaQeuF3Toc_mSBdAjNDqXdS3ouDRFlvzYfyO4phxMQaikNDRM7oAu89aBrWL8RSQawgWaxdJT5rj8RN26D12F4PtG2w7r_8oQamnSBrMcEdl1lQFXBxbl-Yf_QQKjonPIEVcRi79IGgrzIqt00iN0inlm--rhULQ0mQpaAIMG6O0Pf53TzMKBju0WQZ6RbaUuba6kqg"} \ No newline at end of file diff --git a/verifier/testdata/timestamp/sigEnv/timestampAfterNotAfter.sig b/verifier/testdata/timestamp/sigEnv/timestampAfterNotAfter.sig new file mode 100644 index 0000000000000000000000000000000000000000..05a27dbf78af381dcd3fc81a76b16600807f575c GIT binary patch literal 7365 zcmchcc{tSVzsJpD>`Rsj+4p4mj$KW%mR&`5WsI>i%uKdyGh~;@l1R3)gzTX#C2NbU zr9>36Z_$HrMm;@0&vMT1y3Tce#~-e__s_k2-mm-qeEY&JvhISEg~3EWZWpXH+7s<4 z?TICzaQ@PG7bi~_PbU+!GsXi0@jHg{@^W`UqX;foPZ=LihdKlf$o;(>X><%qi%@IQ~{_PYsw3V=!;hXBzMq79HB>HrCRG#dg2fx%#k5`Y0l zBN3q!@r?llqNAh$j1hDI4GeMt3S$LdF!`0BW(Aw8BbWik{SqoxDiaKfKyb$(n8?k^ zIkc=WqaU;VRRzLIMZn+*rY7nD?_mZ208|jl2!w*XoV*n|i8zq_zaNkU5d2pS?1@?-We(LN*;XaAolji4WX%zpHEl^1XfU1@5BwrYMNCk+*sgP zPr#hWq&1y^+*$CVshz5{tlP@VrSj*mXdN6E3cdNh)7&vZY}KF}QF% zh@up=$2tL>Vd;557xS&n8!8m^2Hu#$K4^FI1bvL#4r|X|aCl_VU841JZJsb5ZBx!2 zm{eKVBW??gWCBA#6remYK;*}6@-Trwdr&9@Oce^SlJ}BF1WFIk!l;kIK$MhJ5Xix$ zB%crRQi3R)chIrUwab(ztFg>1VMmjq6Do)f$}(57k2zn^l%V%z5KL(F0Ut{CS)}R2 zMp7fe{mUsTqYj*I%deX)`uJ7@TfRiJOT{jdycQ=u$DMK&3M#XYbvRLVz)kM+N5g1-HpfPWR;Blb}ct!QpaMPp4mVl zrf>AkYk}GN!q4g|Uo(!}s(dq?bI4Ans6)J7-}PC0P)ns|1^m)m%-2G<&OSy}>&Qxo z{tS$p6MDl(WcrqIJw%ajY3?4yr2p~=jUAj#;EkYzHAl+?cp0)pz1XB`VGlWMf8J-M z)@4?L)9=VX`=z=Q#*^T=?+HJ=8zBuy1AYR3sY@U`FP?z%@G>C_1B!4Nhp~h|2T1Ua zKm3pioK1q)k+Z77AP9m1po7uaMd*Mq5GWV~5Vv7;zxyiu{eHp2OpFt8soq(#eYVg{Euvf90HL|Vle?oFgJh%HTkJv%plIo z1n;h-H(FzNQ|Icv*#B}~0qcLZhxPCFAOM*k_OOZ{Fm+#Qf9w`n!ud7T$(EStsLLtu zn{-BgU)%Q00%Q?@9016YwM|Z*JTLj*lmFSpAPZXV!P)*4x`ch9iy;dgk)l%JG@&>w zelWEFsWaHtT{vdiM14PJ%w|USwcW*S8G9I;QeHgEsTeB>U-tbPa zqTQlRq6}w912t1V`fdTLitieryjpPmm}g1G!I*s20(I`3I_o7!wQ5A(s7&-eAzDWu#@e3i$u z?sNX;d?G5ACZ{w#{Yy!*c$#t?O&K!tx8QTRO0J#W4LrsSq9C(i^VZ86Z%sa;(I0}d zcna;myxL8-G}&0Ah}pT3($o7>Xi1<#@{Z*HO>E&m#CBhN59%#7z_Xvv2!%u0o;58- zBBKe6qg9KXN3PPpQa1{@4Vdj0^FxgRLx36vb0X4%pkP4#57!6r0`h?DFZl+8;G)h1 zf*1a{jEt|Zue8$-AKZ5|X*AYD28Z#&;#~+>oWBe}zuzzGzByok0w7-h)ddIyC58dS zP(bBZ4giXf+V7OyCl-zO`fI0Xl#COefJdQGcxM#ZQ=H@h%|DugBb0t`ipQYI()ahq zXbg_<*AAr7I0C@8Z=evA1AvFJ&BEJVrawJ5*H)3sUsh{+-P(vrB`*TG0w44^pbRKx z%V*0*0KX4~#<~A}oPQX@{h&AfU>z7lQ6<|u>$LZNte{#+%XWdc$w#Q`6=cD1z;#+K z4ta^+{{7;NyRyn;y7#tdBA-|V-UhNy9B_u=9ha# z)4*upWI>E5T8N4$y7{Sg@^qT;8F!stX4h`-N>$s|lTrdCw=gs|ttD}HJ1DijxP|-W z-O}rRp+i9)(GqIcN<_Biq7;RKBUZO-U<=}5l2z|+1z>d!!IKqhwAF4C6&Tto;xbN5 zA!h6r{6!grlx0V2@iGS|ZDFUwLMzAOuc3Gx(+=GOSC(;Jd{zj+4=v}ta z(=dtnZIe%G`6F#yc-&o;yc6YXio=?N88?NQUO)XLs#-d}z0G@n6t=PLtUiwzE9&Bn z2GBfrlG^Bww3=<;8N$KyLQlRs8zA@r zUh*k~(y<;sz>xD;Ea4|R&MP8VfkXQ>Xjy6hRpVDC%H?jM$=i-ZO=TD*29*R{FV6M~_}{y(f~7>b+KRWpUrqt!#bDnzaf8)rGGm zG_)D-DXQNuklOJx(u~@@!FhOi5z+HF=7gu~v#908w2hH9j%@vOZpO$0(ebFR?8)?r ztgo2{r);g~YnS>kJ=%1pCo4=%sAAJS>rB&Q3K2;sRs({*Gg^!hUB}Dac`+o30fCO> zU5(TeD|8hhA*XLLMxG47%=MZTNjGj=oUFOJWs+`aO<2I`=Q5C#IO$*CpS60j#59;* zf9k8T!b&DnzY^>DVG;R-)TQ5?W~rMJbOZLTR}6eR%Km1P!FDK8lb7(!OT0StN~1)^ zqwsOY5-dY~&4!2BZVV5NsxYIIXvg%H$VUrkr-~SyT?ZRcCo}VaGGE?NNmR zwSLxs1`KzVL$s`+4{RI&+k@kH;`d6CFBf$ealKrdJ+>JT1xz&h=y$ zovq#sk(i#=ad468yOo36_$I7RunNLOC{%&X`C>D_KPoX8-5ND92-{()sMWn-eED_> zRfORq_SgjpOBKOQi@J$qDVD%9oy`%Xi(PEPR6UfO7 z-cQBhq-fO^y>)?Id*%fm;QPjlSsk&!*vlFrZqL{5x~1?zE#zsV7f5G6_g*RNnrhN1 zK6YU^{-FpztsPG7YzqH?rdHEdcFHurWvyR(zH6~y20)?=BS&Q1e!_)O zd+HG+Os@4RMrUeI``mw?F66h$A2|8>bonFsf6TIfhm#blFZgc9&3U%&E68sQ)GO86 zbdscMo%T6vWLa39dXgMlJ~m`V;zfITlv`VEbZ>j*9^0#PYy$IoAC6eH4@E8-9%qLw zI5^TJg?4L=;**Wm3Zg@d{m|5%EN4A59Ayma{lyK>bH#9lKI9}a20x2=>|h|kt?B&c zBr>M0(sA(mt%nF$ThoMxEbJcdX8l}oUR`q&34QkUGDq~-XD0vk*<3z}J}>Dj(~oaF z@-Ugu35;W=Qr>f{^hE`KoQ*>kSLbi6rRcFxdF;ehM)$nVM)`JH5XuLHj(@W~-ktmY zHqEH5melnX;!E?St>DLJp=kLrw;LQyZis2#2RZQ|-fd~TgW zvG(f6+lo0@)0h>UnWuDA+c^y__Tj_x6(In-=|RU zQ@(@4iD}`q?gL;$LJQl%j>>k}>P5C3XgS@??qb5YCtW3V70QvuwE}h=lWN(rtgzGd zPCTCLP^1@;w(!fIXy4sBlTk<(f4 z_Hba646rcn*QeHPOL5>rGy0!guZruoD9zN+_V;9rz=i8U+n%2K^$LnFlv9{j`!8bJN|nFN9XOn;z+5`d6Va)2ZM zh>3s8k$;fkFp-5Xy*nxAUuLyHvlCsWY+i?tj+Evae>vkfgt=K{U5Jbf1jqDxK7`|^ zF148693(V7c{yd`Hx9C3$lh3aS;< z0y)#qG?n~in`)*rB@G^H9!??vB8C%TkJ*H z@q622UcgN2qQ>ckr#C30w}Q}DPQCUf22y;vS;pum-zu{Gfc6f*+lLdZ2`q6F>RdVj z_-tR7j#`@#QYY`O#S!sih3=&nJz6OHt~{Iz-4#*V1!p*yXxO$cuD=*rK6|-O(Is>0 z3Utg9=2AOKOQT~MId_H4F2JGKMRO^!!(g7{gZq++R9yP_#Z{bYk7;M4(|kUYf%aa1 zJs?D7kigs=kvg1iRh@3mo&Vwyd$dV|Bqh`5XIY#T9P)z(w;L9|@jVbuf%+9f9xW0l z-(3of)yug~5Gklq)$f!vYwYM;Ql79$TK4~z8QwsULV@^$gL_wvsVpzWN@<>-J58TF zzV3L&-*?c|ny*w?>AAL*QMQ&&=iBo1Hui9ujUip#7EIj~m$zqj;R@-CwyOIO_zkU7 z7^PKLJ~M&@(Iv~UHaW5dVE?1{YVhCVRR^Pc*(8t@!1YHUkcJ%n`%|d8mvXDFc?!Ktiy5m$*yd_W+t5J3RSp*`Y>k~CV zEI%+BSO!7N28g!-;w^xf2IZ&o&s8bYV2)oht1_i*PI!6EvOqt4abmP}*!#)sVflFg z4_wN({r_IQKTjD-0)-M3S7JA*YGQepJ_ho}hNM17{QMEZkw$@c85i}@Ha$`3T10DE zBU(GvmvD==Xg$^#P?udP4SgilekkRO$5T!^ntq!Q-V2|`c+8u|w?7mbzhIbkEpoqp zyam#Fo3<6MJ9JNHRac@tgp%;i_M(Y>fkHzti-pJ%uK&!YPat9JPU9K_YBSW`z;--N4Yv5L7|g2X=XM=NF>KL50_ZRm+%96XFl9quXCWe`Ga z&METF;=Ys!-sR8q-bn0iyz3`oNjNe$L+Z8kesjk@3>AhNbXjbNv0;1*xq=qzfk2$Da1IbjIuID(5K z3QZ6^enrp&Z^eeW4#ZwIFy`XvJ4||m?ISfv$0?DWgbyFCYC9VFpFZu) z_WaUz(qhYfEy_9eW+~T}3r44EGR{b32fa;#yqDarsQIkKcE5dCn439Q=z(f8e2aBW zynnR@J>0?Irc+}-Z+b+c$NQ?K%ox$vUGNb7n*@sVYpL)Y`vx}P)R!}>S@BQhsLCDI za0QJUH)JR62`w@F1&TtsN)dIM7Qxzh#O}mdPHkxBknjOdn@|7%*x_(!pF==S-yuD=^lINtbQZES$A literal 0 HcmV?d00001 diff --git a/verifier/testdata/timestamp/sigEnv/timestampBeforeNotBefore.sig b/verifier/testdata/timestamp/sigEnv/timestampBeforeNotBefore.sig new file mode 100644 index 00000000..266a3c2f --- /dev/null +++ b/verifier/testdata/timestamp/sigEnv/timestampBeforeNotBefore.sig @@ -0,0 +1 @@ +{"payload":"eyJ0YXJnZXRBcnRpZmFjdCI6eyJkaWdlc3QiOiJzaGEyNTY6YzA2NjllZjM0Y2RjMTQzMzJjMGYxYWIwYzJjMDFhY2I5MWQ5NjAxNGIxNzJmMWE3NmYzYTM5ZTYzZDFmMGJkYSIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuZGlzdHJpYnV0aW9uLm1hbmlmZXN0LnYyK2pzb24iLCJzaXplIjo1Mjh9fQ","protected":"eyJhbGciOiJQUzI1NiIsImNyaXQiOlsiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSJdLCJjdHkiOiJhcHBsaWNhdGlvbi92bmQuY25jZi5ub3RhcnkucGF5bG9hZC52MStqc29uIiwiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSI6Im5vdGFyeS54NTA5IiwiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1RpbWUiOiIyMDI0LTA2LTE5VDE3OjMwOjExKzA4OjAwIn0","header":{"io.cncf.notary.timestampSignature":"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","x5c":["MIIDRTCCAi2gAwIBAgICAKYwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3RhcnkxEDAOBgNVBAMTB3Rlc3RUU0EwIhgPMjA5OTA5MTgxMTU0MzRaGA8yMTAwMDkxODExNTQzNFowTzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3RhcnkxEDAOBgNVBAMTB3Rlc3RUU0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDI7xKl3GyBZregnHgxUw7rb3yO5jSo31Pa+EhxghQ0/rRKc/1DtfMQURjDYDdjqRmEXq8rVyEAuaBXSKqBMq9bazP7Ot8N/B0OgRCgXwizn//Ha5XfpHqV9lUud4oztdxapejfT6UQSIVqtgWEbZkr4N74G5NV13LlITtWmHpTLo2LfE7jAXTaoCjo/U/eVFFc6X7jyXwaAVyNC2Pi45d/GOaFx/MGHnK6zbN8PeIh5KqInp0UNcHZLBbduxWQhdISULR/x6pVocqExv6zLmRbn5I65wrYL/8gpQPTeZv4S2COpB+25Xy8oyaM6tPa96Pi1NIXtChWO8+muXj1Z4VfAgMBAAGjJzAlMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzANBgkqhkiG9w0BAQsFAAOCAQEAXFaaITvi3skq+czzmbyebtrAa8I9iEbjmWSPjoaUir2NYOLWsyQ7+gkBlMcw5+anP+BC98VBgNVjuQ5oXwdu57xouW7jk/dI5uuKLOFxFdCG7FwW3ycD6GGgj+/2LthxNOxc7CnnMjUuSw2FKJKesiuHQJpdPjgw9cKs+fZF5tr6ZhX4yAUFqouZJ7Hc5JSj3zyEpIbFapVpSAK8O1/mct4KDtt1SmyYn34o55ggyLurrlZ9ctQWHT8xyjc6+b4lEKbilA+xjTt+/BLIs/v/8CVIUzz6OzTCwBraj3kayM7CdGKSysocnJZ/yUcHVw1hLs1+JIMj75i0T6s+GtuT4A=="],"io.cncf.notary.signingAgent":"Notation/1.0.0"},"signature":"pWbiEQRI4e_8nPV2AJPGNHg289WVwqnK7xqH6byLwXjc0hWrkniUSkIPLd3XDhGdpqLbqSLazU3cVTbSphV25aW1GS1G3Qsa3W3wzcwfq5ZhVDmuwO4u_322SAw01s3hVVxXciYK-9bTKkkfHfE_9ZKVSf7zEr28vyuQ92aZd85P-oz3YfvvnAxBGLYp-RPOQNSmtD2IxJWWTNLtwnnntBqr0WdGXS7wWSmUWzcKS9kNEAER1CN8L9SCh2mvBcNfDJlwCoLNaQZK_ZtBIrDQHmQjYkjSBupFTKp_TFic45j79AS7_-4sMdscJbZJzR9Tav7JInMhIKvh0mIfSfkIVQ"} \ No newline at end of file diff --git a/verifier/testdata/timestamp/sigEnv/withoutTimestamp.sig b/verifier/testdata/timestamp/sigEnv/withoutTimestamp.sig new file mode 100644 index 00000000..64d36fbc --- /dev/null +++ b/verifier/testdata/timestamp/sigEnv/withoutTimestamp.sig @@ -0,0 +1 @@ +{"payload":"eyJ0YXJnZXRBcnRpZmFjdCI6eyJkaWdlc3QiOiJzaGEyNTY6YzA2NjllZjM0Y2RjMTQzMzJjMGYxYWIwYzJjMDFhY2I5MWQ5NjAxNGIxNzJmMWE3NmYzYTM5ZTYzZDFmMGJkYSIsIm1lZGlhVHlwZSI6ImFwcGxpY2F0aW9uL3ZuZC5kb2NrZXIuZGlzdHJpYnV0aW9uLm1hbmlmZXN0LnYyK2pzb24iLCJzaXplIjo1Mjh9fQ","protected":"eyJhbGciOiJQUzI1NiIsImNyaXQiOlsiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSJdLCJjdHkiOiJhcHBsaWNhdGlvbi92bmQuY25jZi5ub3RhcnkucGF5bG9hZC52MStqc29uIiwiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1NjaGVtZSI6Im5vdGFyeS54NTA5IiwiaW8uY25jZi5ub3Rhcnkuc2lnbmluZ1RpbWUiOiIyMDI0LTA2LTE4VDE3OjA4OjM1KzA4OjAwIn0","header":{"x5c":["MIIDPjCCAiagAwIBAgIBeTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEPMA0GA1UEAxMGYWxwaW5lMB4XDTIzMDUwOTA0NTUxMloXDTMzMDUxMDA0NTUxMlowTjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3RhcnkxDzANBgNVBAMTBmFscGluZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK5hpq1229GGLjMK6i9KZhuUO+SV7rUFnWIDiIPO5yWxYDkl+bGroeAvJYu6MVCMQ6FMRXD9jhnG6R+sAHwY7gVgcJ1OXak87PkLp/Ii1Cr7XkkySZeD+Br1vSQzfxs3pFG+iBCeVVkeZdsg+xqwnAlqAILXwIbTGRyJP1Xiu9nwOeuX1YmxPl2m29Pt1EtfVCL9COsVKt5LgOVyWP/9ISWevOBqSCU9bk35HFo9VTeUf6+ffhSMjv0Y9uwkFFOKXpcV8Sa3ArqyBmgQlUfGg1iwYlqiDE0fTYxiB3gLgETAlmTm50J+WB9LoDrnrQpbXFLoegm+JV+uSD8J8H7DL2sCAwEAAaMnMCUwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBAQAt0Nvna1c4pPn8kzoN5VvmFmeIgdO/BJpmdhdg0WIQ9aeN/xPXXaVjPp1Mk7edXHAvBwQr0Gyzqyy7g/h0gdnAFG7f6blrRNzbrRBCq6cNqX8iwgK/9+2OYKxk1QWj8Gx0cvu1DN1aXjPPGgQ2j3tHjJvJv32J/zuZa8gU40RPPSLaBlc5ZjpFmyi29sKlTeeZ+F/Ssic51qXXw2CsYGGWK5yQ3xSCxbw6bb2G/s/YI7/KlWg9BktBJHzRu04ZNR77W7/dyJ3Lj17PlW1XKmMOFHsQivagXeRCbmYZ43fX4ugFRFKL7KE0EgmGOWpJ0xv+6ig93sqHzQ/0uv1YgFov"],"io.cncf.notary.signingAgent":"Notation/1.0.0"},"signature":"ToCyclYJtk-Gtb13j1sWW7FQ7iZA9Vq6u_x6nJD3pRkBXhtatvSBsaZ_mqFHKrJWEY3UOBzi2SYobCQYww0cVwbzeDetPhjBhmH-bW-N_pbjGntgB2K1owvJnlycUoOfC2RQ1eDa4mC7Dj1mKzA5Tb-qnNbrT75pvQKZjTY1RZaN6p_xKBJA-AAiQrgHEvlf4m8ZbvqtZ0x4_uiGwfWoNCqPtrZK71mEpPSjfOT3mN5FkZqY0L3jSKRtFRLd1rb0UA2RB-E0CshsNb-hJgTX4SIzUlgcVT10SJnKw0yy_QqrxhMlejOUiV8HHKgbsZqQg1kwFjP5QwzWr5HB6vbRzg"} \ No newline at end of file diff --git a/verifier/testdata/truststore/x509/ca/valid-trust-store/TestTimestamp.crt b/verifier/testdata/truststore/x509/ca/valid-trust-store/TestTimestamp.crt new file mode 100644 index 00000000..dd0094e9 --- /dev/null +++ b/verifier/testdata/truststore/x509/ca/valid-trust-store/TestTimestamp.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDPjCCAiagAwIBAgIBeTANBgkqhkiG9w0BAQsFADBOMQswCQYDVQQGEwJVUzEL +MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEP +MA0GA1UEAxMGYWxwaW5lMB4XDTIzMDUwOTA0NTUxMloXDTMzMDUxMDA0NTUxMlow +TjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8w +DQYDVQQKEwZOb3RhcnkxDzANBgNVBAMTBmFscGluZTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAK5hpq1229GGLjMK6i9KZhuUO+SV7rUFnWIDiIPO5yWx +YDkl+bGroeAvJYu6MVCMQ6FMRXD9jhnG6R+sAHwY7gVgcJ1OXak87PkLp/Ii1Cr7 +XkkySZeD+Br1vSQzfxs3pFG+iBCeVVkeZdsg+xqwnAlqAILXwIbTGRyJP1Xiu9nw +OeuX1YmxPl2m29Pt1EtfVCL9COsVKt5LgOVyWP/9ISWevOBqSCU9bk35HFo9VTeU +f6+ffhSMjv0Y9uwkFFOKXpcV8Sa3ArqyBmgQlUfGg1iwYlqiDE0fTYxiB3gLgETA +lmTm50J+WB9LoDrnrQpbXFLoegm+JV+uSD8J8H7DL2sCAwEAAaMnMCUwDgYDVR0P +AQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsGAQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IB +AQAt0Nvna1c4pPn8kzoN5VvmFmeIgdO/BJpmdhdg0WIQ9aeN/xPXXaVjPp1Mk7ed +XHAvBwQr0Gyzqyy7g/h0gdnAFG7f6blrRNzbrRBCq6cNqX8iwgK/9+2OYKxk1QWj +8Gx0cvu1DN1aXjPPGgQ2j3tHjJvJv32J/zuZa8gU40RPPSLaBlc5ZjpFmyi29sKl +TeeZ+F/Ssic51qXXw2CsYGGWK5yQ3xSCxbw6bb2G/s/YI7/KlWg9BktBJHzRu04Z +NR77W7/dyJ3Lj17PlW1XKmMOFHsQivagXeRCbmYZ43fX4ugFRFKL7KE0EgmGOWpJ +0xv+6ig93sqHzQ/0uv1YgFov +-----END CERTIFICATE----- diff --git a/verifier/testdata/truststore/x509/ca/valid-trust-store/TestTimestampNotYetValid.crt b/verifier/testdata/truststore/x509/ca/valid-trust-store/TestTimestampNotYetValid.crt new file mode 100644 index 00000000..b135a840 --- /dev/null +++ b/verifier/testdata/truststore/x509/ca/valid-trust-store/TestTimestampNotYetValid.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDRTCCAi2gAwIBAgICAKYwDQYJKoZIhvcNAQELBQAwTzELMAkGA1UEBhMCVVMx +CzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3Rhcnkx +EDAOBgNVBAMTB3Rlc3RUU0EwIhgPMjA5OTA5MTgxMTU0MzRaGA8yMTAwMDkxODEx +NTQzNFowTzELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQHEwdTZWF0 +dGxlMQ8wDQYDVQQKEwZOb3RhcnkxEDAOBgNVBAMTB3Rlc3RUU0EwggEiMA0GCSqG +SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDI7xKl3GyBZregnHgxUw7rb3yO5jSo31Pa ++EhxghQ0/rRKc/1DtfMQURjDYDdjqRmEXq8rVyEAuaBXSKqBMq9bazP7Ot8N/B0O +gRCgXwizn//Ha5XfpHqV9lUud4oztdxapejfT6UQSIVqtgWEbZkr4N74G5NV13Ll +ITtWmHpTLo2LfE7jAXTaoCjo/U/eVFFc6X7jyXwaAVyNC2Pi45d/GOaFx/MGHnK6 +zbN8PeIh5KqInp0UNcHZLBbduxWQhdISULR/x6pVocqExv6zLmRbn5I65wrYL/8g +pQPTeZv4S2COpB+25Xy8oyaM6tPa96Pi1NIXtChWO8+muXj1Z4VfAgMBAAGjJzAl +MA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzANBgkqhkiG9w0B +AQsFAAOCAQEAXFaaITvi3skq+czzmbyebtrAa8I9iEbjmWSPjoaUir2NYOLWsyQ7 ++gkBlMcw5+anP+BC98VBgNVjuQ5oXwdu57xouW7jk/dI5uuKLOFxFdCG7FwW3ycD +6GGgj+/2LthxNOxc7CnnMjUuSw2FKJKesiuHQJpdPjgw9cKs+fZF5tr6ZhX4yAUF +qouZJ7Hc5JSj3zyEpIbFapVpSAK8O1/mct4KDtt1SmyYn34o55ggyLurrlZ9ctQW +HT8xyjc6+b4lEKbilA+xjTt+/BLIs/v/8CVIUzz6OzTCwBraj3kayM7CdGKSysoc +nJZ/yUcHVw1hLs1+JIMj75i0T6s+GtuT4A== +-----END CERTIFICATE----- diff --git a/verifier/testdata/truststore/x509/tsa/test-mismatch/wabbit-networks.io.crt b/verifier/testdata/truststore/x509/tsa/test-mismatch/wabbit-networks.io.crt new file mode 100644 index 00000000..60028b63 --- /dev/null +++ b/verifier/testdata/truststore/x509/tsa/test-mismatch/wabbit-networks.io.crt @@ -0,0 +1,20 @@ +-----BEGIN CERTIFICATE----- +MIIDVjCCAj6gAwIBAgIBUTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzEL +MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEb +MBkGA1UEAxMSd2FiYml0LW5ldHdvcmtzLmlvMB4XDTIzMDExOTA4MTkwN1oXDTMz +MDExOTA4MTkwN1owWjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQH +EwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3RhcnkxGzAZBgNVBAMTEndhYmJpdC1uZXR3 +b3Jrcy5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANHhlP+SiY7h +sGlf2mADOzJW/J9siqMkiQvSOx0OSM2yxetfVQL/abi4iqCXM6wkSxviBeNwIoYE +s4thMA8NGEbnKoXktyh9vmiLB1FW7HHr4QLwjgLzgWJKIQTy1JmDBecXZh56d0f3 +w3Yj1IDTvkIScXCNI+5v/08GUQKhyBwv7Fq9MYpo2lfXSI7V33BKKddXIxPGVWwK +GvPE0sg2VV7WM84ZZLdDKz2mq0PtPTHrSwg3hlK/mjn+blg3gsYQ4h9/7Z6nNaF9 +X0SdyESl841ZWrtMhAOFpIzLbz9ete8NRd3bYCRBIr5gscHWTf6lyUgy4xzsSwMH +PsGLM4A+Z00CAwEAAaMnMCUwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsG +AQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBAQAbN0Eru56uTQSC28ZTf8D7VyCkYrrW +LYiJMYdOKBzzKV9mKaM0OGF2uyWwDaPxp9KTdLXmBp9EFq5SXXArFA+nRS7KinDA +e2O7A/9Std2XjKi927rkA2cj239d5lRsjWXqJXf9vAMV9a2FjUM/in2Eevlq7bvj +FE3l26VXCKtOs9ErmfxrL+6ETRKSVYOOG/rSHFv/SB2MlqDg5QsXC9lZjzL5/X/i +oe2qZKhp6X5DPpad1q1Q4ItKdTN+2EXyMyoHn1BJKNba7CUUvXf03EJebT/Im+qo +zfEksJeZJUSlSujANUPoCpsEYGWWQx5G+ViG05Sqs+6ppKrut+P+DVPo +-----END CERTIFICATE----- diff --git a/verifier/testdata/truststore/x509/tsa/test-timestamp/globalsignRoot.cer b/verifier/testdata/truststore/x509/tsa/test-timestamp/globalsignRoot.cer new file mode 100644 index 0000000000000000000000000000000000000000..3492b9555d8a927fc048accbdfd510d973a4bf8a GIT binary patch literal 1415 zcmXqLVr@2PV$NQ`%*4pV#OL~KH*>S`;nq}-Xa8LT4S3l&wc0$|zVk9N@~|=(_!ue} z$gwepvTzHFyXWL5CFTTYrspXH<>!|uI6ErnDg>Ds3L6N5RB#D%AymKwnUMtzrbf z7RhT}D$uKbzGw38+~7wZH9Z3C7XQ;Wl_%Ccc-3RGYRi&upQm~WvFHBn+0=Rd!h*!| z6A>jFt|(i5kF`3r==NOBd$BIM6FxSc4WIO@ZchM9vdR7I$rAgr%{Ey+S)*dM{loih zGQ#1Lx82+H<5BDO;zc`5SGj(AFxPBhen{8HqOd%@j-!E2E}~Q3Ek0^7ZML6Z6u0|l zHZ#w1gFS`jPnW$>4}38Fd-9e>uasbWK_l0SS*5b`tlC%^=G|_%ruy>^>pb;H zpEAqnS3j37ywS{m@&A1T!JnWsAklyin0{sX85#exumCd!n*l$FFAUt}2QM&?2T3clNEnDUU{`>etANRnk)c`j?Td?lrv{y!cYtNV z#LQ-Z{64y*oN&oy5m`>wTczfjL3M=6i0;sxcI$G64QH=U6C z7a^^oy&`9ATM4e8`Et>2H?s`?&tUywgCL-KSq* zf7`U1Go!Z543}AQX18c(@Gc!z{wGJ~Np6%dx#}}_*W2&%>s6+*RIFg${jTxpt@xU5 zuZ0szRF`kI^FE;yw)gmn_ZE+0CVi;XtY?ygew1xBAHBZk2sXLxY73M8i@v-TJt6k1Drt4hk L&8$%;mk0m=(y?My literal 0 HcmV?d00001 diff --git a/verifier/timestamp_test.go b/verifier/timestamp_test.go new file mode 100644 index 00000000..288014de --- /dev/null +++ b/verifier/timestamp_test.go @@ -0,0 +1,421 @@ +// 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 verifier + +import ( + "context" + "crypto/x509" + "net/http" + "os" + "testing" + "time" + + "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-go" + "github.com/notaryproject/notation-go/dir" + "github.com/notaryproject/notation-go/verifier/trustpolicy" + "github.com/notaryproject/notation-go/verifier/truststore" +) + +func TestAuthenticTimestamp(t *testing.T) { + dir.UserConfigDir = "testdata" + trustStore := truststore.NewX509TrustStore(dir.ConfigFS()) + dummyTrustPolicy := &trustpolicy.TrustPolicy{ + Name: "test-timestamp", + RegistryScopes: []string{"*"}, + SignatureVerification: trustpolicy.SignatureVerification{ + VerificationLevel: trustpolicy.LevelStrict.Name, + VerifyTimestamp: trustpolicy.OptionAlways, + }, + TrustStores: []string{"ca:valid-trust-store", "tsa:test-timestamp"}, + TrustedIdentities: []string{"*"}, + } + revocationTimestsampClient, err := revocation.NewTimestamp(&http.Client{Timeout: 5 * time.Second}) + if err != nil { + t.Fatalf("failed to get revocation timestamp client: %v", err) + } + // valid JWS signature envelope with timestamp countersignature + jwsEnvContent, err := parseEnvContent("testdata/timestamp/sigEnv/jwsWithTimestamp.sig", jws.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + + // valid COSE signature envelope with timestamp countersignature + coseEnvContent, err := parseEnvContent("testdata/timestamp/sigEnv/coseWithTimestamp.sig", cose.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + + t.Run("verify Authentic Timestamp with jws format", func(t *testing.T) { + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: jwsEnvContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + if err := authenticTimestampResult.Error; err != nil { + t.Fatalf("expected nil error, but got %s", err) + } + }) + + t.Run("verify Authentic Timestamp with cose format", func(t *testing.T) { + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: coseEnvContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + if err := authenticTimestampResult.Error; err != nil { + t.Fatalf("expected nil error, but got %s", err) + } + }) + + t.Run("verify Authentic Timestamp jws with expired codeSigning cert", func(t *testing.T) { + jwsEnvContent, err := parseEnvContent("testdata/timestamp/sigEnv/jwsExpiredWithTimestamp.sig", jws.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: jwsEnvContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + if err := authenticTimestampResult.Error; err != nil { + t.Fatalf("expected nil error, but got %s", err) + } + }) + + t.Run("verify Authentic Timestamp cose with expired codeSigning cert", func(t *testing.T) { + coseEnvContent, err := parseEnvContent("testdata/timestamp/sigEnv/coseExpiredWithTimestamp.sig", cose.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: coseEnvContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + if err := authenticTimestampResult.Error; err != nil { + t.Fatalf("expected nil error, but got %s", err) + } + }) + + t.Run("verify Authentic Timestamp with afterCertExpiry set", func(t *testing.T) { + dummyTrustPolicy := &trustpolicy.TrustPolicy{ + Name: "test-timestamp", + RegistryScopes: []string{"*"}, + SignatureVerification: trustpolicy.SignatureVerification{ + VerificationLevel: trustpolicy.LevelStrict.Name, + VerifyTimestamp: trustpolicy.OptionAfterCertExpiry, + }, + TrustStores: []string{"ca:valid-trust-store", "tsa:test-timestamp"}, + TrustedIdentities: []string{"*"}, + } + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: coseEnvContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + if err := authenticTimestampResult.Error; err != nil { + t.Fatalf("expected nil error, but got %s", err) + } + }) + + t.Run("verify Authentic Timestamp failed due to invalid trust policy", func(t *testing.T) { + dummyTrustPolicy := &trustpolicy.TrustPolicy{ + Name: "test-timestamp", + RegistryScopes: []string{"*"}, + SignatureVerification: trustpolicy.SignatureVerification{ + VerificationLevel: trustpolicy.LevelStrict.Name, + VerifyTimestamp: trustpolicy.OptionAlways, + }, + TrustStores: []string{"ca:valid-trust-store", "tsa"}, + TrustedIdentities: []string{"*"}, + } + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: jwsEnvContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + expectedErrMsg := "failed to check tsa trust store configuration in turst policy with error: invalid trust policy statement: \"test-timestamp\" is missing separator in trust store value \"tsa\". The required format is :" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("verify Authentic Timestamp failed due to missing tsa in trust policy and expired codeSigning cert", func(t *testing.T) { + dummyTrustPolicy := &trustpolicy.TrustPolicy{ + Name: "test-timestamp", + RegistryScopes: []string{"*"}, + SignatureVerification: trustpolicy.SignatureVerification{ + VerificationLevel: trustpolicy.LevelStrict.Name, + VerifyTimestamp: trustpolicy.OptionAlways, + }, + TrustStores: []string{"ca:valid-trust-store"}, + TrustedIdentities: []string{"*"}, + } + coseEnvContent, err := parseEnvContent("testdata/timestamp/sigEnv/coseExpiredWithTimestamp.sig", cose.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: coseEnvContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + expectedErrMsg := "verification time is after certificate \"CN=testTSA,O=Notary,L=Seattle,ST=WA,C=US\" validity period, it was expired at \"Tue, 18 Jun 2024 07:30:31 +0000\"" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("verify Authentic Timestamp failed due to missing timestamp countersignature", func(t *testing.T) { + envContent, err := parseEnvContent("testdata/timestamp/sigEnv/withoutTimestamp.sig", jws.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: envContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + expectedErrMsg := "no timestamp countersignature was found in the signature envelope" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("verify Authentic Timestamp failed due to invalid timestamp countersignature content type", func(t *testing.T) { + signedToken, err := os.ReadFile("testdata/timestamp/countersignature/TimeStampTokenWithInvalideContentType.p7s") + if err != nil { + t.Fatalf("failed to get signedToken: %v", err) + } + envContent, err := parseEnvContent("testdata/timestamp/sigEnv/withoutTimestamp.sig", jws.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + envContent.SignerInfo.UnsignedAttributes.TimestampSignature = signedToken + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: envContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + expectedErrMsg := "failed to parse timestamp countersignature with error: unexpected content type: 1.2.840.113549.1.7.1" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("verify Authentic Timestamp failed due to invalid TSTInfo", func(t *testing.T) { + signedToken, err := os.ReadFile("testdata/timestamp/countersignature/TimeStampTokenWithInvalidTSTInfo.p7s") + if err != nil { + t.Fatalf("failed to get signedToken: %v", err) + } + envContent, err := parseEnvContent("testdata/timestamp/sigEnv/withoutTimestamp.sig", jws.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + envContent.SignerInfo.UnsignedAttributes.TimestampSignature = signedToken + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: envContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + expectedErrMsg := "failed to get the timestamp TSTInfo with error: cannot unmarshal TSTInfo from timestamp token: asn1: structure error: tags don't match (23 vs {class:0 tag:16 length:3 isCompound:true}) {optional:false explicit:false application:false private:false defaultValue: tag: stringType:0 timeType:24 set:false omitEmpty:false} Time @89" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("verify Authentic Timestamp failed due to failed to validate TSTInfo", func(t *testing.T) { + signedToken, err := os.ReadFile("testdata/timestamp/countersignature/TimeStampToken.p7s") + if err != nil { + t.Fatalf("failed to get signedToken: %v", err) + } + envContent, err := parseEnvContent("testdata/timestamp/sigEnv/withoutTimestamp.sig", jws.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + envContent.SignerInfo.UnsignedAttributes.TimestampSignature = signedToken + envContent.SignerInfo.Signature = []byte("mismatch") + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: envContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + expectedErrMsg := "failed to get timestamp from timestamp countersignature with error: invalid TSTInfo: mismatched message" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("verify Authentic Timestamp failed due to failed to verify timestamp countersignature", func(t *testing.T) { + signedToken, err := os.ReadFile("testdata/timestamp/countersignature/TimeStampTokenWithoutCertificate.p7s") + if err != nil { + t.Fatalf("failed to get signedToken: %v", err) + } + envContent, err := parseEnvContent("testdata/timestamp/sigEnv/withoutTimestamp.sig", jws.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + envContent.SignerInfo.UnsignedAttributes.TimestampSignature = signedToken + envContent.SignerInfo.Signature = []byte("notation") + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: envContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + expectedErrMsg := "failed to verify the timestamp countersignature with error: failed to verify signed token: signing certificate not found in the timestamp token" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("verify Authentic Timestamp failed due to trust store does not exist", func(t *testing.T) { + dummyTrustPolicy := &trustpolicy.TrustPolicy{ + Name: "test-timestamp", + RegistryScopes: []string{"*"}, + SignatureVerification: trustpolicy.SignatureVerification{ + VerificationLevel: trustpolicy.LevelStrict.Name, + VerifyTimestamp: trustpolicy.OptionAlways, + }, + TrustStores: []string{"ca:valid-trust-store", "tsa:does-not-exist"}, + TrustedIdentities: []string{"*"}, + } + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: coseEnvContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + expectedErrMsg := "failed to load tsa trust store with error: the trust store \"does-not-exist\" of type \"tsa\" does not exist" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("verify Authentic Timestamp failed due to empty trust store", func(t *testing.T) { + dummyTrustPolicy := &trustpolicy.TrustPolicy{ + Name: "test-timestamp", + RegistryScopes: []string{"*"}, + SignatureVerification: trustpolicy.SignatureVerification{ + VerificationLevel: trustpolicy.LevelStrict.Name, + VerifyTimestamp: trustpolicy.OptionAlways, + }, + TrustStores: []string{"ca:valid-trust-store", "tsa:test-empty"}, + TrustedIdentities: []string{"*"}, + } + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: coseEnvContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, dummyTrustStore{}, revocationTimestsampClient, outcome) + expectedErrMsg := "no trusted TSA certificate found in trust store" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("verify Authentic Timestamp failed due to tsa not trust", func(t *testing.T) { + dummyTrustPolicy := &trustpolicy.TrustPolicy{ + Name: "test-timestamp", + RegistryScopes: []string{"*"}, + SignatureVerification: trustpolicy.SignatureVerification{ + VerificationLevel: trustpolicy.LevelStrict.Name, + VerifyTimestamp: trustpolicy.OptionAlways, + }, + TrustStores: []string{"ca:valid-trust-store", "tsa:test-mismatch"}, + TrustedIdentities: []string{"*"}, + } + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: coseEnvContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + expectedErrMsg := "failed to verify the timestamp countersignature with error: failed to verify signed token: cms verification failure: x509: certificate signed by unknown authority" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("verify Authentic Timestamp failed due to timestamp before signing cert not before", func(t *testing.T) { + dummyTrustPolicy := &trustpolicy.TrustPolicy{ + Name: "test-timestamp", + RegistryScopes: []string{"*"}, + SignatureVerification: trustpolicy.SignatureVerification{ + VerificationLevel: trustpolicy.LevelStrict.Name, + VerifyTimestamp: trustpolicy.OptionAlways, + }, + TrustStores: []string{"ca:valid-trust-store", "tsa:test-timestamp"}, + TrustedIdentities: []string{"*"}, + } + envContent, err := parseEnvContent("testdata/timestamp/sigEnv/timestampBeforeNotBefore.sig", jws.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: envContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + expectedErrMsg := "timestamp can be before certificate \"CN=testTSA,O=Notary,L=Seattle,ST=WA,C=US\" validity period, it will be valid from \"Fri, 18 Sep 2099 11:54:34 +0000\"" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("verify Authentic Timestamp failed due to timestamp after signing cert not after", func(t *testing.T) { + dummyTrustPolicy := &trustpolicy.TrustPolicy{ + Name: "test-timestamp", + RegistryScopes: []string{"*"}, + SignatureVerification: trustpolicy.SignatureVerification{ + VerificationLevel: trustpolicy.LevelStrict.Name, + VerifyTimestamp: trustpolicy.OptionAlways, + }, + TrustStores: []string{"ca:valid-trust-store", "tsa:test-timestamp"}, + TrustedIdentities: []string{"*"}, + } + envContent, err := parseEnvContent("testdata/timestamp/sigEnv/timestampAfterNotAfter.sig", cose.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: envContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestsampClient, outcome) + expectedErrMsg := "timestamp can be after certificate \"CN=testTSA,O=Notary,L=Seattle,ST=WA,C=US\" validity period, it was expired at \"Tue, 18 Sep 2001 11:54:34 +0000\"" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) +} + +func parseEnvContent(filepath, format string) (*signature.EnvelopeContent, error) { + sigEnvBytes, err := os.ReadFile(filepath) + if err != nil { + return nil, err + } + sigEnv, err := signature.ParseEnvelope(format, sigEnvBytes) + if err != nil { + return nil, err + } + return sigEnv.Content() +} + +type dummyTrustStore struct{} + +func (ts dummyTrustStore) GetCertificates(ctx context.Context, storeType truststore.Type, namedStore string) ([]*x509.Certificate, error) { + return nil, nil +} diff --git a/verifier/trustpolicy/oci_test.go b/verifier/trustpolicy/oci_test.go index 2eff90ec..e0d6beb5 100644 --- a/verifier/trustpolicy/oci_test.go +++ b/verifier/trustpolicy/oci_test.go @@ -175,6 +175,15 @@ func TestValidateInvalidPolicyDocument(t *testing.T) { t.Fatalf("policy statement with invalid SignatureVerification should return error") } + // Invalid SignatureVerification VerifyTimestamp + policyDoc = dummyOCIPolicyDocument() + 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\"" + 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.TrustPolicies[0].TrustStores = []string{} @@ -352,13 +361,32 @@ func TestValidateValidPolicyDocument(t *testing.T) { policyStatement5.TrustedIdentities = []string{"*"} policyStatement5.SignatureVerification = SignatureVerification{VerificationLevel: "strict"} + policyStatement6 := policyStatement1.clone() + policyStatement6.Name = "test-statement-name-6" + policyStatement6.RegistryScopes = []string{"registry.acme-rockets.io/software/net-monitor6"} + policyStatement6.SignatureVerification.VerifyTimestamp = "" + + policyStatement7 := policyStatement1.clone() + policyStatement7.Name = "test-statement-name-7" + policyStatement7.RegistryScopes = []string{"registry.acme-rockets.io/software/net-monitor7"} + policyStatement7.SignatureVerification.VerifyTimestamp = OptionAlways + + policyStatement8 := policyStatement1.clone() + policyStatement8.Name = "test-statement-name-8" + policyStatement8.RegistryScopes = []string{"registry.acme-rockets.io/software/net-monitor8"} + policyStatement8.SignatureVerification.VerifyTimestamp = OptionAfterCertExpiry + policyDoc.TrustPolicies = []OCITrustPolicy{ *policyStatement1, *policyStatement2, *policyStatement3, *policyStatement4, *policyStatement5, + *policyStatement6, + *policyStatement7, + *policyStatement8, } + err := policyDoc.Validate() if err != nil { t.Fatalf("validation failed on a good policy document. Error : %q", err) diff --git a/verifier/trustpolicy/trustpolicy.go b/verifier/trustpolicy/trustpolicy.go index e4f86c85..cbab4275 100644 --- a/verifier/trustpolicy/trustpolicy.go +++ b/verifier/trustpolicy/trustpolicy.go @@ -63,6 +63,19 @@ const ( ActionSkip ValidationAction = "skip" ) +// TimestampOption is an enum for timestamp verifiction options such as Always, +// AfterCertExpiry. +type TimestampOption string + +const ( + // OptionAlways denotes always perform timestamp verification + OptionAlways TimestampOption = "always" + + // OptionAfterCertExpiry denotes perform timestamp verification only if + // the signing certificate chain has expired + OptionAfterCertExpiry TimestampOption = "afterCertExpiry" +) + var ( LevelStrict = &VerificationLevel{ Name: "strict", @@ -136,6 +149,7 @@ var ( type SignatureVerification struct { VerificationLevel string `json:"level"` Override map[ValidationType]ValidationAction `json:"override,omitempty"` + VerifyTimestamp TimestampOption `json:"verifyTimestamp,omitempty"` } type errPolicyNotExist struct{} @@ -263,6 +277,11 @@ func validatePolicyCore(name string, signatureVerification SignatureVerification if err != nil { return fmt.Errorf("trust policy statement %q has invalid signatureVerification: %w", name, err) } + if signatureVerification.VerifyTimestamp != "" && + signatureVerification.VerifyTimestamp != OptionAlways && + signatureVerification.VerifyTimestamp != OptionAfterCertExpiry { + return fmt.Errorf("trust policy statement %q has invalid signatureVerification: verifyTimestamp must be %q or %q, but got %q", name, OptionAlways, OptionAfterCertExpiry, signatureVerification.VerifyTimestamp) + } // Any signature verification other than "skip" needs a trust store and // trusted identities diff --git a/verifier/trustpolicy/trustpolicy_test.go b/verifier/trustpolicy/trustpolicy_test.go index b8cb9dff..f58cadcc 100644 --- a/verifier/trustpolicy/trustpolicy_test.go +++ b/verifier/trustpolicy/trustpolicy_test.go @@ -243,7 +243,7 @@ func TestGetVerificationLevel(t *testing.T) { } else { for index, action := range tt.verificationActions { if action != level.Enforcement[ValidationTypes[index]] { - t.Errorf("%q verification action should be %q for Verification Level %q", ValidationTypes[index], action, tt.verificationLevel) + t.Errorf("%q verification action should be %q for Verification Level %v", ValidationTypes[index], action, tt.verificationLevel) } } } @@ -293,7 +293,7 @@ func TestCustomVerificationLevel(t *testing.T) { } for index, action := range tt.verificationActions { if action != level.Enforcement[ValidationTypes[index]] { - t.Errorf("%q verification action should be %q for custom verification %q", ValidationTypes[index], action, tt.customVerification) + t.Errorf("%q verification action should be %q for custom verification %v", ValidationTypes[index], action, tt.customVerification) } } } @@ -302,6 +302,9 @@ func TestCustomVerificationLevel(t *testing.T) { } func TestGetDocument(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } dir.UserConfigDir = "/" var ociDoc OCIDocument var blobDoc BlobDocument @@ -349,6 +352,9 @@ func TestGetDocumentErrors(t *testing.T) { }) t.Run("invalid json file", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } tempRoot := t.TempDir() path := filepath.Join(tempRoot, "invalid.json") if err := os.WriteFile(path, []byte(`{"invalid`), 0600); err != nil { diff --git a/verifier/truststore/truststore.go b/verifier/truststore/truststore.go index c98b2c6c..067f5e63 100644 --- a/verifier/truststore/truststore.go +++ b/verifier/truststore/truststore.go @@ -36,12 +36,14 @@ type Type string const ( TypeCA Type = "ca" TypeSigningAuthority Type = "signingAuthority" + TypeTSA Type = "tsa" ) var ( Types = []Type{ TypeCA, TypeSigningAuthority, + TypeTSA, } ) diff --git a/verifier/truststore/truststore_test.go b/verifier/truststore/truststore_test.go index 2f223a16..762553e5 100644 --- a/verifier/truststore/truststore_test.go +++ b/verifier/truststore/truststore_test.go @@ -28,13 +28,10 @@ var trustStore = NewX509TrustStore(dir.NewSysFS(filepath.FromSlash("../testdata/ // TestLoadTrustStore tests a valid trust store func TestLoadValidTrustStore(t *testing.T) { - certs, err := trustStore.GetCertificates(context.Background(), "ca", "valid-trust-store") + _, err := trustStore.GetCertificates(context.Background(), "ca", "valid-trust-store") if err != nil { t.Fatalf("could not get certificates from trust store. %q", err) } - if len(certs) != 4 { - t.Fatalf("unexpected number of certificates in the trust store, expected: %d, got: %d", 4, len(certs)) - } } // TestLoadValidTrustStoreWithSelfSignedSigningCertificate tests a valid trust store with self-signed signing certificate diff --git a/verifier/verifier.go b/verifier/verifier.go index 4ba87fec..4eeca168 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -32,6 +32,7 @@ import ( "github.com/notaryproject/notation-core-go/revocation" revocationresult "github.com/notaryproject/notation-core-go/revocation/result" "github.com/notaryproject/notation-core-go/signature" + nx509 "github.com/notaryproject/notation-core-go/x509" "github.com/notaryproject/notation-go" "github.com/notaryproject/notation-go/dir" "github.com/notaryproject/notation-go/internal/envelope" @@ -44,6 +45,7 @@ import ( "github.com/notaryproject/notation-go/verifier/trustpolicy" "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" ) @@ -56,19 +58,24 @@ var algorithms = map[crypto.Hash]digest.Algorithm{ // verifier implements notation.Verifier, notation.BlobVerifier and notation.verifySkipper type verifier struct { - ociTrustPolicyDoc *trustpolicy.OCIDocument - blobTrustPolicyDoc *trustpolicy.BlobDocument - trustStore truststore.X509TrustStore - pluginManager plugin.Manager - revocationClient revocation.Revocation + ociTrustPolicyDoc *trustpolicy.OCIDocument + blobTrustPolicyDoc *trustpolicy.BlobDocument + trustStore truststore.X509TrustStore + pluginManager plugin.Manager + revocationClient revocation.Revocation + revocationTimestampClient revocation.Revocation } // VerifierOptions specifies additional parameters that can be set when using // the NewVerifierWithOptions constructor type VerifierOptions struct { // RevocationClient is an implementation of revocation.Revocation to use for - // verifying revocation + // verifying revocation of code signing certificate chain RevocationClient revocation.Revocation + + // RevocationTimestampClient is an implementaion of evocation.Revocation to + // use for verifying revocation of timestamping certificate chain + RevocationTimestampClient revocation.Revocation } // NewOCIVerifierFromConfig returns a OCI verifier based on local file system @@ -122,6 +129,15 @@ func NewVerifierWithOptions(ociTrustPolicy *trustpolicy.OCIDocument, blobTrustPo } } + revocationTimestampClient := verifierOptions.RevocationTimestampClient + if revocationTimestampClient == nil { + var err error + revocationTimestampClient, err = revocation.NewTimestamp(&http.Client{Timeout: 2 * time.Second}) + if err != nil { + return nil, err + } + } + if trustStore == nil { return nil, errors.New("trustStore cannot be nil") } @@ -143,13 +159,13 @@ func NewVerifierWithOptions(ociTrustPolicy *trustpolicy.OCIDocument, blobTrustPo } return &verifier{ - ociTrustPolicyDoc: ociTrustPolicy, - blobTrustPolicyDoc: blobTrustPolicy, - trustStore: trustStore, - pluginManager: pluginManager, - revocationClient: revocationClient, + ociTrustPolicyDoc: ociTrustPolicy, + blobTrustPolicyDoc: blobTrustPolicy, + trustStore: trustStore, + pluginManager: pluginManager, + revocationClient: revocationClient, + revocationTimestampClient: revocationTimestampClient, }, nil - } // NewFromConfig returns a OCI verifier based on local file system @@ -194,13 +210,13 @@ func (v *verifier) VerifyBlob(ctx context.Context, descGenFunc notation.BlobDesc 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") + return nil, errors.New("blobTrustPolicyDoc is nil") } var trustPolicy *trustpolicy.BlobTrustPolicy var err error if opts.TrustPolicyName == "" { - trustPolicy, err = v.blobTrustPolicyDoc.GetGlobalTrustPolicy(); + trustPolicy, err = v.blobTrustPolicyDoc.GetGlobalTrustPolicy() } else { trustPolicy, err = v.blobTrustPolicyDoc.GetApplicableTrustPolicy(opts.TrustPolicyName) } @@ -220,7 +236,7 @@ func (v *verifier) VerifyBlob(ctx context.Context, descGenFunc notation.BlobDesc logger.Debug("Skipping signature verification") return outcome, nil } - err = v.processSignature(ctx, signature, opts.SignatureMediaType, trustPolicy.Name, trustPolicy.TrustedIdentities, trustPolicy.TrustStores, opts.PluginConfig, outcome) + 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 @@ -282,7 +298,7 @@ func (v *verifier) Verify(ctx context.Context, desc ocispec.Descriptor, signatur 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") + return nil, errors.New("ociTrustPolicyDoc is nil") } trustPolicy, err := v.ociTrustPolicyDoc.GetApplicableTrustPolicy(artifactRef) @@ -303,7 +319,7 @@ func (v *verifier) Verify(ctx context.Context, desc ocispec.Descriptor, signatur logger.Debug("Skipping signature verification") return outcome, nil } - err = v.processSignature(ctx, signature, envelopeMediaType, trustPolicy.Name, trustPolicy.TrustedIdentities, trustPolicy.TrustStores, pluginConfig, outcome) + err = v.processSignature(ctx, signature, envelopeMediaType, trustPolicy.Name, trustPolicy.TrustedIdentities, trustPolicy.TrustStores, trustPolicy.SignatureVerification, pluginConfig, outcome) if err != nil { outcome.Error = err @@ -334,7 +350,7 @@ func (v *verifier) Verify(ctx context.Context, desc ocispec.Descriptor, signatur return outcome, outcome.Error } -func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelopeMediaType, policyName string, trustedIdentities, trustStores []string, pluginConfig map[string]string, outcome *notation.VerificationOutcome) error { +func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelopeMediaType, policyName string, trustedIdentities, trustStores []string, signatureVerification trustpolicy.SignatureVerification, pluginConfig map[string]string, outcome *notation.VerificationOutcome) error { logger := log.GetLogger(ctx) // verify integrity first. notation will always verify integrity no matter @@ -445,7 +461,7 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop // verify authentic timestamp logger.Debug("Validating authentic timestamp") - authenticTimestampResult := verifyAuthenticTimestamp(outcome) + authenticTimestampResult := verifyAuthenticTimestamp(ctx, policyName, trustStores, signatureVerification, v.trustStore, v.revocationTimestampClient, outcome) outcome.VerificationResults = append(outcome.VerificationResults, authenticTimestampResult) logVerificationResult(logger, authenticTimestampResult) if isCriticalFailure(authenticTimestampResult) { @@ -662,51 +678,34 @@ func verifyExpiry(outcome *notation.VerificationOutcome) *notation.ValidationRes } } -func verifyAuthenticTimestamp(outcome *notation.VerificationOutcome) *notation.ValidationResult { - invalidTimestamp := false - var err error - - if signerInfo := outcome.EnvelopeContent.SignerInfo; signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { - // TODO verify RFC3161 TSA signature if present (not in RC1) - // https://github.com/notaryproject/notation-go/issues/78 - if len(signerInfo.UnsignedAttributes.TimestampSignature) == 0 { - // if there is no TSA signature, then every certificate should be - // valid at the time of verification - now := time.Now() - for _, cert := range signerInfo.CertificateChain { - if now.Before(cert.NotBefore) { - invalidTimestamp = true - err = fmt.Errorf("certificate %q is not valid yet, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z)) - break - } - if now.After(cert.NotAfter) { - invalidTimestamp = true - err = fmt.Errorf("certificate %q is not valid anymore, it was expired at %q", cert.Subject, cert.NotAfter.Format(time.RFC1123Z)) - break - } - } - } - } else if signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509SigningAuthority { - authenticSigningTime := signerInfo.SignedAttributes.SigningTime - // TODO use authenticSigningTime from signerInfo - // https://github.com/notaryproject/notation-core-go/issues/38 - for _, cert := range signerInfo.CertificateChain { - if authenticSigningTime.Before(cert.NotBefore) || authenticSigningTime.After(cert.NotAfter) { - invalidTimestamp = true - err = fmt.Errorf("certificate %q was not valid when the digital signature was produced at %q", cert.Subject, authenticSigningTime.Format(time.RFC1123Z)) - break - } - } - } +func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStores []string, signatureVerification trustpolicy.SignatureVerification, x509TrustStore truststore.X509TrustStore, r revocation.Revocation, outcome *notation.VerificationOutcome) *notation.ValidationResult { + logger := log.GetLogger(ctx) - if invalidTimestamp { + signerInfo := outcome.EnvelopeContent.SignerInfo + // under signing scheme notary.x509 + if signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { + logger.Debug("Under signing scheme notary.x509...") return ¬ation.ValidationResult{ - Error: err, + Error: verifyTimestamp(ctx, policyName, trustStores, signatureVerification, x509TrustStore, r, outcome), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } + // under signing scheme notary.x509.signingAuthority + logger.Debug("Under signing scheme notary.x509.signingAuthority...") + authenticSigningTime := signerInfo.SignedAttributes.SigningTime + for _, cert := range signerInfo.CertificateChain { + if authenticSigningTime.Before(cert.NotBefore) || authenticSigningTime.After(cert.NotAfter) { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("certificate %q was not valid when the digital signature was produced at %q", cert.Subject, authenticSigningTime.Format(time.RFC1123Z)), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + } + + // success return ¬ation.ValidationResult{ Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], @@ -724,12 +723,12 @@ func verifyRevocation(outcome *notation.VerificationOutcome, r revocation.Revoca authenticSigningTime, err := outcome.EnvelopeContent.SignerInfo.AuthenticSigningTime() if err != nil { - logger.Debugf("not using authentic signing time due to error retrieving AuthenticSigningTime, err: %v", err) + logger.Debugf("Not using authentic signing time due to error retrieving AuthenticSigningTime, err: %v", err) authenticSigningTime = time.Time{} } certResults, err := r.Validate(outcome.EnvelopeContent.SignerInfo.CertificateChain, authenticSigningTime) if err != nil { - logger.Debug("error while checking revocation status, err: %s", err.Error()) + logger.Debug("Error while checking revocation status, err: %s", err.Error()) return ¬ation.ValidationResult{ Type: trustpolicy.TypeRevocation, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeRevocation], @@ -741,6 +740,23 @@ func verifyRevocation(outcome *notation.VerificationOutcome, r revocation.Revoca Type: trustpolicy.TypeRevocation, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeRevocation], } + finalResult, problematicCertSubject := revocationFinalResult(certResults, outcome.EnvelopeContent.SignerInfo.CertificateChain, logger) + switch finalResult { + case revocationresult.ResultOK: + logger.Debug("No verification impacting errors encountered while checking revocation, status is OK") + case revocationresult.ResultRevoked: + result.Error = fmt.Errorf("signing certificate with subject %q is revoked", problematicCertSubject) + default: + // revocationresult.ResultUnknown + result.Error = fmt.Errorf("signing certificate with subject %q revocation status is unknown", problematicCertSubject) + } + + return result +} + +// revocationFinalResult returns the final revocation result and problematic +// certificate subject if the final result is not ResultOK +func revocationFinalResult(certResults []*revocationresult.CertRevocationResult, certChain []*x509.Certificate, logger log.Logger) (revocationresult.Result, string) { finalResult := revocationresult.ResultUnknown numOKResults := 0 var problematicCertSubject string @@ -748,14 +764,14 @@ func verifyRevocation(outcome *notation.VerificationOutcome, r revocation.Revoca var revokedCertSubject string for i := len(certResults) - 1; i >= 0; i-- { if len(certResults[i].ServerResults) > 0 && certResults[i].ServerResults[0].Error != nil { - logger.Debugf("error for certificate #%d in chain with subject %v for server %q: %v", (i + 1), outcome.EnvelopeContent.SignerInfo.CertificateChain[i].Subject.String(), certResults[i].ServerResults[0].Server, certResults[i].ServerResults[0].Error) + logger.Debugf("Error for certificate #%d in chain with subject %v for server %q: %v", (i + 1), certChain[i].Subject.String(), certResults[i].ServerResults[0].Server, certResults[i].ServerResults[0].Error) } if certResults[i].Result == revocationresult.ResultOK || certResults[i].Result == revocationresult.ResultNonRevokable { numOKResults++ } else { finalResult = certResults[i].Result - problematicCertSubject = outcome.EnvelopeContent.SignerInfo.CertificateChain[i].Subject.String() + problematicCertSubject = certChain[i].Subject.String() if certResults[i].Result == revocationresult.ResultRevoked { revokedFound = true revokedCertSubject = problematicCertSubject @@ -769,18 +785,7 @@ func verifyRevocation(outcome *notation.VerificationOutcome, r revocation.Revoca if numOKResults == len(certResults) { finalResult = revocationresult.ResultOK } - - switch finalResult { - case revocationresult.ResultOK: - logger.Debug("no verification impacting errors encountered while checking revocation, status is OK") - case revocationresult.ResultRevoked: - result.Error = fmt.Errorf("signing certificate with subject %q is revoked", problematicCertSubject) - default: - // revocationresult.ResultUnknown - result.Error = fmt.Errorf("signing certificate with subject %q revocation status is unknown", problematicCertSubject) - } - - return result + return finalResult, problematicCertSubject } func executePlugin(ctx context.Context, installedPlugin pluginframework.VerifyPlugin, capabilitiesToVerify []pluginframework.Capability, envelopeContent *signature.EnvelopeContent, trustedIdentities []string, pluginConfig map[string]string) (*pluginframework.VerifySignatureResponse, error) { @@ -898,3 +903,137 @@ func logVerificationResult(logger log.Logger, result *notation.ValidationResult) func isRequiredVerificationPluginVer(pluginVer string, minPluginVer string) bool { return semver.Compare("v"+pluginVer, "v"+minPluginVer) != -1 } + +// verifyTimestamp provides core verification logic of authentic timestamp under +// signing scheme `notary.x509`. +func verifyTimestamp(ctx context.Context, policyName string, trustStores []string, signatureVerification trustpolicy.SignatureVerification, x509TrustStore truststore.X509TrustStore, r revocation.Revocation, outcome *notation.VerificationOutcome) error { + logger := log.GetLogger(ctx) + + signerInfo := outcome.EnvelopeContent.SignerInfo + performTimestampVerification := true + + // check if tsa trust store is configured in trust policy + tsaEnabled, err := isTSATrustStoreInPolicy(policyName, trustStores) + if err != nil { + return fmt.Errorf("failed to check tsa trust store configuration in turst policy with error: %w", err) + } + if !tsaEnabled { + logger.Info("Timestamp verification disabled: no tsa trust store is configured in trust policy") + performTimestampVerification = false + } + + // check based on 'verifyTimestamp' field + timeOfVerification := time.Now() + if performTimestampVerification && + signatureVerification.VerifyTimestamp == trustpolicy.OptionAfterCertExpiry { + // check if signing cert chain has expired + var expired bool + for _, cert := range signerInfo.CertificateChain { + if timeOfVerification.After(cert.NotAfter) { + expired = true + break + } + } + if !expired { + logger.Infof("Timestamp verification disabled: verifyTimestamp is set to %q and signing cert chain unexpired", trustpolicy.OptionAfterCertExpiry) + performTimestampVerification = false + } + } + + // timestamp verification disabled, signing cert chain MUST be valid + // at time of verification + if !performTimestampVerification { + for _, cert := range signerInfo.CertificateChain { + if timeOfVerification.Before(cert.NotBefore) { + return fmt.Errorf("verification time is before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z)) + } + if timeOfVerification.After(cert.NotAfter) { + return fmt.Errorf("verification time is after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.Format(time.RFC1123Z)) + } + } + + // success + return nil + } + + // Performing timestamp verification + logger.Info("Performing timestamp verification...") + + // 1. Timestamp countersignature MUST be present + logger.Debug("Checking timestamp countersignature existence...") + if len(signerInfo.UnsignedAttributes.TimestampSignature) == 0 { + return errors.New("no timestamp countersignature was found in the signature envelope") + } + + // 2. Verify the timestamp countersignature + logger.Debug("Verifying the timestamp countersignature...") + signedToken, err := tspclient.ParseSignedToken(signerInfo.UnsignedAttributes.TimestampSignature) + if err != nil { + return fmt.Errorf("failed to parse timestamp countersignature with error: %w", err) + } + info, err := signedToken.Info() + if err != nil { + return fmt.Errorf("failed to get the timestamp TSTInfo with error: %w", err) + } + timestamp, err := info.Validate(signerInfo.Signature) + if err != nil { + return fmt.Errorf("failed to get timestamp from timestamp countersignature with error: %w", err) + } + trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, policyName, trustStores, x509TrustStore) + if err != nil { + return fmt.Errorf("failed to load tsa trust store with error: %w", err) + } + if len(trustTSACerts) == 0 { + return errors.New("no trusted TSA certificate found in trust store") + } + rootCertPool := x509.NewCertPool() + for _, trustedCerts := range trustTSACerts { + rootCertPool.AddCert(trustedCerts) + } + tsaCertChain, err := signedToken.Verify(ctx, x509.VerifyOptions{ + CurrentTime: timestamp.Value, + Roots: rootCertPool, + }) + if err != nil { + return fmt.Errorf("failed to verify the timestamp countersignature with error: %w", err) + } + + // 3. Validate timestamping certificate chain + logger.Debug("Validating timestamping certificate chain...") + if err := nx509.ValidateTimestampingCertChain(tsaCertChain); err != nil { + return fmt.Errorf("failed to validate the timestamping certificate chain with error: %w", err) + } + logger.Info("TSA identity is: ", tsaCertChain[0].Subject) + + // 4. Check the timestamp against the signing certificate chain + logger.Debug("Checking the timestamp against the signing certificate chain...") + logger.Debugf("Timestamp range: [%v, %v]", timestamp.Value.Add(-timestamp.Accuracy), timestamp.Value.Add(timestamp.Accuracy)) + for _, cert := range signerInfo.CertificateChain { + if !timestamp.BoundedAfter(cert.NotBefore) { + return fmt.Errorf("timestamp can be before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z)) + } + if !timestamp.BoundedBefore(cert.NotAfter) { + return fmt.Errorf("timestamp can be after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.Format(time.RFC1123Z)) + } + } + + // 5. Perform the timestamping certificate chain revocation check + logger.Debug("Checking timestamping certificate chain revocation...") + certResults, err := r.Validate(tsaCertChain, time.Time{}) + if err != nil { + return fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err) + } + finalResult, problematicCertSubject := revocationFinalResult(certResults, tsaCertChain, logger) + switch finalResult { + case revocationresult.ResultOK: + logger.Debug("No verification impacting errors encountered while checking timestamping certificate chain revocation, status is OK") + case revocationresult.ResultRevoked: + return fmt.Errorf("timestamping certificate with subject %q is revoked", problematicCertSubject) + default: + // revocationresult.ResultUnknown + return fmt.Errorf("timestamping certificate with subject %q revocation status is unknown", problematicCertSubject) + } + + // success + return nil +} diff --git a/verifier/verifier_test.go b/verifier/verifier_test.go index 571c7499..c8104012 100644 --- a/verifier/verifier_test.go +++ b/verifier/verifier_test.go @@ -32,7 +32,6 @@ import ( "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/signature/jws" "github.com/notaryproject/notation-core-go/testhelper" corex509 "github.com/notaryproject/notation-core-go/x509" "github.com/notaryproject/notation-go" @@ -741,7 +740,14 @@ func TestNewVerifierWithOptionsError(t *testing.T) { if err != nil { t.Fatalf("unexpected error while creating revocation object: %v", err) } - opts := VerifierOptions{RevocationClient: r} + rt, err := revocation.NewTimestamp(&http.Client{}) + if err != nil { + t.Fatalf("unexpected error while creating revocation timestamp object: %v", err) + } + opts := VerifierOptions{ + RevocationClient: r, + RevocationTimestampClient: rt, + } _, err = NewVerifierWithOptions(nil, nil, store, pm, opts) if err == nil || err.Error() != "ociTrustPolicy and blobTrustPolicy both cannot be nil" { @@ -1331,9 +1337,7 @@ func verifyResult(outcome *notation.VerificationOutcome, expectedResult notation } // testTrustStore implements truststore.X509TrustStore and returns the trusted certificates for a given trust-store. -type testTrustStore struct { - certs []*x509.Certificate -} +type testTrustStore struct{} func (ts *testTrustStore) GetCertificates(_ context.Context, _ truststore.Type, _ string) ([]*x509.Certificate, error) { block, _ := pem.Decode([]byte(trustedCert))