From 4b4273838666ab22a5f270511006fe43c63adc85 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 1 Dec 2023 11:56:40 +0800 Subject: [PATCH 01/82] initial test Signed-off-by: Patrick Zheng --- go.mod | 2 + go.sum | 4 +- notation.go | 3 ++ signer/signer.go | 1 + verifier/helpers.go | 64 ++++++++++++++--------- verifier/truststore/truststore.go | 1 + verifier/verifier.go | 84 ++++++++++++++++++++++++++----- 7 files changed, 120 insertions(+), 39 deletions(-) diff --git a/go.mod b/go.mod index 0fe94875..6bd5e6a9 100644 --- a/go.mod +++ b/go.mod @@ -22,3 +22,5 @@ require ( github.com/x448/float16 v0.8.4 // indirect golang.org/x/sync v0.4.0 // indirect ) + +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20231201035326-ac03000e2df3 diff --git a/go.sum b/go.sum index 5b4b602d..0d314f7e 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= +github.com/Two-Hearts/notation-core-go v0.0.0-20231201035326-ac03000e2df3 h1:OD7WwvjZ4UjRW6rcG26PYW406zH0BP0y9TpzaGjY6eE= +github.com/Two-Hearts/notation-core-go v0.0.0-20231201035326-ac03000e2df3/go.mod h1:lqk34iYxJ1OpFP3r2gbBKzYIj/1pJ9p7mNULf1KjErY= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -15,8 +17,6 @@ github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOW github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/uuid v1.3.1 h1:KjJaJ9iWZ3jOFZIf1Lqf4laDRCasjl0BCmnEGxkdLb4= github.com/google/uuid v1.3.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/notaryproject/notation-core-go v1.0.1 h1:01doxjDERbd0vocLQrlJdusKrRLNNn50OJzp0c5I4Cw= -github.com/notaryproject/notation-core-go v1.0.1/go.mod h1:rayl8WlKgS4YxOZgDO0iGGB4Ef515ZFZUFaZDmsPXgE= 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-rc5 h1:Ygwkfw9bpDvs+c9E34SdgGOj41dX/cbdlwvlWt0pnFI= diff --git a/notation.go b/notation.go index ef8593c7..ed59e614 100644 --- a/notation.go +++ b/notation.go @@ -54,6 +54,9 @@ type SignerSignOptions struct { // SigningAgent sets the signing agent name SigningAgent string + + // TSA denotes the TSA server URL + TSAServerURL string } // Signer is a generic interface for signing an artifact. diff --git a/signer/signer.go b/signer/signer.go index cefc7788..556fa696 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -110,6 +110,7 @@ func (s *genericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts SigningTime: time.Now(), SigningScheme: signature.SigningSchemeX509, SigningAgent: signingAgentId, + TSAServerURL: opts.TSAServerURL, } // Add expiry only if ExpiryDuration is not zero diff --git a/verifier/helpers.go b/verifier/helpers.go index dfabadb0..a294c32c 100644 --- a/verifier/helpers.go +++ b/verifier/helpers.go @@ -60,31 +60,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 policy.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 :", policy.Name, 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, policy, x509TrustStore) } // isCriticalFailure checks whether a VerificationResult fails the entire @@ -161,3 +137,41 @@ func getVerificationPluginMinVersion(signerInfo *signature.SignerInfo) (string, func isVersionSemverValid(version string) bool { return semVerRegEx.MatchString(version) } + +func loadX509TSATrustStores(ctx context.Context, scheme signature.SigningScheme, policy *trustpolicy.TrustPolicy, 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, policy, x509TrustStore) +} + +func loadX509TrustStoresWithType(ctx context.Context, trustStoreType truststore.Type, policy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore) ([]*x509.Certificate, error) { + processedStoreSet := set.New[string]() + var certificates []*x509.Certificate + for _, trustStore := range policy.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 :", policy.Name, 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 +} diff --git a/verifier/truststore/truststore.go b/verifier/truststore/truststore.go index c98b2c6c..a1659573 100644 --- a/verifier/truststore/truststore.go +++ b/verifier/truststore/truststore.go @@ -36,6 +36,7 @@ type Type string const ( TypeCA Type = "ca" TypeSigningAuthority Type = "signingAuthority" + TypeTSA Type = "tsa" ) var ( diff --git a/verifier/verifier.go b/verifier/verifier.go index bf76494e..28898a54 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -28,6 +28,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" + "github.com/notaryproject/notation-core-go/timestamp" "github.com/notaryproject/notation-go" "github.com/notaryproject/notation-go/dir" "github.com/notaryproject/notation-go/internal/envelope" @@ -284,7 +285,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, trustPolicy, v.trustStore, outcome) outcome.VerificationResults = append(outcome.VerificationResults, authenticTimestampResult) logVerificationResult(logger, authenticTimestampResult) if isCriticalFailure(authenticTimestampResult) { @@ -512,29 +513,88 @@ func verifyExpiry(outcome *notation.VerificationOutcome) *notation.ValidationRes } } -func verifyAuthenticTimestamp(outcome *notation.VerificationOutcome) *notation.ValidationResult { +func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, outcome *notation.VerificationOutcome) *notation.ValidationResult { invalidTimestamp := false var err error if signerInfo := outcome.EnvelopeContent.SignerInfo; signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { + var timeStampLowerLimit time.Time + var timeStampUpperLimit time.Time // 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 + timeStampLowerLimit = time.Now() + timeStampUpperLimit = timeStampLowerLimit + } else { + trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) + if err != nil { + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + if len(trustTSACerts) < 1 { + return ¬ation.ValidationResult{ + Error: notation.ErrorVerificationInconclusive{Msg: "no trusted TSA certificate was found to verify authentic timestamp"}, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + signedToken, err := timestamp.ParseSignedToken(signerInfo.UnsignedAttributes.TimestampSignature) + if err != nil { + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } - 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 + } + roots := x509.NewCertPool() + for _, cert := range trustTSACerts { + roots.AddCert(cert) + } + opts := x509.VerifyOptions{ + Roots: roots, + } + if _, err := signedToken.Verify(opts); err != nil { + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } + info, err := signedToken.Info() + if err != nil { + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + if err := info.VerifyContent(signerInfo.Signature); err != nil { + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + ts, accuracy := info.Timestamp() + timeStampLowerLimit = ts.Add(-accuracy) + timeStampUpperLimit = ts.Add(accuracy) + } + for _, cert := range signerInfo.CertificateChain { + if timeStampLowerLimit.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 timeStampUpperLimit.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 From ca5bba24b0980954910fa749603fd20bc20d5495 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 4 Dec 2023 16:26:11 +0800 Subject: [PATCH 02/82] fix trust store Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- verifier/truststore/truststore.go | 1 + verifier/verifier.go | 2 ++ 4 files changed, 6 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6bd5e6a9..89f99852 100644 --- a/go.mod +++ b/go.mod @@ -23,4 +23,4 @@ require ( golang.org/x/sync v0.4.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20231201035326-ac03000e2df3 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20231204081632-05b04634606c diff --git a/go.sum b/go.sum index 0d314f7e..d1f81fae 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20231201035326-ac03000e2df3 h1:OD7WwvjZ4UjRW6rcG26PYW406zH0BP0y9TpzaGjY6eE= -github.com/Two-Hearts/notation-core-go v0.0.0-20231201035326-ac03000e2df3/go.mod h1:lqk34iYxJ1OpFP3r2gbBKzYIj/1pJ9p7mNULf1KjErY= +github.com/Two-Hearts/notation-core-go v0.0.0-20231204081632-05b04634606c h1:+T5N99gr+CIWQW7z8a0CNQWNmW0HS2rm2AbLRV8BNdo= +github.com/Two-Hearts/notation-core-go v0.0.0-20231204081632-05b04634606c/go.mod h1:lqk34iYxJ1OpFP3r2gbBKzYIj/1pJ9p7mNULf1KjErY= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/verifier/truststore/truststore.go b/verifier/truststore/truststore.go index a1659573..067f5e63 100644 --- a/verifier/truststore/truststore.go +++ b/verifier/truststore/truststore.go @@ -43,6 +43,7 @@ var ( Types = []Type{ TypeCA, TypeSigningAuthority, + TypeTSA, } ) diff --git a/verifier/verifier.go b/verifier/verifier.go index 28898a54..7eb2801f 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -583,8 +583,10 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus ts, accuracy := info.Timestamp() timeStampLowerLimit = ts.Add(-accuracy) timeStampUpperLimit = ts.Add(accuracy) + fmt.Printf("tsa time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) } for _, cert := range signerInfo.CertificateChain { + fmt.Printf("cert validiy time range: [%v, %v]\n", cert.NotBefore, cert.NotAfter) if timeStampLowerLimit.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)) From 8e6bbdb4fe5201ca0651b3e1e4246cf26a91727c Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 15 Jan 2024 14:52:24 +0800 Subject: [PATCH 03/82] initial commits Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- signer/signer.go | 1 + 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 7ba608e7..c30c8f5f 100644 --- a/go.mod +++ b/go.mod @@ -23,4 +23,4 @@ require ( golang.org/x/sync v0.4.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20231204081632-05b04634606c +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240115064451-8f41af02bdf0 diff --git a/go.sum b/go.sum index 67785263..7aef88e6 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20231204081632-05b04634606c h1:+T5N99gr+CIWQW7z8a0CNQWNmW0HS2rm2AbLRV8BNdo= -github.com/Two-Hearts/notation-core-go v0.0.0-20231204081632-05b04634606c/go.mod h1:lqk34iYxJ1OpFP3r2gbBKzYIj/1pJ9p7mNULf1KjErY= +github.com/Two-Hearts/notation-core-go v0.0.0-20240115064451-8f41af02bdf0 h1:0yq4cJuiqusBnu/0+4aacw8MKJRBa91F682V8f7KF7k= +github.com/Two-Hearts/notation-core-go v0.0.0-20240115064451-8f41af02bdf0/go.mod h1:UODkkz67jE/0osUGm8vqDFvdzy10wkXj0qVCfskMoks= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/signer/signer.go b/signer/signer.go index 556fa696..2210c285 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -124,6 +124,7 @@ func (s *genericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts logger.Debugf(" Expiry: %v", signReq.Expiry) logger.Debugf(" SigningScheme: %v", signReq.SigningScheme) logger.Debugf(" SigningAgent: %v", signReq.SigningAgent) + logger.Debugf(" TSAServerURL: %v", signReq.TSAServerURL) // perform signing sigEnv, err := signature.NewEnvelope(opts.SignatureMediaType) From b454646ffe9017138deecf1240af81aefadb60a5 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 15 Jan 2024 15:01:40 +0800 Subject: [PATCH 04/82] initial commits Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index c30c8f5f..cb036a47 100644 --- a/go.mod +++ b/go.mod @@ -23,4 +23,4 @@ require ( golang.org/x/sync v0.4.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240115064451-8f41af02bdf0 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240115065858-01e426868efb diff --git a/go.sum b/go.sum index 7aef88e6..dfc941e1 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240115064451-8f41af02bdf0 h1:0yq4cJuiqusBnu/0+4aacw8MKJRBa91F682V8f7KF7k= -github.com/Two-Hearts/notation-core-go v0.0.0-20240115064451-8f41af02bdf0/go.mod h1:UODkkz67jE/0osUGm8vqDFvdzy10wkXj0qVCfskMoks= +github.com/Two-Hearts/notation-core-go v0.0.0-20240115065858-01e426868efb h1:ZMzek1iFSk+A02pgcovmWPv+sMVl4pMGg1Gi3/jhlJY= +github.com/Two-Hearts/notation-core-go v0.0.0-20240115065858-01e426868efb/go.mod h1:UODkkz67jE/0osUGm8vqDFvdzy10wkXj0qVCfskMoks= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 9cd5aafaea0cb10bddd06119a96c249fbd59d869 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 23 Jan 2024 12:46:05 +0800 Subject: [PATCH 05/82] updated to use tspclient-go Signed-off-by: Patrick Zheng --- go.mod | 5 ++++- go.sum | 6 ++++-- verifier/verifier.go | 6 +++--- 3 files changed, 11 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index cf43c11f..f0d10e25 100644 --- a/go.mod +++ b/go.mod @@ -5,6 +5,7 @@ go 1.20 require ( github.com/go-ldap/ldap/v3 v3.4.6 github.com/notaryproject/notation-core-go v1.0.1 + github.com/notaryproject/tspclient-go v0.0.0-20240122083733-a373599795a2 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0-rc5 github.com/veraison/go-cose v1.1.0 @@ -23,4 +24,6 @@ require ( golang.org/x/sync v0.4.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240115065858-01e426868efb +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240123043947-8ad3eab6de2e + +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240122092120-2bc44d93e3de diff --git a/go.sum b/go.sum index 72d611e0..8f05c2d8 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240115065858-01e426868efb h1:ZMzek1iFSk+A02pgcovmWPv+sMVl4pMGg1Gi3/jhlJY= -github.com/Two-Hearts/notation-core-go v0.0.0-20240115065858-01e426868efb/go.mod h1:UODkkz67jE/0osUGm8vqDFvdzy10wkXj0qVCfskMoks= +github.com/Two-Hearts/notation-core-go v0.0.0-20240123043947-8ad3eab6de2e h1:Y8tQ++n4f1F7jRwIFNcbIEMkqHASU2oSRAQToJEEgWw= +github.com/Two-Hearts/notation-core-go v0.0.0-20240123043947-8ad3eab6de2e/go.mod h1:k7FA8ztvUYy8Cj8tkwYsYhtNentRXsA0RdZaj9cyies= +github.com/Two-Hearts/tspclient-go v0.0.0-20240122092120-2bc44d93e3de h1:hVtfF/PdWNEO6lGPE2ljr7zgAehX6At0oao1abpvo9Q= +github.com/Two-Hearts/tspclient-go v0.0.0-20240122092120-2bc44d93e3de/go.mod h1:Pgt9nPf69t08eVXdxjcfxZalElbQocRuP1DGSKZDpMs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/verifier/verifier.go b/verifier/verifier.go index 3617ef5f..a3cad125 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -28,7 +28,6 @@ import ( "github.com/notaryproject/notation-core-go/revocation" revocationresult "github.com/notaryproject/notation-core-go/revocation/result" "github.com/notaryproject/notation-core-go/signature" - "github.com/notaryproject/notation-core-go/timestamp" "github.com/notaryproject/notation-go" "github.com/notaryproject/notation-go/dir" "github.com/notaryproject/notation-go/internal/envelope" @@ -41,6 +40,7 @@ import ( "github.com/notaryproject/notation-go/plugin/proto" "github.com/notaryproject/notation-go/verifier/trustpolicy" "github.com/notaryproject/notation-go/verifier/truststore" + "github.com/notaryproject/tspclient-go" ocispec "github.com/opencontainers/image-spec/specs-go/v1" "golang.org/x/mod/semver" "oras.land/oras-go/v2/content" @@ -544,7 +544,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - signedToken, err := timestamp.ParseSignedToken(signerInfo.UnsignedAttributes.TimestampSignature) + signedToken, err := tspclient.ParseSignedToken(ctx, signerInfo.UnsignedAttributes.TimestampSignature) if err != nil { return ¬ation.ValidationResult{ Error: err, @@ -559,7 +559,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus opts := x509.VerifyOptions{ Roots: roots, } - if _, err := signedToken.Verify(opts); err != nil { + if _, err := signedToken.Verify(ctx, opts); err != nil { return ¬ation.ValidationResult{ Error: err, Type: trustpolicy.TypeAuthenticTimestamp, From ea97a99e7c3c942126598edeed0a38ee3d0a700d Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 31 Jan 2024 16:36:30 +0800 Subject: [PATCH 06/82] updated tspclient-go Signed-off-by: Patrick Zheng --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 967dd739..ecd43d40 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,6 @@ require ( golang.org/x/sync v0.4.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240123043947-8ad3eab6de2e +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240131082739-3e76750e7e47 -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240122092120-2bc44d93e3de +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240131082004-ba595813cc9d diff --git a/go.sum b/go.sum index 8f05c2d8..e3c738ec 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240123043947-8ad3eab6de2e h1:Y8tQ++n4f1F7jRwIFNcbIEMkqHASU2oSRAQToJEEgWw= -github.com/Two-Hearts/notation-core-go v0.0.0-20240123043947-8ad3eab6de2e/go.mod h1:k7FA8ztvUYy8Cj8tkwYsYhtNentRXsA0RdZaj9cyies= -github.com/Two-Hearts/tspclient-go v0.0.0-20240122092120-2bc44d93e3de h1:hVtfF/PdWNEO6lGPE2ljr7zgAehX6At0oao1abpvo9Q= -github.com/Two-Hearts/tspclient-go v0.0.0-20240122092120-2bc44d93e3de/go.mod h1:Pgt9nPf69t08eVXdxjcfxZalElbQocRuP1DGSKZDpMs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240131082739-3e76750e7e47 h1:W1nlb5g6XVdyJ46WcUnY91Ja+BCfvvgUeuZYOF1Q5VA= +github.com/Two-Hearts/notation-core-go v0.0.0-20240131082739-3e76750e7e47/go.mod h1:FaerqzzTnQn/bqZhph5WGhrGhFOFRDeghTvXAUG1SZA= +github.com/Two-Hearts/tspclient-go v0.0.0-20240131082004-ba595813cc9d h1:RaFc+6Xkky04Y9DHb4BVhq9M1u3yhdoyccgDzcXwSgw= +github.com/Two-Hearts/tspclient-go v0.0.0-20240131082004-ba595813cc9d/go.mod h1:Pgt9nPf69t08eVXdxjcfxZalElbQocRuP1DGSKZDpMs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From fa4eaafc7f2e6236281bc15e1b4e8efa56163474 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 1 Feb 2024 12:58:27 +0800 Subject: [PATCH 07/82] test Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ecd43d40..0c38cc46 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,6 @@ require ( golang.org/x/sync v0.4.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240131082739-3e76750e7e47 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240201045651-5fc45dcf1f9e replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240131082004-ba595813cc9d diff --git a/go.sum b/go.sum index e3c738ec..789527ce 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240131082739-3e76750e7e47 h1:W1nlb5g6XVdyJ46WcUnY91Ja+BCfvvgUeuZYOF1Q5VA= -github.com/Two-Hearts/notation-core-go v0.0.0-20240131082739-3e76750e7e47/go.mod h1:FaerqzzTnQn/bqZhph5WGhrGhFOFRDeghTvXAUG1SZA= +github.com/Two-Hearts/notation-core-go v0.0.0-20240201045651-5fc45dcf1f9e h1:IysWIIIVRtsKXps0UfoiPpcOoWeRVR2eau71WUmihMU= +github.com/Two-Hearts/notation-core-go v0.0.0-20240201045651-5fc45dcf1f9e/go.mod h1:FaerqzzTnQn/bqZhph5WGhrGhFOFRDeghTvXAUG1SZA= github.com/Two-Hearts/tspclient-go v0.0.0-20240131082004-ba595813cc9d h1:RaFc+6Xkky04Y9DHb4BVhq9M1u3yhdoyccgDzcXwSgw= github.com/Two-Hearts/tspclient-go v0.0.0-20240131082004-ba595813cc9d/go.mod h1:Pgt9nPf69t08eVXdxjcfxZalElbQocRuP1DGSKZDpMs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= From dc9c5fe781907346690e804c5bd0ed27e33e2aa9 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 1 Feb 2024 13:11:18 +0800 Subject: [PATCH 08/82] update Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- verifier/verifier.go | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/go.mod b/go.mod index 0c38cc46..750c1bc7 100644 --- a/go.mod +++ b/go.mod @@ -24,6 +24,6 @@ require ( golang.org/x/sync v0.4.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240201045651-5fc45dcf1f9e +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240201050938-182af1affc30 replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240131082004-ba595813cc9d diff --git a/go.sum b/go.sum index 789527ce..cc171242 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240201045651-5fc45dcf1f9e h1:IysWIIIVRtsKXps0UfoiPpcOoWeRVR2eau71WUmihMU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240201045651-5fc45dcf1f9e/go.mod h1:FaerqzzTnQn/bqZhph5WGhrGhFOFRDeghTvXAUG1SZA= +github.com/Two-Hearts/notation-core-go v0.0.0-20240201050938-182af1affc30 h1:0EE/GVxacnp/KykreEfdzqc1HZcESd6w2Q0Q6IzUneo= +github.com/Two-Hearts/notation-core-go v0.0.0-20240201050938-182af1affc30/go.mod h1:FaerqzzTnQn/bqZhph5WGhrGhFOFRDeghTvXAUG1SZA= github.com/Two-Hearts/tspclient-go v0.0.0-20240131082004-ba595813cc9d h1:RaFc+6Xkky04Y9DHb4BVhq9M1u3yhdoyccgDzcXwSgw= github.com/Two-Hearts/tspclient-go v0.0.0-20240131082004-ba595813cc9d/go.mod h1:Pgt9nPf69t08eVXdxjcfxZalElbQocRuP1DGSKZDpMs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= diff --git a/verifier/verifier.go b/verifier/verifier.go index a3cad125..4e3b2f23 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -584,7 +584,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus ts, accuracy := info.Timestamp() timeStampLowerLimit = ts.Add(-accuracy) timeStampUpperLimit = ts.Add(accuracy) - fmt.Printf("tsa time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) + fmt.Printf("timestamp token time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) } for _, cert := range signerInfo.CertificateChain { fmt.Printf("cert validiy time range: [%v, %v]\n", cert.NotBefore, cert.NotAfter) From 3b98cd78ecf46576a156c76556cf2d3136128f63 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 22 Mar 2024 14:44:32 +0800 Subject: [PATCH 09/82] update sign with timestamping Signed-off-by: Patrick Zheng --- go.mod | 8 ++++---- go.sum | 16 ++++++++-------- signer/signer.go | 9 ++++++--- 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/go.mod b/go.mod index 2bebcc57..86c544b2 100644 --- a/go.mod +++ b/go.mod @@ -10,14 +10,14 @@ require ( github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/veraison/go-cose v1.1.0 - golang.org/x/crypto v0.20.0 + golang.org/x/crypto v0.21.0 golang.org/x/mod v0.15.0 oras.land/oras-go/v2 v2.4.0 ) require ( github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect - github.com/fxamacker/cbor/v2 v2.5.0 // indirect + github.com/fxamacker/cbor/v2 v2.6.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.3.1 // indirect @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240201050938-182af1affc30 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240322064059-bf4ea64638b0 -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240131082004-ba595813cc9d +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240322031047-c33159600668 diff --git a/go.sum b/go.sum index aa08be9e..775ad187 100644 --- a/go.sum +++ b/go.sum @@ -1,16 +1,16 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240201050938-182af1affc30 h1:0EE/GVxacnp/KykreEfdzqc1HZcESd6w2Q0Q6IzUneo= -github.com/Two-Hearts/notation-core-go v0.0.0-20240201050938-182af1affc30/go.mod h1:FaerqzzTnQn/bqZhph5WGhrGhFOFRDeghTvXAUG1SZA= -github.com/Two-Hearts/tspclient-go v0.0.0-20240131082004-ba595813cc9d h1:RaFc+6Xkky04Y9DHb4BVhq9M1u3yhdoyccgDzcXwSgw= -github.com/Two-Hearts/tspclient-go v0.0.0-20240131082004-ba595813cc9d/go.mod h1:Pgt9nPf69t08eVXdxjcfxZalElbQocRuP1DGSKZDpMs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240322064059-bf4ea64638b0 h1:CRM7IOv+86vhe82iD8EAGRbi/V+BhTXIEFwGegCP9uE= +github.com/Two-Hearts/notation-core-go v0.0.0-20240322064059-bf4ea64638b0/go.mod h1:cYwg3vrJsiuSC3ID7bG4/q6spGYbBTIr2mqG3ePwrqQ= +github.com/Two-Hearts/tspclient-go v0.0.0-20240322031047-c33159600668 h1:DwEjNM07LP9yYT17LMWEgv4g0UnjmORuyX2aqUgnURE= +github.com/Two-Hearts/tspclient-go v0.0.0-20240322031047-c33159600668/go.mod h1:Pgt9nPf69t08eVXdxjcfxZalElbQocRuP1DGSKZDpMs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= 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.5.0 h1:oHsG0V/Q6E/wqTS2O1Cozzsy69nqCiguo5Q1a1ADivE= -github.com/fxamacker/cbor/v2 v2.5.0/go.mod h1:TA1xS00nchWmaBnEIxPSE5oHLuJBAVvqrtAnWBwBCVo= +github.com/fxamacker/cbor/v2 v2.6.0 h1:sU6J2usfADwWlYDAFhZBQ6TnLFBHxgesMrQfQgk1tWA= +github.com/fxamacker/cbor/v2 v2.6.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.6 h1:ert95MdbiG7aWo/oPYp9btL3KJlMPKnP58r09rI8T+A= @@ -40,8 +40,8 @@ github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5t golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc= -golang.org/x/crypto v0.20.0 h1:jmAMJJZXr5KiCw05dfYK9QnqaqKLYXijU23lsEdcQqg= -golang.org/x/crypto v0.20.0/go.mod h1:Xwo95rrVNIoSMx9wa1JroENMToLWn3RNVrTBpLHgZPQ= +golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= +golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.15.0 h1:SernR4v+D55NyBH2QiEQrlBAnj1ECL6AGrA5+dPaMY8= diff --git a/signer/signer.go b/signer/signer.go index 90c1d03e..af693d36 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -144,9 +144,14 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts return nil, nil, err } + var timestampErr *signature.TimestampError sig, err := sigEnv.Sign(signReq) if err != nil { - return nil, nil, err + if !errors.As(err, ×tampErr) { + return nil, nil, err + } + // warn on timestamping error, but do not fail the signing process + logger.Warnf("Failed to timestamp the signature. Error: %v", timestampErr) } envContent, err := sigEnv.Verify() @@ -156,8 +161,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 } From e5984163c3867f8f0014e20cd7ccdfa9a5548676 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 22 Mar 2024 16:25:08 +0800 Subject: [PATCH 10/82] update timestamp verification Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 +- verifier/verifier.go | 163 ++++++++++++++++++++++--------------------- 3 files changed, 88 insertions(+), 81 deletions(-) diff --git a/go.mod b/go.mod index 5fb2a354..e8973f3f 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240322064059-bf4ea64638b0 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240322074029-e6537801a769 replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240322031047-c33159600668 diff --git a/go.sum b/go.sum index 0dfc6f09..5b61fa77 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240322064059-bf4ea64638b0 h1:CRM7IOv+86vhe82iD8EAGRbi/V+BhTXIEFwGegCP9uE= -github.com/Two-Hearts/notation-core-go v0.0.0-20240322064059-bf4ea64638b0/go.mod h1:cYwg3vrJsiuSC3ID7bG4/q6spGYbBTIr2mqG3ePwrqQ= +github.com/Two-Hearts/notation-core-go v0.0.0-20240322074029-e6537801a769 h1:IjW5HyuNFL1rW29o/dCFoO4J5kXGCrEMOwNTwPyd6fs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240322074029-e6537801a769/go.mod h1:cYwg3vrJsiuSC3ID7bG4/q6spGYbBTIr2mqG3ePwrqQ= github.com/Two-Hearts/tspclient-go v0.0.0-20240322031047-c33159600668 h1:DwEjNM07LP9yYT17LMWEgv4g0UnjmORuyX2aqUgnURE= github.com/Two-Hearts/tspclient-go v0.0.0-20240322031047-c33159600668/go.mod h1:Pgt9nPf69t08eVXdxjcfxZalElbQocRuP1DGSKZDpMs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= diff --git a/verifier/verifier.go b/verifier/verifier.go index d2a1a5de..642ebefc 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -516,111 +516,118 @@ func verifyExpiry(outcome *notation.VerificationOutcome) *notation.ValidationRes } func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, outcome *notation.VerificationOutcome) *notation.ValidationResult { - invalidTimestamp := false - var err error - if signerInfo := outcome.EnvelopeContent.SignerInfo; signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { - var timeStampLowerLimit time.Time - var timeStampUpperLimit time.Time - // TODO verify RFC3161 TSA signature if present (not in RC1) - // https://github.com/notaryproject/notation-go/issues/78 + var needTimestamp bool + for _, cert := range signerInfo.CertificateChain { + if time.Now().Before(cert.NotBefore) || time.Now().After(cert.NotAfter) { + // found at least one cert that current time is not in its + // validity period; need timestamp to continue this step + needTimestamp = true + break + } + } + if !needTimestamp { // this step is a success + return ¬ation.ValidationResult{ + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } if len(signerInfo.UnsignedAttributes.TimestampSignature) == 0 { - // if there is no TSA signature, then every certificate should be - // valid at the time of verification - timeStampLowerLimit = time.Now() - timeStampUpperLimit = timeStampLowerLimit - } else { - trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) - if err != nil { - return ¬ation.ValidationResult{ - Error: err, - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } + // if there is no timestamp token, fail this step + return ¬ation.ValidationResult{ + Error: errors.New("current time is not in certificate chain validity period and no timestamp token was found in the signature envelope"), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } - if len(trustTSACerts) < 1 { - return ¬ation.ValidationResult{ - Error: notation.ErrorVerificationInconclusive{Msg: "no trusted TSA certificate was found to verify authentic timestamp"}, - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } + } + trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) + if err != nil { + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } - signedToken, err := tspclient.ParseSignedToken(ctx, signerInfo.UnsignedAttributes.TimestampSignature) - if err != nil { - return ¬ation.ValidationResult{ - Error: err, - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } + } + if len(trustTSACerts) < 1 { + return ¬ation.ValidationResult{ + Error: errors.New("no trusted TSA root certificate was found in the trust store"), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } - roots := x509.NewCertPool() - for _, cert := range trustTSACerts { - roots.AddCert(cert) + } + signedToken, err := tspclient.ParseSignedToken(ctx, signerInfo.UnsignedAttributes.TimestampSignature) + if err != nil { + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + roots := x509.NewCertPool() + for _, cert := range trustTSACerts { + roots.AddCert(cert) + } + opts := x509.VerifyOptions{ + Roots: roots, + } + // TODO: check revocation of cert chain + if _, err := signedToken.Verify(ctx, opts); err != nil { + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } - opts := x509.VerifyOptions{ - Roots: roots, + } + info, err := signedToken.Info() + if err != nil { + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } - if _, err := signedToken.Verify(ctx, opts); err != nil { - return ¬ation.ValidationResult{ - Error: err, - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } + } + if err := info.VerifyContent(signerInfo.Signature); err != nil { + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } - info, err := signedToken.Info() - if err != nil { + } + // consume the timestamp + ts, accuracy := info.Timestamp() + timeStampLowerLimit := ts.Add(-accuracy) + timeStampUpperLimit := ts.Add(accuracy) + fmt.Printf("timestamp token time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) + for _, cert := range signerInfo.CertificateChain { + if timeStampLowerLimit.Before(cert.NotBefore) { return ¬ation.ValidationResult{ - Error: err, + Error: fmt.Errorf("timestamp lower limit %q is before certificate %q validity period , it will be valid from %q", timeStampLowerLimit.Format(time.RFC1123Z), cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - if err := info.VerifyContent(signerInfo.Signature); err != nil { + if timeStampUpperLimit.After(cert.NotAfter) { return ¬ation.ValidationResult{ - Error: err, + Error: fmt.Errorf("timestamp upper limit %q is after certificate %q validity period, it was expired at %q", timeStampUpperLimit.Format(time.RFC1123Z), cert.Subject, cert.NotAfter.Format(time.RFC1123Z)), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - ts, accuracy := info.Timestamp() - timeStampLowerLimit = ts.Add(-accuracy) - timeStampUpperLimit = ts.Add(accuracy) - fmt.Printf("timestamp token time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) - } - for _, cert := range signerInfo.CertificateChain { - fmt.Printf("cert validiy time range: [%v, %v]\n", cert.NotBefore, cert.NotAfter) - if timeStampLowerLimit.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 timeStampUpperLimit.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 + 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], + } } } } - if invalidTimestamp { - return ¬ation.ValidationResult{ - Error: err, - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - + // this step is a success return ¬ation.ValidationResult{ Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], From be2ea0e3a52ad7d3ca6d157cf2d19d1adf54b89a Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 27 Mar 2024 16:30:59 +0800 Subject: [PATCH 11/82] updated timestmap Signed-off-by: Patrick Zheng --- go.mod | 8 +++++--- go.sum | 8 ++++---- verifier/verifier.go | 8 ++++---- 3 files changed, 13 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index e8973f3f..2a08e992 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,8 @@ module github.com/notaryproject/notation-go -go 1.20 +go 1.21 + +toolchain go1.21.4 require ( github.com/go-ldap/ldap/v3 v3.4.6 @@ -25,6 +27,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240322074029-e6537801a769 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240327082239-e085696162b1 -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240322031047-c33159600668 +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0 diff --git a/go.sum b/go.sum index 5b61fa77..e94cf25e 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240322074029-e6537801a769 h1:IjW5HyuNFL1rW29o/dCFoO4J5kXGCrEMOwNTwPyd6fs= -github.com/Two-Hearts/notation-core-go v0.0.0-20240322074029-e6537801a769/go.mod h1:cYwg3vrJsiuSC3ID7bG4/q6spGYbBTIr2mqG3ePwrqQ= -github.com/Two-Hearts/tspclient-go v0.0.0-20240322031047-c33159600668 h1:DwEjNM07LP9yYT17LMWEgv4g0UnjmORuyX2aqUgnURE= -github.com/Two-Hearts/tspclient-go v0.0.0-20240322031047-c33159600668/go.mod h1:Pgt9nPf69t08eVXdxjcfxZalElbQocRuP1DGSKZDpMs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240327082239-e085696162b1 h1:VFaRt48d2PQ97WY3u4sWWgWpIBHSzid6UjiJG+0Ydcw= +github.com/Two-Hearts/notation-core-go v0.0.0-20240327082239-e085696162b1/go.mod h1:GsHR/83xmdubOk+77PlzIilthZNt+qCY4I9BxMKXbxg= +github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0 h1:EbUo6vzeco2sq3ipHCL7JtsgAwOXNiM7BRRRLVp2o3U= +github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/verifier/verifier.go b/verifier/verifier.go index 642ebefc..6e793ca0 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -570,7 +570,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus opts := x509.VerifyOptions{ Roots: roots, } - // TODO: check revocation of cert chain + // TODO: validate and check revocation of cert chain if _, err := signedToken.Verify(ctx, opts); err != nil { return ¬ation.ValidationResult{ Error: err, @@ -586,15 +586,15 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - if err := info.VerifyContent(signerInfo.Signature); err != nil { + // validate and consume the timestamp + ts, accuracy, err := info.Timestamp(signerInfo.Signature) + if err != nil { return ¬ation.ValidationResult{ Error: err, Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - // consume the timestamp - ts, accuracy := info.Timestamp() timeStampLowerLimit := ts.Add(-accuracy) timeStampUpperLimit := ts.Add(accuracy) fmt.Printf("timestamp token time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) From c8f8e4ead7c787922b743f9862bbdf08fbf89ba0 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 27 Mar 2024 16:46:47 +0800 Subject: [PATCH 12/82] updated timestamp Signed-off-by: Patrick Zheng --- verifier/verifier.go | 17 ++++++++++++++--- 1 file changed, 14 insertions(+), 3 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 6e793ca0..f9b5cfff 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -31,6 +31,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" @@ -570,14 +571,24 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus opts := x509.VerifyOptions{ Roots: roots, } - // TODO: validate and check revocation of cert chain - if _, err := signedToken.Verify(ctx, opts); err != nil { + // TODO: check revocation of cert chain + tsaCertChain, err := signedToken.Verify(ctx, opts) + if err != nil { + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + // validate TSA cert chain + if err := nx509.ValidateTimeStampingCertChain(tsaCertChain, nil); err != nil { return ¬ation.ValidationResult{ Error: err, Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } + // get the timestamp token info info, err := signedToken.Info() if err != nil { return ¬ation.ValidationResult{ @@ -586,7 +597,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - // validate and consume the timestamp + // validate the info and consume timestamp ts, accuracy, err := info.Timestamp(signerInfo.Signature) if err != nil { return ¬ation.ValidationResult{ From 200a071d04c065035b77840d614faa8303737cad Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 8 Apr 2024 11:07:51 +0800 Subject: [PATCH 13/82] added tsa cert chain revocation check Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 +-- verifier/verifier.go | 76 +++++++++++++++++++++++++++++++++++--------- 3 files changed, 64 insertions(+), 18 deletions(-) diff --git a/go.mod b/go.mod index 0fa06802..41d100e9 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240327082239-e085696162b1 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240408025912-2338257358ed replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0 diff --git a/go.sum b/go.sum index ef723996..81ab8b82 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240327082239-e085696162b1 h1:VFaRt48d2PQ97WY3u4sWWgWpIBHSzid6UjiJG+0Ydcw= -github.com/Two-Hearts/notation-core-go v0.0.0-20240327082239-e085696162b1/go.mod h1:GsHR/83xmdubOk+77PlzIilthZNt+qCY4I9BxMKXbxg= +github.com/Two-Hearts/notation-core-go v0.0.0-20240408025912-2338257358ed h1:9HuLSjZdpwFQXxeL0N/dy/9N1nmxNsqnI6jHiud5Wjo= +github.com/Two-Hearts/notation-core-go v0.0.0-20240408025912-2338257358ed/go.mod h1:GsHR/83xmdubOk+77PlzIilthZNt+qCY4I9BxMKXbxg= github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0 h1:EbUo6vzeco2sq3ipHCL7JtsgAwOXNiM7BRRRLVp2o3U= github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= diff --git a/verifier/verifier.go b/verifier/verifier.go index f9b5cfff..5e58994a 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -517,6 +517,9 @@ func verifyExpiry(outcome *notation.VerificationOutcome) *notation.ValidationRes } func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, outcome *notation.VerificationOutcome) *notation.ValidationResult { + logger := log.GetLogger(ctx) + + // under signing scheme notary.x509 if signerInfo := outcome.EnvelopeContent.SignerInfo; signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { var needTimestamp bool for _, cert := range signerInfo.CertificateChain { @@ -571,7 +574,6 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus opts := x509.VerifyOptions{ Roots: roots, } - // TODO: check revocation of cert chain tsaCertChain, err := signedToken.Verify(ctx, opts) if err != nil { return ¬ation.ValidationResult{ @@ -609,6 +611,43 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus timeStampLowerLimit := ts.Add(-accuracy) timeStampUpperLimit := ts.Add(accuracy) fmt.Printf("timestamp token time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) + // TSA certificate chain revocation check + revocationClient, err := revocation.New(&http.Client{Timeout: 2 * time.Second}) + if err != nil { + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + certResults, err := revocationClient.Validate(tsaCertChain, timeStampUpperLimit) + if err != nil { + logger.Debug("error while checking revocation status, err: %s", err.Error()) + return ¬ation.ValidationResult{ + Error: err, + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + finalResult, problematicCertSubject := revocationFinalResult(certResults, tsaCertChain, logger) + switch finalResult { + case revocationresult.ResultOK: + logger.Debug("no verification impacting errors encountered while checking TSA certificate chain revocation, status is OK") + case revocationresult.ResultRevoked: + return ¬ation.ValidationResult{ + Error: fmt.Errorf("TSA certificate with subject %q is revoked", problematicCertSubject), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + default: + // revocationresult.ResultUnknown + return ¬ation.ValidationResult{ + Error: fmt.Errorf("TSA certificate with subject %q revocation status is unknown", problematicCertSubject), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + // timestamp core process for _, cert := range signerInfo.CertificateChain { if timeStampLowerLimit.Before(cert.NotBefore) { return ¬ation.ValidationResult{ @@ -626,6 +665,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } } else if signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509SigningAuthority { + // under signing scheme notary.x509.signingAuthority authenticSigningTime := signerInfo.SignedAttributes.SigningTime for _, cert := range signerInfo.CertificateChain { if authenticSigningTime.Before(cert.NotBefore) || authenticSigningTime.After(cert.NotAfter) { @@ -673,6 +713,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 @@ -680,14 +737,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 @@ -701,18 +758,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, trustPolicy *trustpolicy.TrustPolicy, capabilitiesToVerify []pluginframework.Capability, envelopeContent *signature.EnvelopeContent, pluginConfig map[string]string) (*pluginframework.VerifySignatureResponse, error) { From 53ee15c5b70c082b9fc5b47bfc9adf32f2b76e9a Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 8 Apr 2024 13:39:12 +0800 Subject: [PATCH 14/82] update tsa Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 41d100e9..50ec0b56 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240408025912-2338257358ed +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240408053347-db08071e1dba replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0 diff --git a/go.sum b/go.sum index 81ab8b82..8f7b780c 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240408025912-2338257358ed h1:9HuLSjZdpwFQXxeL0N/dy/9N1nmxNsqnI6jHiud5Wjo= -github.com/Two-Hearts/notation-core-go v0.0.0-20240408025912-2338257358ed/go.mod h1:GsHR/83xmdubOk+77PlzIilthZNt+qCY4I9BxMKXbxg= +github.com/Two-Hearts/notation-core-go v0.0.0-20240408053347-db08071e1dba h1:NkrPabtr/MVAsD2NZVkJGkbvnOjoG6wCQPvXIPluyqw= +github.com/Two-Hearts/notation-core-go v0.0.0-20240408053347-db08071e1dba/go.mod h1:GsHR/83xmdubOk+77PlzIilthZNt+qCY4I9BxMKXbxg= github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0 h1:EbUo6vzeco2sq3ipHCL7JtsgAwOXNiM7BRRRLVp2o3U= github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= From e5aaefee24f78f69e235112bbce68b98a88fc774 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 8 Apr 2024 14:13:47 +0800 Subject: [PATCH 15/82] added tsa ocsp check Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- verifier/verifier.go | 10 +--------- 3 files changed, 4 insertions(+), 12 deletions(-) diff --git a/go.mod b/go.mod index 50ec0b56..714b5b97 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240408053347-db08071e1dba +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240408061121-8c59a124c1ff replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0 diff --git a/go.sum b/go.sum index 8f7b780c..4da3fd58 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240408053347-db08071e1dba h1:NkrPabtr/MVAsD2NZVkJGkbvnOjoG6wCQPvXIPluyqw= -github.com/Two-Hearts/notation-core-go v0.0.0-20240408053347-db08071e1dba/go.mod h1:GsHR/83xmdubOk+77PlzIilthZNt+qCY4I9BxMKXbxg= +github.com/Two-Hearts/notation-core-go v0.0.0-20240408061121-8c59a124c1ff h1:FiCD0T10oRjvO3ADmrkpaiYBZA1U91SfYEK8UTDqDbQ= +github.com/Two-Hearts/notation-core-go v0.0.0-20240408061121-8c59a124c1ff/go.mod h1:GsHR/83xmdubOk+77PlzIilthZNt+qCY4I9BxMKXbxg= github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0 h1:EbUo6vzeco2sq3ipHCL7JtsgAwOXNiM7BRRRLVp2o3U= github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= diff --git a/verifier/verifier.go b/verifier/verifier.go index 5e58994a..ed27cb03 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -612,15 +612,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus timeStampUpperLimit := ts.Add(accuracy) fmt.Printf("timestamp token time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) // TSA certificate chain revocation check - revocationClient, err := revocation.New(&http.Client{Timeout: 2 * time.Second}) - if err != nil { - return ¬ation.ValidationResult{ - Error: err, - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - certResults, err := revocationClient.Validate(tsaCertChain, timeStampUpperLimit) + certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit) if err != nil { logger.Debug("error while checking revocation status, err: %s", err.Error()) return ¬ation.ValidationResult{ From 2e674e4cb276fb982e0798e8ca1a2f10709b09af Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 8 Apr 2024 15:39:41 +0800 Subject: [PATCH 16/82] updated timestamping Signed-off-by: Patrick Zheng --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 714b5b97..909af822 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240408061121-8c59a124c1ff +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240408072948-cbde6f956cbe -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0 +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240408072521-32657eeb0822 diff --git a/go.sum b/go.sum index 4da3fd58..a1b49112 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240408061121-8c59a124c1ff h1:FiCD0T10oRjvO3ADmrkpaiYBZA1U91SfYEK8UTDqDbQ= -github.com/Two-Hearts/notation-core-go v0.0.0-20240408061121-8c59a124c1ff/go.mod h1:GsHR/83xmdubOk+77PlzIilthZNt+qCY4I9BxMKXbxg= -github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0 h1:EbUo6vzeco2sq3ipHCL7JtsgAwOXNiM7BRRRLVp2o3U= -github.com/Two-Hearts/tspclient-go v0.0.0-20240327080830-9d2a35b7f3f0/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240408072948-cbde6f956cbe h1:BaNFMCJckSyFinHzrDw8K5hADfEp1dmdFHiDg5jb2K0= +github.com/Two-Hearts/notation-core-go v0.0.0-20240408072948-cbde6f956cbe/go.mod h1:etS+BOHG3eXU6yMSxMOjeZjrEQojZMb57/5uALoL6gY= +github.com/Two-Hearts/tspclient-go v0.0.0-20240408072521-32657eeb0822 h1:Fri3XvjQNGCHw7uZINZhk/p6qP9eYdjgyPltUQdB1f4= +github.com/Two-Hearts/tspclient-go v0.0.0-20240408072521-32657eeb0822/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From 31de40f4956a6f9fe6d1f64f320444fafa9b4dee Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 10 Apr 2024 11:53:20 +0800 Subject: [PATCH 17/82] update Signed-off-by: Patrick Zheng --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 909af822..de270982 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240408072948-cbde6f956cbe +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240410034234-29bc7737eb3c -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240408072521-32657eeb0822 +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240410033505-94c3b3def019 diff --git a/go.sum b/go.sum index a1b49112..e2916252 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240408072948-cbde6f956cbe h1:BaNFMCJckSyFinHzrDw8K5hADfEp1dmdFHiDg5jb2K0= -github.com/Two-Hearts/notation-core-go v0.0.0-20240408072948-cbde6f956cbe/go.mod h1:etS+BOHG3eXU6yMSxMOjeZjrEQojZMb57/5uALoL6gY= -github.com/Two-Hearts/tspclient-go v0.0.0-20240408072521-32657eeb0822 h1:Fri3XvjQNGCHw7uZINZhk/p6qP9eYdjgyPltUQdB1f4= -github.com/Two-Hearts/tspclient-go v0.0.0-20240408072521-32657eeb0822/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240410034234-29bc7737eb3c h1:hr6zVMTS6oEjGuNt7HSAG/41Ck7KQVG+UJxeiF6LHgI= +github.com/Two-Hearts/notation-core-go v0.0.0-20240410034234-29bc7737eb3c/go.mod h1:o3qDLatecAi3cQKnlnTk32mJNoNWovGFMiToV5n8KW4= +github.com/Two-Hearts/tspclient-go v0.0.0-20240410033505-94c3b3def019 h1:7SJ4FlWTmpXssu5J+XI7Fzn50tPsagFMEJSWmqv8nLU= +github.com/Two-Hearts/tspclient-go v0.0.0-20240410033505-94c3b3def019/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From f4536db71936db371fea06f1cc8b04bbccd7a19f Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 11 Apr 2024 10:15:50 +0800 Subject: [PATCH 18/82] update Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index de270982..bc8cbfd6 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240410034234-29bc7737eb3c +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240411021119-44995cc7a08f replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240410033505-94c3b3def019 diff --git a/go.sum b/go.sum index e2916252..626f83d1 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240410034234-29bc7737eb3c h1:hr6zVMTS6oEjGuNt7HSAG/41Ck7KQVG+UJxeiF6LHgI= -github.com/Two-Hearts/notation-core-go v0.0.0-20240410034234-29bc7737eb3c/go.mod h1:o3qDLatecAi3cQKnlnTk32mJNoNWovGFMiToV5n8KW4= +github.com/Two-Hearts/notation-core-go v0.0.0-20240411021119-44995cc7a08f h1:OUQLq7PVUmvVMSuI7RV9IQwcLkqP2fr+DwCo7lMirM0= +github.com/Two-Hearts/notation-core-go v0.0.0-20240411021119-44995cc7a08f/go.mod h1:o3qDLatecAi3cQKnlnTk32mJNoNWovGFMiToV5n8KW4= github.com/Two-Hearts/tspclient-go v0.0.0-20240410033505-94c3b3def019 h1:7SJ4FlWTmpXssu5J+XI7Fzn50tPsagFMEJSWmqv8nLU= github.com/Two-Hearts/tspclient-go v0.0.0-20240410033505-94c3b3def019/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= From 998d79ff0b3c5c5450089adc89f59c15389680c9 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 11 Apr 2024 14:32:32 +0800 Subject: [PATCH 19/82] added skip tsa cert expire check Signed-off-by: Patrick Zheng --- notation.go | 19 ++++++++++++++++--- verifier/verifier.go | 33 +++++++++++++++++++-------------- 2 files changed, 35 insertions(+), 17 deletions(-) diff --git a/notation.go b/notation.go index 34ddda88..56860703 100644 --- a/notation.go +++ b/notation.go @@ -319,6 +319,12 @@ type VerifierVerifyOptions struct { // UserMetadata contains key-value pairs that must be present in the // signature. UserMetadata map[string]string + + // SkipTimestampCertificateExpirationCheck skips timestamp certificate + // expiration check during timestamp countersignature verification. The + // time point been stamped still MUST be within timestamp certificate chain's + // validity period, and this check is always enforced. + SkipTimestampCertificateExpirationCheck bool } // Verifier is a generic interface for verifying an artifact. @@ -353,6 +359,12 @@ type VerifyOptions struct { // UserMetadata contains key-value pairs that must be present in the // signature UserMetadata map[string]string + + // SkipTimestampCertificateExpirationCheck skips timestamp certificate + // expiration check during timestamp countersignature verification. The + // time point been stamped still MUST be within timestamp certificate chain's + // validity period, and this check is always enforced. + SkipTimestampCertificateExpirationCheck bool } // Verify performs signature verification on each of the notation supported @@ -376,9 +388,10 @@ func Verify(ctx context.Context, verifier Verifier, repo registry.Repository, ve // opts to be passed in verifier.Verify() opts := VerifierVerifyOptions{ - ArtifactReference: verifyOpts.ArtifactReference, - PluginConfig: verifyOpts.PluginConfig, - UserMetadata: verifyOpts.UserMetadata, + ArtifactReference: verifyOpts.ArtifactReference, + PluginConfig: verifyOpts.PluginConfig, + UserMetadata: verifyOpts.UserMetadata, + SkipTimestampCertificateExpirationCheck: verifyOpts.SkipTimestampCertificateExpirationCheck, } if skipChecker, ok := verifier.(verifySkipper); ok { diff --git a/verifier/verifier.go b/verifier/verifier.go index ed27cb03..8080d9b8 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -157,7 +157,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, pluginConfig, outcome) + err = v.processSignature(ctx, signature, envelopeMediaType, trustPolicy, opts.SkipTimestampCertificateExpirationCheck, pluginConfig, outcome) if err != nil { outcome.Error = err @@ -188,7 +188,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 string, trustPolicy *trustpolicy.TrustPolicy, pluginConfig map[string]string, outcome *notation.VerificationOutcome) error { +func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelopeMediaType string, trustPolicy *trustpolicy.TrustPolicy, skipTimestampCertExpirationCheck bool, pluginConfig map[string]string, outcome *notation.VerificationOutcome) error { logger := log.GetLogger(ctx) // verify integrity first. notation will always verify integrity no matter @@ -288,7 +288,7 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop // verify authentic timestamp logger.Debug("Validating authentic timestamp") - authenticTimestampResult := verifyAuthenticTimestamp(ctx, trustPolicy, v.trustStore, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(ctx, trustPolicy, v.trustStore, skipTimestampCertExpirationCheck, outcome) outcome.VerificationResults = append(outcome.VerificationResults, authenticTimestampResult) logVerificationResult(logger, authenticTimestampResult) if isCriticalFailure(authenticTimestampResult) { @@ -516,7 +516,7 @@ func verifyExpiry(outcome *notation.VerificationOutcome) *notation.ValidationRes } } -func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, outcome *notation.VerificationOutcome) *notation.ValidationResult { +func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, skipTimestampCertExpirationCheck bool, outcome *notation.VerificationOutcome) *notation.ValidationResult { logger := log.GetLogger(ctx) // under signing scheme notary.x509 @@ -571,10 +571,11 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus for _, cert := range trustTSACerts { roots.AddCert(cert) } - opts := x509.VerifyOptions{ + timestampVerifyOpts := x509.VerifyOptions{ Roots: roots, } - tsaCertChain, err := signedToken.Verify(ctx, opts) + // get the timestamp token info + info, err := signedToken.Info() if err != nil { return ¬ation.ValidationResult{ Error: err, @@ -582,16 +583,20 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - // validate TSA cert chain - if err := nx509.ValidateTimeStampingCertChain(tsaCertChain, nil); err != nil { + // validate the info + ts, accuracy, err := info.Timestamp(signerInfo.Signature) + if err != nil { return ¬ation.ValidationResult{ Error: err, Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - // get the timestamp token info - info, err := signedToken.Info() + if skipTimestampCertExpirationCheck { + timestampVerifyOpts.CurrentTime = ts + } + // verify the timestamp countersignature + tsaCertChain, err := signedToken.Verify(ctx, timestampVerifyOpts) if err != nil { return ¬ation.ValidationResult{ Error: err, @@ -599,18 +604,18 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - // validate the info and consume timestamp - ts, accuracy, err := info.Timestamp(signerInfo.Signature) - if err != nil { + // validate timestamp certificate chain + if err := nx509.ValidateTimeStampingCertChain(tsaCertChain, nil); err != nil { return ¬ation.ValidationResult{ Error: err, Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } + // get the timestamp token time range timeStampLowerLimit := ts.Add(-accuracy) timeStampUpperLimit := ts.Add(accuracy) - fmt.Printf("timestamp token time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) + logger.Info("timestamp token time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) // TSA certificate chain revocation check certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit) if err != nil { From 545e1e76454e82f6b4bbcf3ea032292afcb176f8 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 11 Apr 2024 14:50:42 +0800 Subject: [PATCH 20/82] update Signed-off-by: Patrick Zheng --- notation.go | 26 ++++++++++++-------------- verifier/verifier.go | 10 +++++----- 2 files changed, 17 insertions(+), 19 deletions(-) diff --git a/notation.go b/notation.go index 56860703..429c4c29 100644 --- a/notation.go +++ b/notation.go @@ -320,11 +320,10 @@ type VerifierVerifyOptions struct { // signature. UserMetadata map[string]string - // SkipTimestampCertificateExpirationCheck skips timestamp certificate - // expiration check during timestamp countersignature verification. The - // time point been stamped still MUST be within timestamp certificate chain's - // validity period, and this check is always enforced. - SkipTimestampCertificateExpirationCheck bool + // VerifyAtTimestampedTime verifies the timestamp countersignature at the + // time point been stamped. This time point MUST be within timestamp + // certificate chain's validity period. + VerifyAtTimestampedTime bool } // Verifier is a generic interface for verifying an artifact. @@ -360,11 +359,10 @@ type VerifyOptions struct { // signature UserMetadata map[string]string - // SkipTimestampCertificateExpirationCheck skips timestamp certificate - // expiration check during timestamp countersignature verification. The - // time point been stamped still MUST be within timestamp certificate chain's - // validity period, and this check is always enforced. - SkipTimestampCertificateExpirationCheck bool + // VerifyAtTimestampedTime verifies the timestamp countersignature at the + // time point been stamped. This time point MUST be within timestamp + // certificate chain's validity period. + VerifyAtTimestampedTime bool } // Verify performs signature verification on each of the notation supported @@ -388,10 +386,10 @@ func Verify(ctx context.Context, verifier Verifier, repo registry.Repository, ve // opts to be passed in verifier.Verify() opts := VerifierVerifyOptions{ - ArtifactReference: verifyOpts.ArtifactReference, - PluginConfig: verifyOpts.PluginConfig, - UserMetadata: verifyOpts.UserMetadata, - SkipTimestampCertificateExpirationCheck: verifyOpts.SkipTimestampCertificateExpirationCheck, + ArtifactReference: verifyOpts.ArtifactReference, + PluginConfig: verifyOpts.PluginConfig, + UserMetadata: verifyOpts.UserMetadata, + VerifyAtTimestampedTime: verifyOpts.VerifyAtTimestampedTime, } if skipChecker, ok := verifier.(verifySkipper); ok { diff --git a/verifier/verifier.go b/verifier/verifier.go index 8080d9b8..453d10e4 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -157,7 +157,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, opts.SkipTimestampCertificateExpirationCheck, pluginConfig, outcome) + err = v.processSignature(ctx, signature, envelopeMediaType, trustPolicy, opts.VerifyAtTimestampedTime, pluginConfig, outcome) if err != nil { outcome.Error = err @@ -188,7 +188,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 string, trustPolicy *trustpolicy.TrustPolicy, skipTimestampCertExpirationCheck bool, pluginConfig map[string]string, outcome *notation.VerificationOutcome) error { +func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelopeMediaType string, trustPolicy *trustpolicy.TrustPolicy, verifyAtTimestampedTime bool, pluginConfig map[string]string, outcome *notation.VerificationOutcome) error { logger := log.GetLogger(ctx) // verify integrity first. notation will always verify integrity no matter @@ -288,7 +288,7 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop // verify authentic timestamp logger.Debug("Validating authentic timestamp") - authenticTimestampResult := verifyAuthenticTimestamp(ctx, trustPolicy, v.trustStore, skipTimestampCertExpirationCheck, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(ctx, trustPolicy, v.trustStore, verifyAtTimestampedTime, outcome) outcome.VerificationResults = append(outcome.VerificationResults, authenticTimestampResult) logVerificationResult(logger, authenticTimestampResult) if isCriticalFailure(authenticTimestampResult) { @@ -516,7 +516,7 @@ func verifyExpiry(outcome *notation.VerificationOutcome) *notation.ValidationRes } } -func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, skipTimestampCertExpirationCheck bool, outcome *notation.VerificationOutcome) *notation.ValidationResult { +func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, verifyAtTimestampedTime bool, outcome *notation.VerificationOutcome) *notation.ValidationResult { logger := log.GetLogger(ctx) // under signing scheme notary.x509 @@ -592,7 +592,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - if skipTimestampCertExpirationCheck { + if verifyAtTimestampedTime { timestampVerifyOpts.CurrentTime = ts } // verify the timestamp countersignature From 527b84a2b66d2e61f4453ef7c786a9717adf6d6f Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 16 Apr 2024 16:41:07 +0800 Subject: [PATCH 21/82] added timestamp trust policy Signed-off-by: Patrick Zheng --- notation.go | 17 +++-------------- verifier/trustpolicy/trustpolicy.go | 17 +++++++++++++++-- verifier/verifier.go | 18 +++++++++++++----- 3 files changed, 31 insertions(+), 21 deletions(-) diff --git a/notation.go b/notation.go index 429c4c29..34ddda88 100644 --- a/notation.go +++ b/notation.go @@ -319,11 +319,6 @@ type VerifierVerifyOptions struct { // UserMetadata contains key-value pairs that must be present in the // signature. UserMetadata map[string]string - - // VerifyAtTimestampedTime verifies the timestamp countersignature at the - // time point been stamped. This time point MUST be within timestamp - // certificate chain's validity period. - VerifyAtTimestampedTime bool } // Verifier is a generic interface for verifying an artifact. @@ -358,11 +353,6 @@ type VerifyOptions struct { // UserMetadata contains key-value pairs that must be present in the // signature UserMetadata map[string]string - - // VerifyAtTimestampedTime verifies the timestamp countersignature at the - // time point been stamped. This time point MUST be within timestamp - // certificate chain's validity period. - VerifyAtTimestampedTime bool } // Verify performs signature verification on each of the notation supported @@ -386,10 +376,9 @@ func Verify(ctx context.Context, verifier Verifier, repo registry.Repository, ve // opts to be passed in verifier.Verify() opts := VerifierVerifyOptions{ - ArtifactReference: verifyOpts.ArtifactReference, - PluginConfig: verifyOpts.PluginConfig, - UserMetadata: verifyOpts.UserMetadata, - VerifyAtTimestampedTime: verifyOpts.VerifyAtTimestampedTime, + ArtifactReference: verifyOpts.ArtifactReference, + PluginConfig: verifyOpts.PluginConfig, + UserMetadata: verifyOpts.UserMetadata, } if skipChecker, ok := verifier.(verifySkipper); ok { diff --git a/verifier/trustpolicy/trustpolicy.go b/verifier/trustpolicy/trustpolicy.go index b0aaede5..b28ec9dd 100644 --- a/verifier/trustpolicy/trustpolicy.go +++ b/verifier/trustpolicy/trustpolicy.go @@ -134,7 +134,7 @@ var ( } ) -var supportedPolicyVersions = []string{"1.0"} +var supportedPolicyVersions = []string{"1.0", "1.1"} // Document represents a trustPolicy.json document type Document struct { @@ -156,6 +156,9 @@ type TrustPolicy struct { // SignatureVerification setting for this policy statement SignatureVerification SignatureVerification `json:"signatureVerification"` + // TimestampVerification setting for this policy statement + TimestampVerification *TimestampVerification `json:"timestampVerification,omitempty"` + // TrustStores this policy statement uses TrustStores []string `json:"trustStores,omitempty"` @@ -169,6 +172,12 @@ type SignatureVerification struct { Override map[ValidationType]ValidationAction `json:"override,omitempty"` } +// TimestampVerification represents timestamp countersignature verification +// configuration in a trust policy +type TimestampVerification struct { + AtTimestampedTime bool `json:"atTimestampedTime"` +} + // Validate validates a policy document according to its version's rule set. // if any rule is violated, returns an error func (policyDoc *Document) Validate() error { @@ -185,7 +194,6 @@ func (policyDoc *Document) Validate() error { return fmt.Errorf("trust policy document uses unsupported version %q", policyDoc.Version) } - // Validate the policy according to 1.0 rules if len(policyDoc.TrustPolicies) == 0 { return errors.New("trust policy document can not have zero trust policy statements") } @@ -206,6 +214,11 @@ func (policyDoc *Document) Validate() error { return fmt.Errorf("trust policy statement %q has invalid signatureVerification: %w", statement.Name, err) } + // Verify timestamp verification is valid + if statement.TimestampVerification != nil && policyDoc.Version != "1.1" { + return fmt.Errorf("trust policy document version must be 1.1 to support timestamp verification, but got %q", policyDoc.Version) + } + // Any signature verification other than "skip" needs a trust store and // trusted identities if verificationLevel.Name == "skip" { diff --git a/verifier/verifier.go b/verifier/verifier.go index 453d10e4..a07bfd0c 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -157,7 +157,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, opts.VerifyAtTimestampedTime, pluginConfig, outcome) + err = v.processSignature(ctx, signature, envelopeMediaType, trustPolicy, pluginConfig, outcome) if err != nil { outcome.Error = err @@ -188,7 +188,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 string, trustPolicy *trustpolicy.TrustPolicy, verifyAtTimestampedTime bool, pluginConfig map[string]string, outcome *notation.VerificationOutcome) error { +func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelopeMediaType string, trustPolicy *trustpolicy.TrustPolicy, pluginConfig map[string]string, outcome *notation.VerificationOutcome) error { logger := log.GetLogger(ctx) // verify integrity first. notation will always verify integrity no matter @@ -288,7 +288,7 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop // verify authentic timestamp logger.Debug("Validating authentic timestamp") - authenticTimestampResult := verifyAuthenticTimestamp(ctx, trustPolicy, v.trustStore, verifyAtTimestampedTime, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(ctx, trustPolicy, v.trustStore, outcome) outcome.VerificationResults = append(outcome.VerificationResults, authenticTimestampResult) logVerificationResult(logger, authenticTimestampResult) if isCriticalFailure(authenticTimestampResult) { @@ -516,7 +516,7 @@ func verifyExpiry(outcome *notation.VerificationOutcome) *notation.ValidationRes } } -func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, verifyAtTimestampedTime bool, outcome *notation.VerificationOutcome) *notation.ValidationResult { +func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, outcome *notation.VerificationOutcome) *notation.ValidationResult { logger := log.GetLogger(ctx) // under signing scheme notary.x509 @@ -544,6 +544,14 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } + if trustPolicy.TimestampVerification == nil { + // if there is no timestamp verification configuration in trust policy + return ¬ation.ValidationResult{ + Error: errors.New("current time is not in certificate chain validity period and no timestamp verification configuration was found in trust policy"), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) if err != nil { return ¬ation.ValidationResult{ @@ -592,7 +600,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - if verifyAtTimestampedTime { + if trustPolicy.TimestampVerification.AtTimestampedTime { timestampVerifyOpts.CurrentTime = ts } // verify the timestamp countersignature From 1e21a3d0356e7061bd52eb389ba729c81d402cbd Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 17 Apr 2024 11:19:36 +0800 Subject: [PATCH 22/82] update Signed-off-by: Patrick Zheng --- verifier/trustpolicy/trustpolicy.go | 1 + 1 file changed, 1 insertion(+) diff --git a/verifier/trustpolicy/trustpolicy.go b/verifier/trustpolicy/trustpolicy.go index b28ec9dd..015553e3 100644 --- a/verifier/trustpolicy/trustpolicy.go +++ b/verifier/trustpolicy/trustpolicy.go @@ -407,6 +407,7 @@ func (t *TrustPolicy) clone() *TrustPolicy { return &TrustPolicy{ Name: t.Name, SignatureVerification: t.SignatureVerification, + TimestampVerification: t.TimestampVerification, RegistryScopes: append([]string(nil), t.RegistryScopes...), TrustedIdentities: append([]string(nil), t.TrustedIdentities...), TrustStores: append([]string(nil), t.TrustStores...), From 27a5b3565c7e5fd328363ec27343151c1da41640 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 17 Apr 2024 12:46:03 +0800 Subject: [PATCH 23/82] update Signed-off-by: Patrick Zheng --- verifier/trustpolicy/trustpolicy.go | 8 ++++++++ verifier/verifier.go | 6 +++--- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/verifier/trustpolicy/trustpolicy.go b/verifier/trustpolicy/trustpolicy.go index 015553e3..112719f8 100644 --- a/verifier/trustpolicy/trustpolicy.go +++ b/verifier/trustpolicy/trustpolicy.go @@ -166,6 +166,14 @@ type TrustPolicy struct { TrustedIdentities []string `json:"trustedIdentities,omitempty"` } +func (t *TrustPolicy) String() string { + policyJson, err := json.Marshal(t) + if err != nil { + return "" + } + return string(policyJson) +} + // SignatureVerification represents verification configuration in a trust policy type SignatureVerification struct { VerificationLevel string `json:"level"` diff --git a/verifier/verifier.go b/verifier/verifier.go index a07bfd0c..36478a54 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -144,7 +144,7 @@ func (v *verifier) Verify(ctx context.Context, desc ocispec.Descriptor, signatur if err != nil { return nil, notation.ErrorNoApplicableTrustPolicy{Msg: err.Error()} } - logger.Infof("Trust policy configuration: %+v", trustPolicy) + logger.Infof("Trust policy configuration: %q", trustPolicy.String()) // ignore the error since we already validated the policy document verificationLevel, _ := trustPolicy.SignatureVerification.GetVerificationLevel() @@ -623,7 +623,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus // get the timestamp token time range timeStampLowerLimit := ts.Add(-accuracy) timeStampUpperLimit := ts.Add(accuracy) - logger.Info("timestamp token time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) + logger.Infof("timestamp token time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) // TSA certificate chain revocation check certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit) if err != nil { @@ -656,7 +656,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus for _, cert := range signerInfo.CertificateChain { if timeStampLowerLimit.Before(cert.NotBefore) { return ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamp lower limit %q is before certificate %q validity period , it will be valid from %q", timeStampLowerLimit.Format(time.RFC1123Z), cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), + Error: fmt.Errorf("timestamp lower limit %q is before certificate %q validity period, it will be valid from %q", timeStampLowerLimit.Format(time.RFC1123Z), cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } From 90424bd1cdb54418e895a4f5efdc0d98a2181d3a Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 17 Apr 2024 13:01:45 +0800 Subject: [PATCH 24/82] update Signed-off-by: Patrick Zheng --- verifier/trustpolicy/trustpolicy.go | 7 ++----- verifier/verifier.go | 4 ++-- 2 files changed, 4 insertions(+), 7 deletions(-) diff --git a/verifier/trustpolicy/trustpolicy.go b/verifier/trustpolicy/trustpolicy.go index 112719f8..dc1b1efb 100644 --- a/verifier/trustpolicy/trustpolicy.go +++ b/verifier/trustpolicy/trustpolicy.go @@ -166,12 +166,9 @@ type TrustPolicy struct { TrustedIdentities []string `json:"trustedIdentities,omitempty"` } +// String returns print out of TrustPolicy as a string func (t *TrustPolicy) String() string { - policyJson, err := json.Marshal(t) - if err != nil { - return "" - } - return string(policyJson) + return fmt.Sprintf("Name: %s, RegistryScopes: %v, SignatureVerification: %+v, TimestampVerification: %+v, TrustStores: %v, TrustedIdentities: %v", t.Name, t.RegistryScopes, t.SignatureVerification, t.TimestampVerification, t.TrustStores, t.TrustedIdentities) } // SignatureVerification represents verification configuration in a trust policy diff --git a/verifier/verifier.go b/verifier/verifier.go index 36478a54..eb0e6a44 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -144,7 +144,7 @@ func (v *verifier) Verify(ctx context.Context, desc ocispec.Descriptor, signatur if err != nil { return nil, notation.ErrorNoApplicableTrustPolicy{Msg: err.Error()} } - logger.Infof("Trust policy configuration: %q", trustPolicy.String()) + logger.Infof("Trust policy configuration: %+v", trustPolicy) // ignore the error since we already validated the policy document verificationLevel, _ := trustPolicy.SignatureVerification.GetVerificationLevel() @@ -623,7 +623,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus // get the timestamp token time range timeStampLowerLimit := ts.Add(-accuracy) timeStampUpperLimit := ts.Add(accuracy) - logger.Infof("timestamp token time range: [%v, %v]\n", timeStampLowerLimit, timeStampUpperLimit) + logger.Infof("timestamp token time range: [%v, %v]", timeStampLowerLimit, timeStampUpperLimit) // TSA certificate chain revocation check certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit) if err != nil { From d7a03968d75f38809c66959a85d50de9d3d86ba2 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 17 Apr 2024 16:57:55 +0800 Subject: [PATCH 25/82] timestamp trust policy Signed-off-by: Patrick Zheng --- verifier/trustpolicy/trustpolicy.go | 3 ++- verifier/verifier.go | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/verifier/trustpolicy/trustpolicy.go b/verifier/trustpolicy/trustpolicy.go index dc1b1efb..e5297e78 100644 --- a/verifier/trustpolicy/trustpolicy.go +++ b/verifier/trustpolicy/trustpolicy.go @@ -180,7 +180,8 @@ type SignatureVerification struct { // TimestampVerification represents timestamp countersignature verification // configuration in a trust policy type TimestampVerification struct { - AtTimestampedTime bool `json:"atTimestampedTime"` + Enable bool `json:"enable,omitempty"` + ExpiryRelaxed bool `json:"expiryRelaxed,omitempty"` } // Validate validates a policy document according to its version's rule set. diff --git a/verifier/verifier.go b/verifier/verifier.go index eb0e6a44..92866c06 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -521,16 +521,16 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus // under signing scheme notary.x509 if signerInfo := outcome.EnvelopeContent.SignerInfo; signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { - var needTimestamp bool + var requireTimestampVerification bool for _, cert := range signerInfo.CertificateChain { if time.Now().Before(cert.NotBefore) || time.Now().After(cert.NotAfter) { // found at least one cert that current time is not in its - // validity period; need timestamp to continue this step - needTimestamp = true + // validity period; require timestamp to continue this step + requireTimestampVerification = true break } } - if !needTimestamp { // this step is a success + if !requireTimestampVerification { // this step is a success return ¬ation.ValidationResult{ Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], @@ -544,10 +544,10 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - if trustPolicy.TimestampVerification == nil { - // if there is no timestamp verification configuration in trust policy + if trustPolicy.TimestampVerification == nil || !trustPolicy.TimestampVerification.Enable { + // if timestamp verification is disabled in trust policy return ¬ation.ValidationResult{ - Error: errors.New("current time is not in certificate chain validity period and no timestamp verification configuration was found in trust policy"), + Error: errors.New("current time is not in certificate chain validity period and timestamp verification is disabled in trust policy"), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } @@ -600,7 +600,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - if trustPolicy.TimestampVerification.AtTimestampedTime { + if trustPolicy.TimestampVerification.ExpiryRelaxed { timestampVerifyOpts.CurrentTime = ts } // verify the timestamp countersignature From 12ac6b696d7facd01b84e02514d0d9c04bf069bd Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 18 Apr 2024 13:02:30 +0800 Subject: [PATCH 26/82] update Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index bc8cbfd6..54bcabc6 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240411021119-44995cc7a08f +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240418044922-14d05519328b replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240410033505-94c3b3def019 diff --git a/go.sum b/go.sum index 626f83d1..70efd74f 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240411021119-44995cc7a08f h1:OUQLq7PVUmvVMSuI7RV9IQwcLkqP2fr+DwCo7lMirM0= -github.com/Two-Hearts/notation-core-go v0.0.0-20240411021119-44995cc7a08f/go.mod h1:o3qDLatecAi3cQKnlnTk32mJNoNWovGFMiToV5n8KW4= +github.com/Two-Hearts/notation-core-go v0.0.0-20240418044922-14d05519328b h1:a27dSIOWWw7rJSD2ebmWUYjwhhhPnIaMGlqPl9OuCmI= +github.com/Two-Hearts/notation-core-go v0.0.0-20240418044922-14d05519328b/go.mod h1:o3qDLatecAi3cQKnlnTk32mJNoNWovGFMiToV5n8KW4= github.com/Two-Hearts/tspclient-go v0.0.0-20240410033505-94c3b3def019 h1:7SJ4FlWTmpXssu5J+XI7Fzn50tPsagFMEJSWmqv8nLU= github.com/Two-Hearts/tspclient-go v0.0.0-20240410033505-94c3b3def019/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20210105120005-909beea2cc74 h1:Kk6a4nehpJ3UuJRqlA3JxYxBZEqCeOmATOvrbT4p9RA= From 6e363033966121d09cab90298c73703a02f11fe0 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 18 Apr 2024 13:06:03 +0800 Subject: [PATCH 27/82] update Signed-off-by: Patrick Zheng --- verifier/verifier.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 92866c06..9c3d3666 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -545,7 +545,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } if trustPolicy.TimestampVerification == nil || !trustPolicy.TimestampVerification.Enable { - // if timestamp verification is disabled in trust policy + // if timestamp verification is disabled by trust policy return ¬ation.ValidationResult{ Error: errors.New("current time is not in certificate chain validity period and timestamp verification is disabled in trust policy"), Type: trustpolicy.TypeAuthenticTimestamp, @@ -652,7 +652,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - // timestamp core process + // timestamp validation core process for _, cert := range signerInfo.CertificateChain { if timeStampLowerLimit.Before(cert.NotBefore) { return ¬ation.ValidationResult{ From bea674c16d59c2676d5a04de35d3a8b56528cca2 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 18 Apr 2024 13:22:57 +0800 Subject: [PATCH 28/82] error msg Signed-off-by: Patrick Zheng --- verifier/verifier.go | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 9c3d3666..1207c099 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -522,11 +522,13 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus // under signing scheme notary.x509 if signerInfo := outcome.EnvelopeContent.SignerInfo; signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { var requireTimestampVerification bool + var invalidCertificate *x509.Certificate for _, cert := range signerInfo.CertificateChain { if time.Now().Before(cert.NotBefore) || time.Now().After(cert.NotAfter) { // found at least one cert that current time is not in its // validity period; require timestamp to continue this step requireTimestampVerification = true + invalidCertificate = cert break } } @@ -539,7 +541,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus if len(signerInfo.UnsignedAttributes.TimestampSignature) == 0 { // if there is no timestamp token, fail this step return ¬ation.ValidationResult{ - Error: errors.New("current time is not in certificate chain validity period and no timestamp token was found in the signature envelope"), + Error: fmt.Errorf("current time is not in certificate %q validity period [%q, %q] and no timestamp token was found in the signature envelope", invalidCertificate.Subject, invalidCertificate.NotBefore.Format(time.RFC1123Z), invalidCertificate.NotAfter.Format(time.RFC1123Z)), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } @@ -547,7 +549,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus if trustPolicy.TimestampVerification == nil || !trustPolicy.TimestampVerification.Enable { // if timestamp verification is disabled by trust policy return ¬ation.ValidationResult{ - Error: errors.New("current time is not in certificate chain validity period and timestamp verification is disabled in trust policy"), + Error: fmt.Errorf("current time is not in certificate %q validity period [%q, %q] and timestamp verification is disabled by trust policy", invalidCertificate.Subject, invalidCertificate.NotBefore.Format(time.RFC1123Z), invalidCertificate.NotAfter.Format(time.RFC1123Z)), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } From a510cbf82e696ca36b9d069c37db287db4cf59f5 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 8 May 2024 16:42:11 +0800 Subject: [PATCH 29/82] updated per spec Signed-off-by: Patrick Zheng --- go.mod | 6 ++-- go.sum | 11 +++--- verifier/trustpolicy/trustpolicy.go | 23 +------------ verifier/verifier.go | 53 ++++++++++++----------------- 4 files changed, 32 insertions(+), 61 deletions(-) diff --git a/go.mod b/go.mod index 111e7715..a90b67ab 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/veraison/go-cose v1.1.0 - golang.org/x/crypto v0.21.0 + golang.org/x/crypto v0.22.0 golang.org/x/mod v0.17.0 oras.land/oras-go/v2 v2.5.0 ) @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240418044922-14d05519328b +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240508074737-fc1cb3d28098 -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240410033505-94c3b3def019 +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240508074024-ec1725d6dc9b diff --git a/go.sum b/go.sum index 4527d6f5..85446a04 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240418044922-14d05519328b h1:a27dSIOWWw7rJSD2ebmWUYjwhhhPnIaMGlqPl9OuCmI= -github.com/Two-Hearts/notation-core-go v0.0.0-20240418044922-14d05519328b/go.mod h1:o3qDLatecAi3cQKnlnTk32mJNoNWovGFMiToV5n8KW4= -github.com/Two-Hearts/tspclient-go v0.0.0-20240410033505-94c3b3def019 h1:7SJ4FlWTmpXssu5J+XI7Fzn50tPsagFMEJSWmqv8nLU= -github.com/Two-Hearts/tspclient-go v0.0.0-20240410033505-94c3b3def019/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240508074737-fc1cb3d28098 h1:xfyYkDuH7MXz5+Pd5wvRSlARyDUp9UM7I23OzlbIMsA= +github.com/Two-Hearts/notation-core-go v0.0.0-20240508074737-fc1cb3d28098/go.mod h1:wkaaIh2fMRBO3j48U/F64tZOCqcYkuKOiA9o7ERkXXU= +github.com/Two-Hearts/tspclient-go v0.0.0-20240508074024-ec1725d6dc9b h1:pNICDsr2or3iCRyjB8UnrG/N7mhP6H6yIfx3F8Zkcqk= +github.com/Two-Hearts/tspclient-go v0.0.0-20240508074024-ec1725d6dc9b/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -61,8 +61,9 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58= golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= -golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0 h1:g1v0xeRhjcugydODzvb3mEM9SQ0HGp9s/nh3COQ/C30= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.17.0 h1:zY54UmvipHiNd+pm+m0x9KhZ9hl1/7QNMyxXbc6ICqA= diff --git a/verifier/trustpolicy/trustpolicy.go b/verifier/trustpolicy/trustpolicy.go index e5297e78..bc74432d 100644 --- a/verifier/trustpolicy/trustpolicy.go +++ b/verifier/trustpolicy/trustpolicy.go @@ -134,7 +134,7 @@ var ( } ) -var supportedPolicyVersions = []string{"1.0", "1.1"} +var supportedPolicyVersions = []string{"1.0"} // Document represents a trustPolicy.json document type Document struct { @@ -156,9 +156,6 @@ type TrustPolicy struct { // SignatureVerification setting for this policy statement SignatureVerification SignatureVerification `json:"signatureVerification"` - // TimestampVerification setting for this policy statement - TimestampVerification *TimestampVerification `json:"timestampVerification,omitempty"` - // TrustStores this policy statement uses TrustStores []string `json:"trustStores,omitempty"` @@ -166,24 +163,12 @@ type TrustPolicy struct { TrustedIdentities []string `json:"trustedIdentities,omitempty"` } -// String returns print out of TrustPolicy as a string -func (t *TrustPolicy) String() string { - return fmt.Sprintf("Name: %s, RegistryScopes: %v, SignatureVerification: %+v, TimestampVerification: %+v, TrustStores: %v, TrustedIdentities: %v", t.Name, t.RegistryScopes, t.SignatureVerification, t.TimestampVerification, t.TrustStores, t.TrustedIdentities) -} - // SignatureVerification represents verification configuration in a trust policy type SignatureVerification struct { VerificationLevel string `json:"level"` Override map[ValidationType]ValidationAction `json:"override,omitempty"` } -// TimestampVerification represents timestamp countersignature verification -// configuration in a trust policy -type TimestampVerification struct { - Enable bool `json:"enable,omitempty"` - ExpiryRelaxed bool `json:"expiryRelaxed,omitempty"` -} - // Validate validates a policy document according to its version's rule set. // if any rule is violated, returns an error func (policyDoc *Document) Validate() error { @@ -220,11 +205,6 @@ func (policyDoc *Document) Validate() error { return fmt.Errorf("trust policy statement %q has invalid signatureVerification: %w", statement.Name, err) } - // Verify timestamp verification is valid - if statement.TimestampVerification != nil && policyDoc.Version != "1.1" { - return fmt.Errorf("trust policy document version must be 1.1 to support timestamp verification, but got %q", policyDoc.Version) - } - // Any signature verification other than "skip" needs a trust store and // trusted identities if verificationLevel.Name == "skip" { @@ -413,7 +393,6 @@ func (t *TrustPolicy) clone() *TrustPolicy { return &TrustPolicy{ Name: t.Name, SignatureVerification: t.SignatureVerification, - TimestampVerification: t.TimestampVerification, RegistryScopes: append([]string(nil), t.RegistryScopes...), TrustedIdentities: append([]string(nil), t.TrustedIdentities...), TrustStores: append([]string(nil), t.TrustStores...), diff --git a/verifier/verifier.go b/verifier/verifier.go index 1207c099..2ad119c1 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -330,13 +330,13 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop return err } - return processPluginResponse(logger, capabilitiesToVerify, response, outcome) + return processPluginResponse(capabilitiesToVerify, response, outcome) } } return nil } -func processPluginResponse(logger log.Logger, capabilitiesToVerify []pluginframework.Capability, response *pluginframework.VerifySignatureResponse, outcome *notation.VerificationOutcome) error { +func processPluginResponse(capabilitiesToVerify []pluginframework.Capability, response *pluginframework.VerifySignatureResponse, outcome *notation.VerificationOutcome) error { verificationPluginName, err := getVerificationPlugin(&outcome.EnvelopeContent.SignerInfo) if err != nil { return err @@ -538,18 +538,11 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } + invalidCertErrMsg := fmt.Sprintf("current time is not in certificate %q validity period [%q, %q]", invalidCertificate.Subject, invalidCertificate.NotBefore.Format(time.RFC1123Z), invalidCertificate.NotAfter.Format(time.RFC1123Z)) if len(signerInfo.UnsignedAttributes.TimestampSignature) == 0 { // if there is no timestamp token, fail this step return ¬ation.ValidationResult{ - Error: fmt.Errorf("current time is not in certificate %q validity period [%q, %q] and no timestamp token was found in the signature envelope", invalidCertificate.Subject, invalidCertificate.NotBefore.Format(time.RFC1123Z), invalidCertificate.NotAfter.Format(time.RFC1123Z)), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - if trustPolicy.TimestampVerification == nil || !trustPolicy.TimestampVerification.Enable { - // if timestamp verification is disabled by trust policy - return ¬ation.ValidationResult{ - Error: fmt.Errorf("current time is not in certificate %q validity period [%q, %q] and timestamp verification is disabled by trust policy", invalidCertificate.Subject, invalidCertificate.NotBefore.Format(time.RFC1123Z), invalidCertificate.NotAfter.Format(time.RFC1123Z)), + Error: errors.New(invalidCertErrMsg + ", and no timestamp countersignature was found in the signature envelope"), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } @@ -557,14 +550,14 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) if err != nil { return ¬ation.ValidationResult{ - Error: err, + Error: fmt.Errorf(invalidCertErrMsg+", and timestamp verification is disabled with error: %w", err), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } if len(trustTSACerts) < 1 { return ¬ation.ValidationResult{ - Error: errors.New("no trusted TSA root certificate was found in the trust store"), + Error: errors.New(invalidCertErrMsg + ", and no trusted TSA root certificate was found in the trust store"), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } @@ -572,7 +565,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus signedToken, err := tspclient.ParseSignedToken(ctx, signerInfo.UnsignedAttributes.TimestampSignature) if err != nil { return ¬ation.ValidationResult{ - Error: err, + Error: fmt.Errorf(invalidCertErrMsg+", and failed to parse timestamp countersignature with error: %w", err), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } @@ -588,36 +581,35 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus info, err := signedToken.Info() if err != nil { return ¬ation.ValidationResult{ - Error: err, + Error: fmt.Errorf(invalidCertErrMsg+", and failed to get timestamp information with error: %w", err), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - // validate the info + // validate the info and get the timestamp ts, accuracy, err := info.Timestamp(signerInfo.Signature) if err != nil { return ¬ation.ValidationResult{ - Error: err, + Error: fmt.Errorf(invalidCertErrMsg+", and failed to get timestamp from timestamp countersignature with error: %w", err), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - if trustPolicy.TimestampVerification.ExpiryRelaxed { - timestampVerifyOpts.CurrentTime = ts - } + // verify the timestamp countersignature at the time point been stamped + timestampVerifyOpts.CurrentTime = ts // verify the timestamp countersignature tsaCertChain, err := signedToken.Verify(ctx, timestampVerifyOpts) if err != nil { return ¬ation.ValidationResult{ - Error: err, + Error: fmt.Errorf(invalidCertErrMsg+", and failed to verify the timestamp countersignature with error: %w", err), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - // validate timestamp certificate chain + // validate timestamping certificate chain if err := nx509.ValidateTimeStampingCertChain(tsaCertChain, nil); err != nil { return ¬ation.ValidationResult{ - Error: err, + Error: fmt.Errorf(invalidCertErrMsg+", and failed to validate the timestamping certificate chain with error: %w", err), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } @@ -626,12 +618,11 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus timeStampLowerLimit := ts.Add(-accuracy) timeStampUpperLimit := ts.Add(accuracy) logger.Infof("timestamp token time range: [%v, %v]", timeStampLowerLimit, timeStampUpperLimit) - // TSA certificate chain revocation check - certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit) + // perform the timestamping certificate chain revocation check + certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit, &http.Client{Timeout: 2 * time.Second}) if err != nil { - logger.Debug("error while checking revocation status, err: %s", err.Error()) return ¬ation.ValidationResult{ - Error: err, + Error: fmt.Errorf(invalidCertErrMsg+", and timestamping certificate chain revocation check failed with error: %w", err), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } @@ -639,22 +630,22 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus finalResult, problematicCertSubject := revocationFinalResult(certResults, tsaCertChain, logger) switch finalResult { case revocationresult.ResultOK: - logger.Debug("no verification impacting errors encountered while checking TSA certificate chain revocation, status is OK") + logger.Debug("no verification impacting errors encountered while checking timestamping certificate chain revocation, status is OK") case revocationresult.ResultRevoked: return ¬ation.ValidationResult{ - Error: fmt.Errorf("TSA certificate with subject %q is revoked", problematicCertSubject), + Error: fmt.Errorf(invalidCertErrMsg+", and timestamping certificate with subject %q is revoked", problematicCertSubject), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } default: // revocationresult.ResultUnknown return ¬ation.ValidationResult{ - Error: fmt.Errorf("TSA certificate with subject %q revocation status is unknown", problematicCertSubject), + Error: fmt.Errorf(invalidCertErrMsg+", and timestamping certificate with subject %q revocation status is unknown", problematicCertSubject), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - // timestamp validation core process + // core process for _, cert := range signerInfo.CertificateChain { if timeStampLowerLimit.Before(cert.NotBefore) { return ¬ation.ValidationResult{ From de71d3441d098f0794536bb18720dc914f5cb211 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 8 May 2024 16:48:13 +0800 Subject: [PATCH 30/82] updated per spec Signed-off-by: Patrick Zheng --- verifier/trustpolicy/trustpolicy.go | 1 + 1 file changed, 1 insertion(+) diff --git a/verifier/trustpolicy/trustpolicy.go b/verifier/trustpolicy/trustpolicy.go index bc74432d..b0aaede5 100644 --- a/verifier/trustpolicy/trustpolicy.go +++ b/verifier/trustpolicy/trustpolicy.go @@ -185,6 +185,7 @@ func (policyDoc *Document) Validate() error { return fmt.Errorf("trust policy document uses unsupported version %q", policyDoc.Version) } + // Validate the policy according to 1.0 rules if len(policyDoc.TrustPolicies) == 0 { return errors.New("trust policy document can not have zero trust policy statements") } From cde5adb39abfac160931dc4a94b9c63c49e51914 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 10 May 2024 16:16:50 +0800 Subject: [PATCH 31/82] updated tspclient-go Signed-off-by: Patrick Zheng --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 1f724f33..dfc2fc07 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240508074737-fc1cb3d28098 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240510081223-bf89fbfde06f -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240508074024-ec1725d6dc9b +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240510080813-e58c4f362fa4 diff --git a/go.sum b/go.sum index af3a4a03..bdd6573d 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240508074737-fc1cb3d28098 h1:xfyYkDuH7MXz5+Pd5wvRSlARyDUp9UM7I23OzlbIMsA= -github.com/Two-Hearts/notation-core-go v0.0.0-20240508074737-fc1cb3d28098/go.mod h1:wkaaIh2fMRBO3j48U/F64tZOCqcYkuKOiA9o7ERkXXU= -github.com/Two-Hearts/tspclient-go v0.0.0-20240508074024-ec1725d6dc9b h1:pNICDsr2or3iCRyjB8UnrG/N7mhP6H6yIfx3F8Zkcqk= -github.com/Two-Hearts/tspclient-go v0.0.0-20240508074024-ec1725d6dc9b/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240510081223-bf89fbfde06f h1:0qJ4YyR0q7SYv9N1VMafb5823SpxI7AGuYnSlvEcTjo= +github.com/Two-Hearts/notation-core-go v0.0.0-20240510081223-bf89fbfde06f/go.mod h1:KDiMLnM1MHQRMeiPM622MN0MBb9Hz6xRU4/O9qDOics= +github.com/Two-Hearts/tspclient-go v0.0.0-20240510080813-e58c4f362fa4 h1:jtwluHassbSXeXjloQ5FCJJ1hOhN/DCnAztY8Cr6if0= +github.com/Two-Hearts/tspclient-go v0.0.0-20240510080813-e58c4f362fa4/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From d13d60c64b5f9e4b464874c4e9b4788ee55ef0ae Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 4 Jun 2024 16:26:08 +0800 Subject: [PATCH 32/82] updated timestamping Signed-off-by: Patrick Zheng --- go.mod | 4 ++-- go.sum | 8 ++++---- verifier/helpers.go | 15 +++++++++++++++ verifier/verifier.go | 25 ++++++++++++++++++++----- 4 files changed, 41 insertions(+), 11 deletions(-) diff --git a/go.mod b/go.mod index 9824f250..6b63819d 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240510081223-bf89fbfde06f +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240604074342-99b519049ef9 -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240510080813-e58c4f362fa4 +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240604030442-e5d82db3a4d4 diff --git a/go.sum b/go.sum index 9b41f8fb..c0ddc38a 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240510081223-bf89fbfde06f h1:0qJ4YyR0q7SYv9N1VMafb5823SpxI7AGuYnSlvEcTjo= -github.com/Two-Hearts/notation-core-go v0.0.0-20240510081223-bf89fbfde06f/go.mod h1:KDiMLnM1MHQRMeiPM622MN0MBb9Hz6xRU4/O9qDOics= -github.com/Two-Hearts/tspclient-go v0.0.0-20240510080813-e58c4f362fa4 h1:jtwluHassbSXeXjloQ5FCJJ1hOhN/DCnAztY8Cr6if0= -github.com/Two-Hearts/tspclient-go v0.0.0-20240510080813-e58c4f362fa4/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240604074342-99b519049ef9 h1:gMwiXl+IGOeVhF4KUHbfqbvqZsgONcqPtzfYBexFKRE= +github.com/Two-Hearts/notation-core-go v0.0.0-20240604074342-99b519049ef9/go.mod h1:uk5VrENYWqPdnnBOZCEk1XEfilOscHJckfhaWzuMJlU= +github.com/Two-Hearts/tspclient-go v0.0.0-20240604030442-e5d82db3a4d4 h1:WCm4ObRL++IM3gVexV7evDbhzk2c4iAZYJmlTWIBOnQ= +github.com/Two-Hearts/tspclient-go v0.0.0-20240604030442-e5d82db3a4d4/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/verifier/helpers.go b/verifier/helpers.go index 43ddb7ce..057239e1 100644 --- a/verifier/helpers.go +++ b/verifier/helpers.go @@ -168,3 +168,18 @@ func loadX509TrustStoresWithType(ctx context.Context, trustStoreType truststore. } return certificates, nil } + +// isTSATrustStoreInPolicy checks if tsa trust store is configured in +// trust policy +func isTSATrustStoreInPolicy(policy *trustpolicy.TrustPolicy) (bool, error) { + for _, trustStore := range policy.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 :", policy.Name, trustStore)} + } + if truststore.Type(storeType) == truststore.TypeTSA { + return true, nil + } + } + return false, nil +} diff --git a/verifier/verifier.go b/verifier/verifier.go index 7192abad..996fdd2a 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -525,19 +525,19 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus timeStampLowerLimit := time.Now() timeStampUpperLimit := timeStampLowerLimit // check if tsa trust store is configured in trust policy - trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) + tsaEnabled, err := isTSATrustStoreInPolicy(trustPolicy) if err != nil { return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to load tsa trust store with error: %w", err), + Error: fmt.Errorf("failed to check tsa trust store configuration in turst policy with error: %w", err), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - if len(trustTSACerts) < 1 { + if !tsaEnabled { performTimestampVerification = false } // check based on 'verifyTimestamp' field - if trustPolicy.SignatureVerification.VerifyTimestamp == trustpolicy.OptionAfterCertExpiry { + if performTimestampVerification && trustPolicy.SignatureVerification.VerifyTimestamp == trustpolicy.OptionAfterCertExpiry { // check if signing cert chain has expired var expired bool for _, cert := range signerInfo.CertificateChain { @@ -586,7 +586,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } // 2. Verify the timestamp countersignature logger.Info("Verifying the timestamp countersignature...") - signedToken, err := tspclient.ParseSignedToken(ctx, signerInfo.UnsignedAttributes.TimestampSignature) + signedToken, err := tspclient.ParseSignedToken(signerInfo.UnsignedAttributes.TimestampSignature) if err != nil { return ¬ation.ValidationResult{ Error: fmt.Errorf("failed to parse timestamp countersignature with error: %w", err), @@ -611,6 +611,21 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } roots := x509.NewCertPool() + trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) + if err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to load tsa trust store with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + if len(trustTSACerts) < 1 { + return ¬ation.ValidationResult{ + Error: errors.New("no TSA root cert found in trust store"), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } for _, cert := range trustTSACerts { roots.AddCert(cert) } From c5ececc222963ea61137557f3c804ea72f5e8ca1 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 4 Jun 2024 16:32:02 +0800 Subject: [PATCH 33/82] updated timestamping Signed-off-by: Patrick Zheng --- verifier/verifier.go | 3 +++ 1 file changed, 3 insertions(+) diff --git a/verifier/verifier.go b/verifier/verifier.go index 996fdd2a..8ac2919a 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -521,6 +521,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus // under signing scheme notary.x509 if signerInfo := outcome.EnvelopeContent.SignerInfo; signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { + logger.Info("under signing scheme notary.x509...") performTimestampVerification := true timeStampLowerLimit := time.Now() timeStampUpperLimit := timeStampLowerLimit @@ -569,6 +570,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } } + // this step is a success return ¬ation.ValidationResult{ Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], @@ -700,6 +702,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } else if signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509SigningAuthority { // under signing scheme notary.x509.signingAuthority + logger.Info("under signing scheme notary.x509.signingAuthority...") authenticSigningTime := signerInfo.SignedAttributes.SigningTime for _, cert := range signerInfo.CertificateChain { if authenticSigningTime.Before(cert.NotBefore) || authenticSigningTime.After(cert.NotAfter) { From d8f19cfde887c089cbc32aa4de3bb37ecc818743 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 4 Jun 2024 16:50:03 +0800 Subject: [PATCH 34/82] updated timestamping Signed-off-by: Patrick Zheng --- verifier/verifier.go | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 8ac2919a..8a3668b2 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -521,7 +521,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus // under signing scheme notary.x509 if signerInfo := outcome.EnvelopeContent.SignerInfo; signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { - logger.Info("under signing scheme notary.x509...") + logger.Info("Under signing scheme notary.x509...") performTimestampVerification := true timeStampLowerLimit := time.Now() timeStampUpperLimit := timeStampLowerLimit @@ -666,7 +666,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus 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") + logger.Debug("No verification impacting errors encountered while checking timestamping certificate chain revocation, status is OK") case revocationresult.ResultRevoked: return ¬ation.ValidationResult{ Error: fmt.Errorf("timestamping certificate with subject %q is revoked", problematicCertSubject), @@ -683,7 +683,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } // 5. Check the timestamp against the signing certificate chain logger.Info("Checking the timestamp against the signing certificate chain...") - logger.Infof("timestamp range: [%v, %v]", timeStampLowerLimit, timeStampUpperLimit) + logger.Infof("Timestamp range: [%v, %v]", timeStampLowerLimit, timeStampUpperLimit) for _, cert := range signerInfo.CertificateChain { if timeStampLowerLimit.Before(cert.NotBefore) { return ¬ation.ValidationResult{ @@ -702,7 +702,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } else if signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509SigningAuthority { // under signing scheme notary.x509.signingAuthority - logger.Info("under signing scheme notary.x509.signingAuthority...") + logger.Info("Under signing scheme notary.x509.signingAuthority...") authenticSigningTime := signerInfo.SignedAttributes.SigningTime for _, cert := range signerInfo.CertificateChain { if authenticSigningTime.Before(cert.NotBefore) || authenticSigningTime.After(cert.NotAfter) { @@ -733,12 +733,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], @@ -753,7 +753,7 @@ func verifyRevocation(outcome *notation.VerificationOutcome, r revocation.Revoca 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") + 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: @@ -774,7 +774,7 @@ func revocationFinalResult(certResults []*revocationresult.CertRevocationResult, 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), certChain[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 { From f1497b1f9233d29c8c6acc17e92ccd3d7d20cc83 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 11 Jun 2024 13:43:16 +0800 Subject: [PATCH 35/82] update Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 6b63819d..0e3c8e13 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240604074342-99b519049ef9 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240611053818-29d77ead8420 replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240604030442-e5d82db3a4d4 diff --git a/go.sum b/go.sum index c0ddc38a..cd74d385 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240604074342-99b519049ef9 h1:gMwiXl+IGOeVhF4KUHbfqbvqZsgONcqPtzfYBexFKRE= -github.com/Two-Hearts/notation-core-go v0.0.0-20240604074342-99b519049ef9/go.mod h1:uk5VrENYWqPdnnBOZCEk1XEfilOscHJckfhaWzuMJlU= +github.com/Two-Hearts/notation-core-go v0.0.0-20240611053818-29d77ead8420 h1:csyLPcBqLKcgEqyqjEsbCplRxcMk9P1oHuP3ECzitwk= +github.com/Two-Hearts/notation-core-go v0.0.0-20240611053818-29d77ead8420/go.mod h1:uk5VrENYWqPdnnBOZCEk1XEfilOscHJckfhaWzuMJlU= github.com/Two-Hearts/tspclient-go v0.0.0-20240604030442-e5d82db3a4d4 h1:WCm4ObRL++IM3gVexV7evDbhzk2c4iAZYJmlTWIBOnQ= github.com/Two-Hearts/tspclient-go v0.0.0-20240604030442-e5d82db3a4d4/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= From ee0b91b980f5d6643cddbade9ee36659f419941a Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 11 Jun 2024 17:22:36 +0800 Subject: [PATCH 36/82] build cert chain from tsa token Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- signer/signer.go | 7 +------ verifier/verifier.go | 34 ++++++++++++++++++++++++---------- 4 files changed, 28 insertions(+), 19 deletions(-) diff --git a/go.mod b/go.mod index 3676e570..c9c2acdc 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240611053818-29d77ead8420 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240611085403-02dce641a74d replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240604030442-e5d82db3a4d4 diff --git a/go.sum b/go.sum index 48196521..2341a25a 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240611053818-29d77ead8420 h1:csyLPcBqLKcgEqyqjEsbCplRxcMk9P1oHuP3ECzitwk= -github.com/Two-Hearts/notation-core-go v0.0.0-20240611053818-29d77ead8420/go.mod h1:uk5VrENYWqPdnnBOZCEk1XEfilOscHJckfhaWzuMJlU= +github.com/Two-Hearts/notation-core-go v0.0.0-20240611085403-02dce641a74d h1:Jang//VKYgXC2lxp7E2YaTk+FpsAmUSEs9NVrNBrAHE= +github.com/Two-Hearts/notation-core-go v0.0.0-20240611085403-02dce641a74d/go.mod h1:uk5VrENYWqPdnnBOZCEk1XEfilOscHJckfhaWzuMJlU= github.com/Two-Hearts/tspclient-go v0.0.0-20240604030442-e5d82db3a4d4 h1:WCm4ObRL++IM3gVexV7evDbhzk2c4iAZYJmlTWIBOnQ= github.com/Two-Hearts/tspclient-go v0.0.0-20240604030442-e5d82db3a4d4/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= diff --git a/signer/signer.go b/signer/signer.go index af693d36..8db490d1 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -144,14 +144,9 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts return nil, nil, err } - var timestampErr *signature.TimestampError sig, err := sigEnv.Sign(signReq) if err != nil { - if !errors.As(err, ×tampErr) { - return nil, nil, err - } - // warn on timestamping error, but do not fail the signing process - logger.Warnf("Failed to timestamp the signature. Error: %v", timestampErr) + return nil, nil, err } envContent, err := sigEnv.Verify() diff --git a/verifier/verifier.go b/verifier/verifier.go index 8a3668b2..eab6b3cb 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -612,7 +612,16 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - roots := x509.NewCertPool() + tsaCertChain, err := signedToken.Verify(ctx, x509.VerifyOptions{ + CurrentTime: ts, + }) + if err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to verify the timestamp countersignature with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) if err != nil { return ¬ation.ValidationResult{ @@ -623,21 +632,26 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } if len(trustTSACerts) < 1 { return ¬ation.ValidationResult{ - Error: errors.New("no TSA root cert found in trust store"), + Error: errors.New("no trusted TSA certificate found in trust store"), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - for _, cert := range trustTSACerts { - roots.AddCert(cert) + var foundTrustedCert bool + for _, trust := range trustTSACerts { + for _, cert := range tsaCertChain { + if trust.Equal(cert) { + foundTrustedCert = true + break + } + } + if foundTrustedCert { + break + } } - tsaCertChain, err := signedToken.Verify(ctx, x509.VerifyOptions{ - Roots: roots, - CurrentTime: ts, - }) - if err != nil { + if !foundTrustedCert { return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to verify the timestamp countersignature with error: %w", err), + Error: errors.New("failed to verify the timestamp countersignature with error: tsa certificate chain does not contain trusted certificate in trust store"), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } From 3cdb0b204de5e00b663a74b9d8e5373af57f70cb Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 11 Jun 2024 18:45:01 +0800 Subject: [PATCH 37/82] update Signed-off-by: Patrick Zheng --- verifier/verifier.go | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index eab6b3cb..54029612 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -622,6 +622,17 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } + // 3. Validate timestamping certificate chain + logger.Info("Validating timestamping certificate chain...") + if err := nx509.ValidateTimeStampingCertChain(tsaCertChain, nil); err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to validate the timestamping certificate chain with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + // 4. Check authenticity of the TSA against trust store + logger.Info("Checking TSA authenticity against the trust store...") trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) if err != nil { return ¬ation.ValidationResult{ @@ -656,16 +667,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - // 3. Validate timestamping certificate chain - logger.Info("Validating timestamping certificate chain...") - if err := nx509.ValidateTimeStampingCertChain(tsaCertChain, nil); err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to validate the timestamping certificate chain with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - // 4. Perform the timestamping certificate chain revocation check + // 5. Perform the timestamping certificate chain revocation check logger.Info("Checking timestamping certificate chain revocation...") timeStampLowerLimit = ts.Add(-accuracy) timeStampUpperLimit = ts.Add(accuracy) @@ -695,7 +697,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - // 5. Check the timestamp against the signing certificate chain + // 6. Check the timestamp against the signing certificate chain logger.Info("Checking the timestamp against the signing certificate chain...") logger.Infof("Timestamp range: [%v, %v]", timeStampLowerLimit, timeStampUpperLimit) for _, cert := range signerInfo.CertificateChain { From 09075e730c2a3c42abbaaee681c98b21209187ef Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 14 Jun 2024 09:09:02 +0800 Subject: [PATCH 38/82] update Signed-off-by: Patrick Zheng --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index c9c2acdc..c0fd9407 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240611085403-02dce641a74d +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240614010738-f309851427d4 -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240604030442-e5d82db3a4d4 +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240614004631-5aa21481e88c diff --git a/go.sum b/go.sum index 2341a25a..e7c57354 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240611085403-02dce641a74d h1:Jang//VKYgXC2lxp7E2YaTk+FpsAmUSEs9NVrNBrAHE= -github.com/Two-Hearts/notation-core-go v0.0.0-20240611085403-02dce641a74d/go.mod h1:uk5VrENYWqPdnnBOZCEk1XEfilOscHJckfhaWzuMJlU= -github.com/Two-Hearts/tspclient-go v0.0.0-20240604030442-e5d82db3a4d4 h1:WCm4ObRL++IM3gVexV7evDbhzk2c4iAZYJmlTWIBOnQ= -github.com/Two-Hearts/tspclient-go v0.0.0-20240604030442-e5d82db3a4d4/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240614010738-f309851427d4 h1:uWhmi+pelmgrU9nskvHj0iaoXfYzBrbCjT+jEUdiTbI= +github.com/Two-Hearts/notation-core-go v0.0.0-20240614010738-f309851427d4/go.mod h1:MOqk8+9Hpx4b5tbUireNZfXX2ioWw3p+tUpgJSVIf3E= +github.com/Two-Hearts/tspclient-go v0.0.0-20240614004631-5aa21481e88c h1:IL7bEELXuO9QhjkhERYBaQD7stFeT7/pgNtXtvXi+mk= +github.com/Two-Hearts/tspclient-go v0.0.0-20240614004631-5aa21481e88c/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From b002bea38168b9d0dcfbb5390b7d5de53b657333 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 18 Jun 2024 13:29:02 +0800 Subject: [PATCH 39/82] updated timestamping Signed-off-by: Patrick Zheng --- go.mod | 4 ++-- go.sum | 8 ++++---- verifier/verifier.go | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 751d3741..ffcf0243 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240614010738-f309851427d4 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240618052238-43b2412f153d -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240614004631-5aa21481e88c +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240618021928-8938258a8bd9 diff --git a/go.sum b/go.sum index fe9ebdec..dc49f21a 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240614010738-f309851427d4 h1:uWhmi+pelmgrU9nskvHj0iaoXfYzBrbCjT+jEUdiTbI= -github.com/Two-Hearts/notation-core-go v0.0.0-20240614010738-f309851427d4/go.mod h1:MOqk8+9Hpx4b5tbUireNZfXX2ioWw3p+tUpgJSVIf3E= -github.com/Two-Hearts/tspclient-go v0.0.0-20240614004631-5aa21481e88c h1:IL7bEELXuO9QhjkhERYBaQD7stFeT7/pgNtXtvXi+mk= -github.com/Two-Hearts/tspclient-go v0.0.0-20240614004631-5aa21481e88c/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240618052238-43b2412f153d h1:gEQfHJBM0FqpCEK4kkSJwhh0S+LIbjNOezT2SP7a8oY= +github.com/Two-Hearts/notation-core-go v0.0.0-20240618052238-43b2412f153d/go.mod h1:2+fC2xU0ai2zw1NhZS5h1lhv6mYTKorAh6xv3OnDKE4= +github.com/Two-Hearts/tspclient-go v0.0.0-20240618021928-8938258a8bd9 h1:AV5JQ4TOXFoAKgjq68j3VQJNId5CPIp7x+HUUadiyhc= +github.com/Two-Hearts/tspclient-go v0.0.0-20240618021928-8938258a8bd9/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/verifier/verifier.go b/verifier/verifier.go index 54029612..50824e7b 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -604,7 +604,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - ts, accuracy, err := info.Timestamp(signerInfo.Signature) + ts, accuracy, err := info.Validate(signerInfo.Signature) if err != nil { return ¬ation.ValidationResult{ Error: fmt.Errorf("failed to get timestamp from timestamp countersignature with error: %w", err), From 1a24903aaf7df082f1ea6832b7e3317ac06dc250 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 18 Jun 2024 17:34:01 +0800 Subject: [PATCH 40/82] first batch of tests Signed-off-by: Patrick Zheng --- verifier/helpers_test.go | 7 +- .../coseSigEnvExpiredWithTimestamp.sig | Bin 0 -> 7365 bytes .../timestamp/coseSigEnvWithTimestamp.sig | Bin 0 -> 7362 bytes .../jwsSigEnvExpiredWithTimestamp.sig | 1 + .../timestamp/jwsSigEnvWithTimestamp.sig | 1 + .../timestamp/sigEnvWithoutTimestamp.sig | 1 + .../ca/valid-trust-store/TestTimestamp.crt | 20 ++ .../tsa/test-timestamp/globalsignRoot.cer | Bin 0 -> 1415 bytes verifier/timestamp_test.go | 203 ++++++++++++++++++ verifier/verifier.go | 5 +- 10 files changed, 231 insertions(+), 7 deletions(-) create mode 100644 verifier/testdata/timestamp/coseSigEnvExpiredWithTimestamp.sig create mode 100644 verifier/testdata/timestamp/coseSigEnvWithTimestamp.sig create mode 100644 verifier/testdata/timestamp/jwsSigEnvExpiredWithTimestamp.sig create mode 100644 verifier/testdata/timestamp/jwsSigEnvWithTimestamp.sig create mode 100644 verifier/testdata/timestamp/sigEnvWithoutTimestamp.sig create mode 100644 verifier/testdata/truststore/x509/ca/valid-trust-store/TestTimestamp.crt create mode 100644 verifier/testdata/truststore/x509/tsa/test-timestamp/globalsignRoot.cer create mode 100644 verifier/timestamp_test.go diff --git a/verifier/helpers_test.go b/verifier/helpers_test.go index 730bb988..24dc44a0 100644 --- a/verifier/helpers_test.go +++ b/verifier/helpers_test.go @@ -83,17 +83,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, x509truststore) + _, err := loadX509TrustStores(context.Background(), signature.SigningSchemeX509, &dummyPolicy, 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, x509truststore) + _, err = loadX509TrustStores(context.Background(), signature.SigningSchemeX509SigningAuthority, &dummyPolicy, 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) { diff --git a/verifier/testdata/timestamp/coseSigEnvExpiredWithTimestamp.sig b/verifier/testdata/timestamp/coseSigEnvExpiredWithTimestamp.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/jwsSigEnvExpiredWithTimestamp.sig b/verifier/testdata/timestamp/jwsSigEnvExpiredWithTimestamp.sig new file mode 100644 index 00000000..bcf35a74 --- /dev/null +++ b/verifier/testdata/timestamp/jwsSigEnvExpiredWithTimestamp.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/jwsSigEnvWithTimestamp.sig b/verifier/testdata/timestamp/jwsSigEnvWithTimestamp.sig new file mode 100644 index 00000000..ec1c0f4e --- /dev/null +++ b/verifier/testdata/timestamp/jwsSigEnvWithTimestamp.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/sigEnvWithoutTimestamp.sig b/verifier/testdata/timestamp/sigEnvWithoutTimestamp.sig new file mode 100644 index 00000000..64d36fbc --- /dev/null +++ b/verifier/testdata/timestamp/sigEnvWithoutTimestamp.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/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..8c1d3021 --- /dev/null +++ b/verifier/timestamp_test.go @@ -0,0 +1,203 @@ +// 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" + "os" + "testing" + + "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{"*"}, + } + // valid JWS signature envelope with timestamp countersignature + jwsEnvContent, err := parseEnvContent("testdata/timestamp/jwsSigEnvWithTimestamp.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/coseSigEnvWithTimestamp.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, trustStore, 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, trustStore, 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/jwsSigEnvExpiredWithTimestamp.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, trustStore, 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/coseSigEnvExpiredWithTimestamp.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, trustStore, 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, trustStore, 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, trustStore, 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/coseSigEnvExpiredWithTimestamp.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, trustStore, 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/sigEnvWithoutTimestamp.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, trustStore, 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) + } + }) +} + +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() +} diff --git a/verifier/verifier.go b/verifier/verifier.go index 50824e7b..f9315134 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -557,14 +557,14 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus for _, cert := range signerInfo.CertificateChain { if timeStampLowerLimit.Before(cert.NotBefore) { return ¬ation.ValidationResult{ - Error: fmt.Errorf("verification time %q is before certificate %q validity period, it will be valid from %q", timeStampLowerLimit.Format(time.RFC1123Z), cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), + Error: fmt.Errorf("verification time is before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } if timeStampUpperLimit.After(cert.NotAfter) { return ¬ation.ValidationResult{ - Error: fmt.Errorf("verification time %q is after certificate %q validity period, it was expired at %q", timeStampUpperLimit.Format(time.RFC1123Z), cert.Subject, cert.NotAfter.Format(time.RFC1123Z)), + Error: fmt.Errorf("verification time is after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.Format(time.RFC1123Z)), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } @@ -631,6 +631,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } + logger.Info("TSA identity is: %s", tsaCertChain[0].Subject) // 4. Check authenticity of the TSA against trust store logger.Info("Checking TSA authenticity against the trust store...") trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) From d22e809302f0d7e3f3b40be37b8239d99d451a73 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 18 Jun 2024 17:39:07 +0800 Subject: [PATCH 41/82] fixed tests Signed-off-by: Patrick Zheng --- verifier/truststore/truststore_test.go | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) 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 From a8811e595ce9058f115acc679ace18d3990f6428 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 19 Jun 2024 17:41:36 +0800 Subject: [PATCH 42/82] added more tests Signed-off-by: Patrick Zheng --- .../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 .../TimestampTokenWithSHA1RootCert.p7s | Bin 0 -> 5955 bytes .../coseExpiredWithTimestamp.sig} | Bin .../coseWithTimestamp.sig} | Bin .../jwsExpiredWithTimestamp.sig} | 0 .../jwsWithTimestamp.sig} | 0 .../sigEnv/timestampAfterNotAfter.sig | Bin 0 -> 7365 bytes .../sigEnv/timestampBeforeNotBefore.sig | 1 + .../withoutTimestamp.sig} | 0 .../TestTimestampNotYetValid.crt | 20 ++ .../tsa/test-mismatch/wabbit-networks.io.crt | 20 ++ verifier/timestamp_test.go | 265 +++++++++++++++++- verifier/verifier.go | 7 +- 16 files changed, 296 insertions(+), 17 deletions(-) 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/countersignature/TimestampTokenWithSHA1RootCert.p7s rename verifier/testdata/timestamp/{coseSigEnvExpiredWithTimestamp.sig => sigEnv/coseExpiredWithTimestamp.sig} (100%) rename verifier/testdata/timestamp/{coseSigEnvWithTimestamp.sig => sigEnv/coseWithTimestamp.sig} (100%) rename verifier/testdata/timestamp/{jwsSigEnvExpiredWithTimestamp.sig => sigEnv/jwsExpiredWithTimestamp.sig} (100%) rename verifier/testdata/timestamp/{jwsSigEnvWithTimestamp.sig => sigEnv/jwsWithTimestamp.sig} (100%) create mode 100644 verifier/testdata/timestamp/sigEnv/timestampAfterNotAfter.sig create mode 100644 verifier/testdata/timestamp/sigEnv/timestampBeforeNotBefore.sig rename verifier/testdata/timestamp/{sigEnvWithoutTimestamp.sig => sigEnv/withoutTimestamp.sig} (100%) 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 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 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 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 zcmc(jc|6qJ+s9|d7{)TfWXm#SEz5Ui>`PgaeJNy1O!i%4WG!ZtJ^PY`NlFPZiQI_F zQj#Si$(k0jgpmCib$9>V%k%mz&+mRc-+yMVbIx_P@3}tj^SuBPcNq+RAWAoCg&9l- zA(OcC0TOo(1Wbcw0hnQMhbUdJGYu31rUe1S=P<@!Tf+B%p=4q$l=uK3-iLs}F!(_j z7z!q1AT$8_4}MTor07?_Ty?&+hN4KwI`1%fK0>!pUHvgzeWLgq&z57Y5TrE>F&nKa z>Utm@v|vO|Cj`e_MgTO_j>(pV7JwO=5rD&JETAxUh^9808{phA7?}3xc=?{jd6~Jp z`k;KyO8Mi^5`frF6%7;WN0t9hmARP)%EcFt(r`M9^Ko=`LP?=?WXYtxP5=pJ0g#|- zWa>x|$R050sJrP+=`%aX`?>qLqO>%qvoO=uz$(gqpANv!$&5h*au@|bNlp%fwc%vOVgPxJ;&&5c^SA5) zKmr%+UL^G;(~!VPAZmFWgajsnMgaHAp;^p6*Uc-H?47Iwph8>5?!KQm34|Nxj&UK5 zq6FNee|hiR_v~fLwdukYi>cxnmG<@1ITtijLokM`Ul(}4UGAZFHq_&u#0MD#Mm(Z8)t zd&K9nkZ|?0pj_T|QeFA^#}^dOf5>$T5hc%~D(c2w9}vmqIzHjuYX~p|wM!jMoUvp) z9GqcVL{pB9#8j*2eXUH*VrMd~&MU6eFlM|Q+rHi;cqAELn-h$I~8K{GAMEQz?5IX8Nw9SnhWNi9G5R@*lergBIBvWf)_URp@c=SW0#7A zqI4nXn>A>l{iZM^5is1TMnSa!EkNV9xCQeAvH<31ClD})s2hRc=dUay6BrmM?fN~= zc7jRT(broB@9gL6?@sW=2g`hqOFnie1fc3e@=t#-7)p!;h!KF&&k_I}CAHHdwL@P= zf4@KW=!lbX^(Xk_9C7|`IBHC|$^u%yxk928es%SCb_~Ef|Jm8m8Bh3Q2hxss0wA!n z*8NZ}fFlAq#nIya@!fMvZ6$2s7xjl-PwJgBsXIVzAOKYc6ajg%EEy98{5q5)-s{if z{KXhvy90=-5;P_125oVAOX=NbRFQ8B`Yfr_)pU+9M)m8v@5 zsJ>T-Cm83NRmGOnW#S?!ZGONCR+4SJ8Bl62%HX!0D)vpahT9t;iW**&T=ajNH2S{H zNk3GF)$mP0Z}t4dv5*f+<$`qFqhAtg&iI{6nUT$pN9Qp&wH%T^=+f7y@rtrvPpIdi zeXM+fO<%KV@nM9qIlO9%Ic4C?>wI}t*~Hk$>WM`c{SJlXc)O6PL)YKY(W#|#BlFfO zTn#=~QL5>EQ!};g3}+G6Ht{b0IBj|Ts18RhZXcL3{HRhgp~au^lxFt}86huWu_6fM zSn4HkrQOBWZ%;G=hMW=>7BA0ER!75&>KWJph0_AoA0_aC?g2r`+=#6TC`e~eNM)z`FCA7cE4o#w*)wqU7~8@^NZ-NfJVTKI@2e?a z1;8e{tlvcM3(;@6WFHBUb7@|=CKlKzs8QD2^(c-wT zFX0Czj?1Ij0oI)s4D1a5Xz{a6*J=Y73uc-YQ% zx@zvFbEh_=xmty}8C`s~&ja)9xLfE{m4%RV8wjfrqQ_Xd7r!&k zxxegvVk?dhen=SMD%!e1VJ4@SQ_|Z*Ke%q)w4(IB)?j;NvFVf2Tw7sCZ;;ok3G>~@ z^-6xqsjOpjiT1;|OBaGxu%v<&wx4@qomTe96n$B)o-1oS>3yk9RFTUjmIgeWEwXyX zXY#5Y#Lz*t6Oshp#LuSA7qJa%vKdX^7JVNGDM45=!MkyJqA?p!DMo`%U$paod34zP z`s=fh3@?vMZ9*rPnV|0^)(pyddlU#42KZd=$oePop9?#c*{8-`o;8(Vn&N%eGV1&u z1wKz6gi55Hn2`QyQ+Xt`i$|D0YCWDBet3C6{s$gp04d-gS%NGUCGx-H zVaG)ZFHhx;7ofA_hk~jDhX7R=l=>I+AL4b_6_hF#Kj1PRGhpd@P}81R1ZVuEsaBlp zM4w^9;66IPmUTvWDM;A?E1=ZE;mNJ8CqmCZk+afQ$ehHVxe!&rIjqrOGFErz#cbpL zgqDk227859xsFT=JT5HhqI6C_KH2>$!ha_i`4*HH0HWfADlm*F8wP ztgg1j(DbB!{wd@Pe$Sb+elJ-v7pD{~(^I(azP*&K$Zhrb_OnzooH zY=AL^-ar4;wZ80*$#VvolIhZRG=+kDYM%6qcbT^zIddu$fp^#F}obm}Ky{>iZo2cf}V-v43?}g1c zxiF?iv>h4tPd8pHiVZgja-@ICX6mi!B4bn&EN*n1Cypngnwy9?-xOEpWGKk1<<_sJ z8rMv5d6j&n8VzfHIPQ&s-Q-`b`CNScLBm6mqiNR{uGorA1JvLl{pTn|0vDM}M1!t&K$=BjwvEz_!oDc{B~R{Iw`kSo?+ z7|oTx=4&1|k3Zof9n*YF^T^)x+3U@UnK{PBHjFxpFnPT|pze&q`yZnmkk_E)jFVflNn<{Y6#9EO7q~|SOxZcpy77zL=Ce2A zmv~sC{fG>=t_1MqDM!(Q@&+UNL{{I@=80Jwo>j7)TD@`YbtFso_6Webda)C$yVU0G zgp>@iGU+j(*K5vj;&DU-t1aD2XtOH4s;M39gNWunX5D=5Eop7xG9%M9$1Cx}<3s!E{*NfZ{s$<*{=FyxgF$*Fr?AC6 z6;6z~bgujQC#a6q+zKx9z3xR>(0y%qb$%H-wac#M9B`MTny3LRqr1M47Tn26YXiD)OQ*@w3+<2X6Y z*N&mccihUKAG=-0gPsbj8b2^ot>C=#K~8eDM^oa1y#q~&Chlg1r3Y4XL=GL*c1Ypi zo2ECyOU7&qRW;Q*Q?;m497i=7`%WshsP3LBID9`(1YC9!Ako-UZ>Ksxq?8c~qCQ|j zD>M4vrA2mfKmYue{%;B?uv@Yr>a_>tw=xt4>e*K+D9Xcsw~91IH* z;#g{oth&%9p0`PRmbJMw2ETC>qSZ=?%Z1ttKbJNbb08fZJAQ|WsN?4~P@&mV1kaJ}yy^T`!y}I2H zG>-e!gRHsIz-p%}Ar1DA*ynOiuQPj%n!9t{rg`Ht8JTwGY>WFv66X&g(FD~09TE9U zjo7uz-%|n9%{5RTY&0$2ddf7nl4-83SDOifYn0q$kBSnf!?t;TAk_Qe*bG$#(!*D2C2#N|DdCtOC2MMgfN|>n>qwm*EMf7-ys!H5V(+djZ zvxx?X<-5j%$e@X2fS3yquK>g>D2lyrvI({AZ7gPvPjLGfL~?d=9lXNLLUhhr4zFr& zSq1z7`$D__haKFN0*8{o5wC*P^|H(DTtjC)9de|<4P^1K+&N@(t)es3;ChpDv)%U9 zW@sE!Bg^*Ord}W`SIXk4oDv_*zU<=M0Dq&>fF#dZzFcbO6UWR;BoL`p>PYW1@cwI$tMkoNA_^SUkv0e4zPGrQXu!;d$Q#|GDDIIf{@ zW5sPJc~)v1$MbZTcq^VSX-1gz)`Pz`&J3#*9%5s>TvliB?Na-xq|=lMNvYbta-_Mo z3r9v(TFxt+d}_w?(Ylw5xt&dEtQ698m$&do1t>Ydup9|AWn@_OO}J0SAgcFyH0Pm4 zrhM$9;qCiQP8yI_xBCw#e2R!1xh>@qb!AElg}Sk|wV7)GYa%$unX_IMicnp#7g?P% 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/countersignature/TimestampTokenWithSHA1RootCert.p7s b/verifier/testdata/timestamp/countersignature/TimestampTokenWithSHA1RootCert.p7s new file mode 100644 index 0000000000000000000000000000000000000000..9785befeaa780d07ee25db374aac490fb3cd2cce GIT binary patch literal 5955 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 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/sigEnvWithoutTimestamp.sig b/verifier/testdata/timestamp/sigEnv/withoutTimestamp.sig similarity index 100% rename from verifier/testdata/timestamp/sigEnvWithoutTimestamp.sig rename to verifier/testdata/timestamp/sigEnv/withoutTimestamp.sig 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/timestamp_test.go b/verifier/timestamp_test.go index 8c1d3021..73479023 100644 --- a/verifier/timestamp_test.go +++ b/verifier/timestamp_test.go @@ -15,8 +15,11 @@ package verifier import ( "context" + "crypto/x509" + "net/http" "os" "testing" + "time" "github.com/notaryproject/notation-core-go/signature" "github.com/notaryproject/notation-core-go/signature/cose" @@ -27,6 +30,8 @@ import ( "github.com/notaryproject/notation-go/verifier/truststore" ) +var revocationHttpClient = &http.Client{Timeout: 2 * time.Second} + func TestAuthenticTimestamp(t *testing.T) { dir.UserConfigDir = "testdata" trustStore := truststore.NewX509TrustStore(dir.ConfigFS()) @@ -41,13 +46,13 @@ func TestAuthenticTimestamp(t *testing.T) { TrustedIdentities: []string{"*"}, } // valid JWS signature envelope with timestamp countersignature - jwsEnvContent, err := parseEnvContent("testdata/timestamp/jwsSigEnvWithTimestamp.sig", jws.MediaTypeEnvelope) + 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/coseSigEnvWithTimestamp.sig", cose.MediaTypeEnvelope) + coseEnvContent, err := parseEnvContent("testdata/timestamp/sigEnv/coseWithTimestamp.sig", cose.MediaTypeEnvelope) if err != nil { t.Fatalf("failed to get signature envelope content: %v", err) } @@ -57,7 +62,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: jwsEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) if err := authenticTimestampResult.Error; err != nil { t.Fatalf("expected nil error, but got %s", err) } @@ -68,14 +73,14 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) 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/jwsSigEnvExpiredWithTimestamp.sig", jws.MediaTypeEnvelope) + jwsEnvContent, err := parseEnvContent("testdata/timestamp/sigEnv/jwsExpiredWithTimestamp.sig", jws.MediaTypeEnvelope) if err != nil { t.Fatalf("failed to get signature envelope content: %v", err) } @@ -83,14 +88,14 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: jwsEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) 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/coseSigEnvExpiredWithTimestamp.sig", cose.MediaTypeEnvelope) + coseEnvContent, err := parseEnvContent("testdata/timestamp/sigEnv/coseExpiredWithTimestamp.sig", cose.MediaTypeEnvelope) if err != nil { t.Fatalf("failed to get signature envelope content: %v", err) } @@ -98,7 +103,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) if err := authenticTimestampResult.Error; err != nil { t.Fatalf("expected nil error, but got %s", err) } @@ -119,7 +124,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) if err := authenticTimestampResult.Error; err != nil { t.Fatalf("expected nil error, but got %s", err) } @@ -140,7 +145,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: jwsEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) 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) @@ -158,7 +163,7 @@ func TestAuthenticTimestamp(t *testing.T) { TrustStores: []string{"ca:valid-trust-store"}, TrustedIdentities: []string{"*"}, } - coseEnvContent, err := parseEnvContent("testdata/timestamp/coseSigEnvExpiredWithTimestamp.sig", cose.MediaTypeEnvelope) + coseEnvContent, err := parseEnvContent("testdata/timestamp/sigEnv/coseExpiredWithTimestamp.sig", cose.MediaTypeEnvelope) if err != nil { t.Fatalf("failed to get signature envelope content: %v", err) } @@ -166,7 +171,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) 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) @@ -174,7 +179,7 @@ func TestAuthenticTimestamp(t *testing.T) { }) t.Run("verify Authentic Timestamp failed due to missing timestamp countersignature", func(t *testing.T) { - envContent, err := parseEnvContent("testdata/timestamp/sigEnvWithoutTimestamp.sig", jws.MediaTypeEnvelope) + envContent, err := parseEnvContent("testdata/timestamp/sigEnv/withoutTimestamp.sig", jws.MediaTypeEnvelope) if err != nil { t.Fatalf("failed to get signature envelope content: %v", err) } @@ -182,12 +187,238 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) 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, trustStore, outcome, revocationHttpClient) + 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, trustStore, outcome, revocationHttpClient) + 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, trustStore, outcome, revocationHttpClient) + 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, trustStore, outcome, revocationHttpClient) + 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 failed to validate tsa cert chain", func(t *testing.T) { + signedToken, err := os.ReadFile("testdata/timestamp/countersignature/TimeStampTokenWithSHA1RootCert.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, trustStore, outcome, revocationHttpClient) + expectedErrMsg := "failed to validate the timestamping certificate chain with error: root certificate with subject \"CN=DigiCert Assured ID Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US\" is invalid or not self-signed. Certificate chain must end with a valid self-signed root certificate. Error: x509: cannot verify signature: insecure algorithm SHA1-RSA (temporarily override with GODEBUG=x509sha1=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 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, trustStore, outcome, revocationHttpClient) + 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, dummyTrustStore{}, outcome, revocationHttpClient) + 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, trustStore, outcome, revocationHttpClient) + expectedErrMsg := "failed to verify the timestamp countersignature with error: tsa certificate chain does not contain trusted certificate 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 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, trustStore, outcome, revocationHttpClient) + expectedErrMsg := "timestamp lower limit \"Wed, 19 Jun 2024 09:30:13 +0000\" is 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, trustStore, outcome, revocationHttpClient) + expectedErrMsg := "timestamp upper limit \"Wed, 19 Jun 2024 09:35:59 +0000\" is 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) { @@ -201,3 +432,9 @@ func parseEnvContent(filepath, format string) (*signature.EnvelopeContent, error } 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/verifier.go b/verifier/verifier.go index f9315134..8973a85f 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -288,7 +288,7 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop // verify authentic timestamp logger.Debug("Validating authentic timestamp") - authenticTimestampResult := verifyAuthenticTimestamp(ctx, trustPolicy, v.trustStore, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(ctx, trustPolicy, v.trustStore, outcome, &http.Client{Timeout: 2 * time.Second}) outcome.VerificationResults = append(outcome.VerificationResults, authenticTimestampResult) logVerificationResult(logger, authenticTimestampResult) if isCriticalFailure(authenticTimestampResult) { @@ -516,7 +516,7 @@ func verifyExpiry(outcome *notation.VerificationOutcome) *notation.ValidationRes } } -func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, outcome *notation.VerificationOutcome) *notation.ValidationResult { +func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, outcome *notation.VerificationOutcome, revocationHttpClient *http.Client) *notation.ValidationResult { logger := log.GetLogger(ctx) // under signing scheme notary.x509 @@ -554,6 +554,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus // not performing any timestamp verification, signing cert chain MUST // be valid at time of verification if !performTimestampVerification { + logger.Info("Timestamp verification disabled") for _, cert := range signerInfo.CertificateChain { if timeStampLowerLimit.Before(cert.NotBefore) { return ¬ation.ValidationResult{ @@ -672,7 +673,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus logger.Info("Checking timestamping certificate chain revocation...") timeStampLowerLimit = ts.Add(-accuracy) timeStampUpperLimit = ts.Add(accuracy) - certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit, &http.Client{Timeout: 2 * time.Second}) + certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit, revocationHttpClient) if err != nil { return ¬ation.ValidationResult{ Error: fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err), From 6e558ee0536ec60296b0f066e71619b5cbc8331c Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 19 Jun 2024 17:43:46 +0800 Subject: [PATCH 43/82] update Signed-off-by: Patrick Zheng --- verifier/timestamp_test.go | 40 +++++++++++++++++--------------------- verifier/verifier.go | 6 +++--- 2 files changed, 21 insertions(+), 25 deletions(-) diff --git a/verifier/timestamp_test.go b/verifier/timestamp_test.go index 73479023..1ef283ff 100644 --- a/verifier/timestamp_test.go +++ b/verifier/timestamp_test.go @@ -16,10 +16,8 @@ package verifier import ( "context" "crypto/x509" - "net/http" "os" "testing" - "time" "github.com/notaryproject/notation-core-go/signature" "github.com/notaryproject/notation-core-go/signature/cose" @@ -30,8 +28,6 @@ import ( "github.com/notaryproject/notation-go/verifier/truststore" ) -var revocationHttpClient = &http.Client{Timeout: 2 * time.Second} - func TestAuthenticTimestamp(t *testing.T) { dir.UserConfigDir = "testdata" trustStore := truststore.NewX509TrustStore(dir.ConfigFS()) @@ -62,7 +58,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: jwsEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) if err := authenticTimestampResult.Error; err != nil { t.Fatalf("expected nil error, but got %s", err) } @@ -73,7 +69,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) if err := authenticTimestampResult.Error; err != nil { t.Fatalf("expected nil error, but got %s", err) } @@ -88,7 +84,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: jwsEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) if err := authenticTimestampResult.Error; err != nil { t.Fatalf("expected nil error, but got %s", err) } @@ -103,7 +99,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) if err := authenticTimestampResult.Error; err != nil { t.Fatalf("expected nil error, but got %s", err) } @@ -124,7 +120,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) if err := authenticTimestampResult.Error; err != nil { t.Fatalf("expected nil error, but got %s", err) } @@ -145,7 +141,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: jwsEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, 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) @@ -171,7 +167,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, 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) @@ -187,7 +183,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, 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) @@ -208,7 +204,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, 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) @@ -229,7 +225,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, 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) @@ -251,7 +247,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, 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) @@ -273,7 +269,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, 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) @@ -295,7 +291,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) expectedErrMsg := "failed to validate the timestamping certificate chain with error: root certificate with subject \"CN=DigiCert Assured ID Root CA,OU=www.digicert.com,O=DigiCert Inc,C=US\" is invalid or not self-signed. Certificate chain must end with a valid self-signed root certificate. Error: x509: cannot verify signature: insecure algorithm SHA1-RSA (temporarily override with GODEBUG=x509sha1=1)" if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { t.Fatalf("expected %s, but got %s", expectedErrMsg, err) @@ -317,7 +313,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, 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) @@ -339,7 +335,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, dummyTrustStore{}, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, dummyTrustStore{}, 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) @@ -361,7 +357,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) expectedErrMsg := "failed to verify the timestamp countersignature with error: tsa certificate chain does not contain trusted certificate in trust store" if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { t.Fatalf("expected %s, but got %s", expectedErrMsg, err) @@ -387,7 +383,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) expectedErrMsg := "timestamp lower limit \"Wed, 19 Jun 2024 09:30:13 +0000\" is 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) @@ -413,7 +409,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome, revocationHttpClient) + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) expectedErrMsg := "timestamp upper limit \"Wed, 19 Jun 2024 09:35:59 +0000\" is 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) diff --git a/verifier/verifier.go b/verifier/verifier.go index 8973a85f..96ba2890 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -288,7 +288,7 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop // verify authentic timestamp logger.Debug("Validating authentic timestamp") - authenticTimestampResult := verifyAuthenticTimestamp(ctx, trustPolicy, v.trustStore, outcome, &http.Client{Timeout: 2 * time.Second}) + authenticTimestampResult := verifyAuthenticTimestamp(ctx, trustPolicy, v.trustStore, outcome) outcome.VerificationResults = append(outcome.VerificationResults, authenticTimestampResult) logVerificationResult(logger, authenticTimestampResult) if isCriticalFailure(authenticTimestampResult) { @@ -516,7 +516,7 @@ func verifyExpiry(outcome *notation.VerificationOutcome) *notation.ValidationRes } } -func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, outcome *notation.VerificationOutcome, revocationHttpClient *http.Client) *notation.ValidationResult { +func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.TrustPolicy, x509TrustStore truststore.X509TrustStore, outcome *notation.VerificationOutcome) *notation.ValidationResult { logger := log.GetLogger(ctx) // under signing scheme notary.x509 @@ -673,7 +673,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus logger.Info("Checking timestamping certificate chain revocation...") timeStampLowerLimit = ts.Add(-accuracy) timeStampUpperLimit = ts.Add(accuracy) - certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit, revocationHttpClient) + certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit, &http.Client{Timeout: 2 * time.Second}) if err != nil { return ¬ation.ValidationResult{ Error: fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err), From f642856c634ef13b9c6250afb8c58733a19041a6 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 20 Jun 2024 15:12:08 +0800 Subject: [PATCH 44/82] updated dependencies Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index ffcf0243..e409695b 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240618052238-43b2412f153d +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240620060810-a57701ff7655 replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240618021928-8938258a8bd9 diff --git a/go.sum b/go.sum index dc49f21a..69370976 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240618052238-43b2412f153d h1:gEQfHJBM0FqpCEK4kkSJwhh0S+LIbjNOezT2SP7a8oY= -github.com/Two-Hearts/notation-core-go v0.0.0-20240618052238-43b2412f153d/go.mod h1:2+fC2xU0ai2zw1NhZS5h1lhv6mYTKorAh6xv3OnDKE4= +github.com/Two-Hearts/notation-core-go v0.0.0-20240620060810-a57701ff7655 h1:Up2oCElFITYHvwKayXRCUq23wREpbMew/OwsRV8kYEI= +github.com/Two-Hearts/notation-core-go v0.0.0-20240620060810-a57701ff7655/go.mod h1:2+fC2xU0ai2zw1NhZS5h1lhv6mYTKorAh6xv3OnDKE4= github.com/Two-Hearts/tspclient-go v0.0.0-20240618021928-8938258a8bd9 h1:AV5JQ4TOXFoAKgjq68j3VQJNId5CPIp7x+HUUadiyhc= github.com/Two-Hearts/tspclient-go v0.0.0-20240618021928-8938258a8bd9/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= From 85fd95324a6fd3c0efb68626f3bc349094534e64 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 20 Jun 2024 15:16:35 +0800 Subject: [PATCH 45/82] fixed tests Signed-off-by: Patrick Zheng --- verifier/timestamp_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/verifier/timestamp_test.go b/verifier/timestamp_test.go index 1ef283ff..d098f759 100644 --- a/verifier/timestamp_test.go +++ b/verifier/timestamp_test.go @@ -277,7 +277,7 @@ func TestAuthenticTimestamp(t *testing.T) { }) t.Run("verify Authentic Timestamp failed due to failed to validate tsa cert chain", func(t *testing.T) { - signedToken, err := os.ReadFile("testdata/timestamp/countersignature/TimeStampTokenWithSHA1RootCert.p7s") + signedToken, err := os.ReadFile("testdata/timestamp/countersignature/TimestampTokenWithSHA1RootCert.p7s") if err != nil { t.Fatalf("failed to get signedToken: %v", err) } From 0697044fdb65948165e2af8ea266cf1bddb305fe Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 20 Jun 2024 18:06:29 +0800 Subject: [PATCH 46/82] fixed tests Signed-off-by: Patrick Zheng --- .../TimestampTokenWithSHA1RootCert.p7s | Bin 5955 -> 0 bytes verifier/timestamp_test.go | 22 ------------------ 2 files changed, 22 deletions(-) delete mode 100644 verifier/testdata/timestamp/countersignature/TimestampTokenWithSHA1RootCert.p7s diff --git a/verifier/testdata/timestamp/countersignature/TimestampTokenWithSHA1RootCert.p7s b/verifier/testdata/timestamp/countersignature/TimestampTokenWithSHA1RootCert.p7s deleted file mode 100644 index 9785befeaa780d07ee25db374aac490fb3cd2cce..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 5955 zcmciGc|276{|9ih*!O*B>_nVl?2%z?r7YP}mh2Oyb3SLB*Llw84d6KsQ&1m>Hi+J&2T_8F zcuoMobIO205I7@1PeJVvZ2)qCK*1n#G9WUZg7!yGY9NxftaEc?6&YR|Vh*WjNdh%;wa0PWA>?VW%s>zQ{Q>e*s3mx=6&cQUiF3Rsatz zB0|6*FqnxPRl1g(L8Y4CJaO25?hME7YJMykL`%8_CpaxYO#!ihQm}$8PQW<<_T2^z zD+3DchSqWM^Ou1co^z6gs{^XLCm^iydnaJ#eprmZi!)3g0W&*+L;$KvuoDJIc||3d zIoiwRg#Q^YAM`mlm<|#U;G~yV0F>bf;QOBqC%pm!4!{-U6%np~M@61m#jO_>k4cSUKBe>qPrnw*R089)1ARK3e~ ziks`=w(dLnGoBgWeC^sO(hjY(%LXy>x|+>A8P>EP*BQ9*>3PS7!9hD+Yzp?<3#M$| zsFvD!vl~_VBY{$?9xnq=rp}V5x>Avh+ z@()EDqM!I1Zt+#r*iWx~z=gqYy69VE91)c(kxp&On*ADr(UkvShS(mgUmPULAa2b} zopa`QAk6dAcjU2=DU=DNar#-G-IbzZ6ZX#gT@52`>h7qVJaz4_n6M8oXm)}SOyT*bX{?RNG%upD9Z}B1 z*q#IyoMoQq)<~O&(1SOE2!fp2I}cFV=JtW;r4TcfLIQQRZ-u9Csb;Nr%Frt&)^BI@ zX|8-*sqPr+nDP`|Y1YPf5q&k%uO~q((LNIN#x+$+eVz7Hxjs2dG#{B|onLkfOLu*g zWEC)rR++sd2N!trZx~4)vXl*hJeUGIe5@z01t`*7)VbOKO+dV z1BF7slo0^kZku(t4F<>nj@_2nZi^0}p`enc0FjeZLZ|@P?r|8D8{h<}C@9<_=|H6J zwEHtJxZ6Vn$^~#lusz@y^E!4>4kLw2lfzy)3rom+;tlZcc3^;VK-u!DmsuB7!yh-7>R1?`(yy zFI^D^7uNPh+!@sR zQW&}5g*<%)-B%~w_Bf&HbR4V>L<{ajpz0{$k1|)mY)`;MIUItZsImwfI?x?$nq`mC2P-%SNO2S9qxQy7uV(1{(`uE6qf30Bs2 z1iw7(P%pWoGG}HpT*4_Va(sPhfOFf#V}~+8&^Hx@?5x!r@RSd=mUGj0nd8M&-~8+$ zL!q~f6j)iYe>pLB_gVz1G=d2kM^fw_NwJh4icu;l*NB>jj_Q|um2^E|cj`}%4B+@H zAnX7uDM2K~==S2Vix`}g*xkdltV{s`0lz%6a3Nqfvn1ZQeva7V&CJ`|pJd#3#N+{z zS$`m=Olr#SA@;9G`gguPj#i{Fyx*eXXJ~5CAqHt%O;j#SHO(IGkLt@by6r_Qdm8oG zW`j8!#jb6iduh#mD{L)2miByxU?!u2pb0CjI3~sGH>*3~u&+9m7si=CV#@D-kdC+z zC(JdyIIhvgdA^uiT2p({E&iRU#>%ke;DY4A#ewoF?1CVL%hhD5fw3j@^w_l+J+hDq z6f$-)^sH6zigHkvZAtf=3(l2ht2q75Gf~_x>?_S_h1}063)O3t*jG#)348WQmBnqD zA)L$8I6+Ll8et>}!V{Yif`r8N&th56|A(KCuH>8uc=( z25@!#3?4V>`V}gB%J+P;CHZy|VA*x#yJu7Y1qm|Ji*+A8e<{;`x|T*}@cq8F&PLO+ zZig2h5bp6Y8vkl0DEfQS_{IK2WWb&kBx5`P^gk2^xi<;`M=Smp!t5qgA3@U1AJEyo zV?pR4Kn+kKDiIOU@_Y0Aot!@>@%#tC|N0~PyI5f-;~yqfdlL##!k}>1;ZY&&S7ltX zOvhMzffLV~xwbn@Y+oOh+V+W~FOoukLAUhsQ@+)7crr>mcly+bSIpK0m>2@?)>F-r z;@xIqG<3!g? znar1QC39b|G&qaLcwTSJ2z~BD6S{n-0c-rgX0wo~!uIWsqY7xj+oO;2^o#U9t9s= zA0c~;tF>+k328mAVHNF})}w{OjA ztO2@(pOT-3#;%a{*tULtE^?lXb`}Q~A6s$3Y3EDDQ0q(2pXbTF$oPejvSDE^Ef}%& zaFs!NZg{&;4#j?Cft7)OLRp0;TYBUDaOf8RPkxmo7WRi&47a%AKR-XXusmV%no5hy zX1`c;qcJ}s^ zAhhhugIzxaJTbWAYGsvWZXHi2U1MATj9Gr@3bCEJ+i7e!r?>#`9#68Hj8BLduTCUr zT?={?*il{HR&|z31;TW7bWk~0mOSjzC%h(8qEE2}9w|RE0mU3Rmk0_KG8$~S#|y#Q z2D*-^!BJ@nTFq1=Hio&a^MypW7r7D**~Y3>%+{QnqNnu|oHtw0mv97}#z|XkTuf{# zI@n<4*#WaZ86kOs?!dERt3y|OWRMO;ynOWY#{g{?eoUVCgR2E?vLgjfWpJyn-YyV42t?*XY}Pq#v7lm4%<<>dsOA{iY__6oOe@Kbky*NESIAQ@ z{96nU+Fba3?xg^)Mjp0x)+51k2WwQ8*LNc7e#_om^_voHFoQff{`|ny)6R@j_4t!up zH>|A0n#iE#)J_m?sW|z`!lPHB*c126Tjbz+xbImJ58)k_TJwVv;iGC}E7dV6Ur+U& zF5!A~EDKWuD$KGfvXgvWmkh^4Z~z|SN2#wVA`wE7{$UcDQXZ?*D0;m6_ zehBdWagH3$NGh7`FZlt|`#OW^;CuiNK&mi6*<4qodw=1leS=z7?notXeB8K2+C2r1(qlYngLHwC`yV}0xeba3lZoEzJ;go5KHIY8 zhrP8^fvp_3t?-L&F?gLIdPQ7J4LQ>6NXAz`pZ4z1@+_@;Z$9cx)io!TmaK`sBc%+& zW}^?)+Und@2ox;Lk~>YN)csYrMq=bLFC{OuxF&*1VQiPPPnSIn91EeRaCJ^gV+B45 zJmPZD)4M(SE@qSUj2Xk191KEb#Bgq^i&N`uN=gV2)Ee9J7Ty!7#vu~-Sz|6Z9Mnaw zALz5{z}awY5!b|ZHzczt2kRK$)TpauYt_UaD05CZV_x}@vcUklEuwF`Xnkmuf$#46 zsa3L`Q#%dp`nNI1Q qoqi4H!$}x*xX$_W+)hBmUOyqPGuYBb(Q00 Date: Fri, 21 Jun 2024 12:51:18 +0800 Subject: [PATCH 47/82] tsa root cert pool Signed-off-by: Patrick Zheng --- go.mod | 4 +- go.sum | 8 ++-- verifier/timestamp_test.go | 2 +- verifier/verifier.go | 90 +++++++++++++++++++++++--------------- 4 files changed, 62 insertions(+), 42 deletions(-) diff --git a/go.mod b/go.mod index e409695b..1799e1f9 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240620060810-a57701ff7655 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240621043238-b2551ef71fb2 -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240618021928-8938258a8bd9 +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240621042808-c9a7560c8168 diff --git a/go.sum b/go.sum index 69370976..2ca549e3 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240620060810-a57701ff7655 h1:Up2oCElFITYHvwKayXRCUq23wREpbMew/OwsRV8kYEI= -github.com/Two-Hearts/notation-core-go v0.0.0-20240620060810-a57701ff7655/go.mod h1:2+fC2xU0ai2zw1NhZS5h1lhv6mYTKorAh6xv3OnDKE4= -github.com/Two-Hearts/tspclient-go v0.0.0-20240618021928-8938258a8bd9 h1:AV5JQ4TOXFoAKgjq68j3VQJNId5CPIp7x+HUUadiyhc= -github.com/Two-Hearts/tspclient-go v0.0.0-20240618021928-8938258a8bd9/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240621043238-b2551ef71fb2 h1:oqjGDjiyHhbIIBlxpfwpIpwO30z1aahqEZf1bC/AMkI= +github.com/Two-Hearts/notation-core-go v0.0.0-20240621043238-b2551ef71fb2/go.mod h1:vKJt67z3v3bj4MNXNLQ3LDoXMCfEdQCLkpwsgwqqCgE= +github.com/Two-Hearts/tspclient-go v0.0.0-20240621042808-c9a7560c8168 h1:zkzAWIQRB+OLkeqy3rJT3zZ0xdR8nGLMtbOpPF5yE0s= +github.com/Two-Hearts/tspclient-go v0.0.0-20240621042808-c9a7560c8168/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/verifier/timestamp_test.go b/verifier/timestamp_test.go index 00466d53..a7f20928 100644 --- a/verifier/timestamp_test.go +++ b/verifier/timestamp_test.go @@ -336,7 +336,7 @@ func TestAuthenticTimestamp(t *testing.T) { VerificationLevel: trustpolicy.LevelStrict, } authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy, trustStore, outcome) - expectedErrMsg := "failed to verify the timestamp countersignature with error: tsa certificate chain does not contain trusted certificate in trust store" + 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) } diff --git a/verifier/verifier.go b/verifier/verifier.go index 96ba2890..90d687e1 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -605,6 +605,25 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } + trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) + if err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to load tsa trust store with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + if len(trustTSACerts) < 1 { + return ¬ation.ValidationResult{ + Error: errors.New("no trusted TSA certificate found in trust store"), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + rootCertPool := x509.NewCertPool() + for _, trustedCerts := range trustTSACerts { + rootCertPool.AddCert(trustedCerts) + } ts, accuracy, err := info.Validate(signerInfo.Signature) if err != nil { return ¬ation.ValidationResult{ @@ -615,6 +634,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } tsaCertChain, err := signedToken.Verify(ctx, x509.VerifyOptions{ CurrentTime: ts, + Roots: rootCertPool, }) if err != nil { return ¬ation.ValidationResult{ @@ -634,41 +654,41 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } logger.Info("TSA identity is: %s", tsaCertChain[0].Subject) // 4. Check authenticity of the TSA against trust store - logger.Info("Checking TSA authenticity against the trust store...") - trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to load tsa trust store with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - if len(trustTSACerts) < 1 { - return ¬ation.ValidationResult{ - Error: errors.New("no trusted TSA certificate found in trust store"), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - var foundTrustedCert bool - for _, trust := range trustTSACerts { - for _, cert := range tsaCertChain { - if trust.Equal(cert) { - foundTrustedCert = true - break - } - } - if foundTrustedCert { - break - } - } - if !foundTrustedCert { - return ¬ation.ValidationResult{ - Error: errors.New("failed to verify the timestamp countersignature with error: tsa certificate chain does not contain trusted certificate in trust store"), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } + // logger.Info("Checking TSA authenticity against the trust store...") + // trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) + // if err != nil { + // return ¬ation.ValidationResult{ + // Error: fmt.Errorf("failed to load tsa trust store with error: %w", err), + // Type: trustpolicy.TypeAuthenticTimestamp, + // Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + // } + // } + // if len(trustTSACerts) < 1 { + // return ¬ation.ValidationResult{ + // Error: errors.New("no trusted TSA certificate found in trust store"), + // Type: trustpolicy.TypeAuthenticTimestamp, + // Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + // } + // } + // var foundTrustedCert bool + // for _, trust := range trustTSACerts { + // for _, cert := range tsaCertChain { + // if trust.Equal(cert) { + // foundTrustedCert = true + // break + // } + // } + // if foundTrustedCert { + // break + // } + // } + // if !foundTrustedCert { + // return ¬ation.ValidationResult{ + // Error: errors.New("failed to verify the timestamp countersignature with error: tsa certificate chain does not contain trusted certificate in trust store"), + // Type: trustpolicy.TypeAuthenticTimestamp, + // Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + // } + // } // 5. Perform the timestamping certificate chain revocation check logger.Info("Checking timestamping certificate chain revocation...") timeStampLowerLimit = ts.Add(-accuracy) From 918f50129b284809f3731e26f3dd569aeb971f30 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 21 Jun 2024 13:03:39 +0800 Subject: [PATCH 48/82] tsa root cert pool Signed-off-by: Patrick Zheng --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 1799e1f9..967d106d 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240621043238-b2551ef71fb2 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240621050238-7211f7a046ca -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240621042808-c9a7560c8168 +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240621050135-2126d69f6c98 diff --git a/go.sum b/go.sum index 2ca549e3..2ed30011 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240621043238-b2551ef71fb2 h1:oqjGDjiyHhbIIBlxpfwpIpwO30z1aahqEZf1bC/AMkI= -github.com/Two-Hearts/notation-core-go v0.0.0-20240621043238-b2551ef71fb2/go.mod h1:vKJt67z3v3bj4MNXNLQ3LDoXMCfEdQCLkpwsgwqqCgE= -github.com/Two-Hearts/tspclient-go v0.0.0-20240621042808-c9a7560c8168 h1:zkzAWIQRB+OLkeqy3rJT3zZ0xdR8nGLMtbOpPF5yE0s= -github.com/Two-Hearts/tspclient-go v0.0.0-20240621042808-c9a7560c8168/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240621050238-7211f7a046ca h1:In5KtgXuHVYVH/qi7yOZ8kzjhj7WdGJbvjdTHKHJUhI= +github.com/Two-Hearts/notation-core-go v0.0.0-20240621050238-7211f7a046ca/go.mod h1:PrG624ulyrDrvCo7y+GUP+IEBJIP+6K+RKosICqwU9M= +github.com/Two-Hearts/tspclient-go v0.0.0-20240621050135-2126d69f6c98 h1:9qi4bRsMM8mNSU6c05m2hGKotd45Tcc5JNHWR7Colo4= +github.com/Two-Hearts/tspclient-go v0.0.0-20240621050135-2126d69f6c98/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From d8b32180b53cb37caf99fe1efbe8e45a1c996d1d Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 21 Jun 2024 17:59:37 +0800 Subject: [PATCH 49/82] update timestamp Signed-off-by: Patrick Zheng --- go.mod | 4 ++-- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 967d106d..765a3eb5 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240621050238-7211f7a046ca +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240621095806-e751e91c74bc -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240621050135-2126d69f6c98 +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240621095541-22fd76ec5c45 diff --git a/go.sum b/go.sum index 2ed30011..725121bb 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240621050238-7211f7a046ca h1:In5KtgXuHVYVH/qi7yOZ8kzjhj7WdGJbvjdTHKHJUhI= -github.com/Two-Hearts/notation-core-go v0.0.0-20240621050238-7211f7a046ca/go.mod h1:PrG624ulyrDrvCo7y+GUP+IEBJIP+6K+RKosICqwU9M= -github.com/Two-Hearts/tspclient-go v0.0.0-20240621050135-2126d69f6c98 h1:9qi4bRsMM8mNSU6c05m2hGKotd45Tcc5JNHWR7Colo4= -github.com/Two-Hearts/tspclient-go v0.0.0-20240621050135-2126d69f6c98/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240621095806-e751e91c74bc h1:ZMwU6xLBShKcskNBLhPeADbIF1hCU029aSsXR93h1GA= +github.com/Two-Hearts/notation-core-go v0.0.0-20240621095806-e751e91c74bc/go.mod h1:8sJ1/g7FGm434RgpoIdd6x81YVAlp9h4asLYwqmRMT0= +github.com/Two-Hearts/tspclient-go v0.0.0-20240621095541-22fd76ec5c45 h1:HkEtw8GJ9aKmFjyBfvGvyCpH06Ox/5X7bpmIG+v+bjM= +github.com/Two-Hearts/tspclient-go v0.0.0-20240621095541-22fd76ec5c45/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= From b256493e8029caefea3589c6163520cc6eceab49 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 21 Jun 2024 18:01:44 +0800 Subject: [PATCH 50/82] update timestamp Signed-off-by: Patrick Zheng --- verifier/verifier.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 90d687e1..bb7daba3 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -652,7 +652,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - logger.Info("TSA identity is: %s", tsaCertChain[0].Subject) + logger.Info("TSA identity is: ", tsaCertChain[0].Subject) // 4. Check authenticity of the TSA against trust store // logger.Info("Checking TSA authenticity against the trust store...") // trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) From d06a838e0d28d6d24e2d2bd3a04edd4b0163c893 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 24 Jun 2024 12:54:41 +0800 Subject: [PATCH 51/82] added more tests Signed-off-by: Patrick Zheng --- verifier/helpers_test.go | 27 +++++++++++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/verifier/helpers_test.go b/verifier/helpers_test.go index 24dc44a0..e732afd6 100644 --- a/verifier/helpers_test.go +++ b/verifier/helpers_test.go @@ -114,6 +114,33 @@ 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()) + _, err := loadX509TSATrustStores(context.Background(), signature.SigningSchemeX509, &policyDoc.TrustPolicies[0], 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, &policyDoc.TrustPolicies[0], 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, "@") From d5f686806e38e08c09cb85a1caa0888e45cc7342 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 24 Jun 2024 16:49:27 +0800 Subject: [PATCH 52/82] updated tsa root cert pool Signed-off-by: Patrick Zheng --- go.mod | 4 ++-- go.sum | 8 ++++---- signer/signer.go | 1 + 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/go.mod b/go.mod index 765a3eb5..da70be12 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240621095806-e751e91c74bc +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240624084736-28b80547d251 -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240621095541-22fd76ec5c45 +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240624080215-1284fbf408ce diff --git a/go.sum b/go.sum index 725121bb..39236fe1 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240621095806-e751e91c74bc h1:ZMwU6xLBShKcskNBLhPeADbIF1hCU029aSsXR93h1GA= -github.com/Two-Hearts/notation-core-go v0.0.0-20240621095806-e751e91c74bc/go.mod h1:8sJ1/g7FGm434RgpoIdd6x81YVAlp9h4asLYwqmRMT0= -github.com/Two-Hearts/tspclient-go v0.0.0-20240621095541-22fd76ec5c45 h1:HkEtw8GJ9aKmFjyBfvGvyCpH06Ox/5X7bpmIG+v+bjM= -github.com/Two-Hearts/tspclient-go v0.0.0-20240621095541-22fd76ec5c45/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240624084736-28b80547d251 h1:DsSiFI1r5pxwqgpJq739UTW+r2HZWVhDfKzCGPAuC8E= +github.com/Two-Hearts/notation-core-go v0.0.0-20240624084736-28b80547d251/go.mod h1:ziEtD5U/wCeZNoRJo8JeRJxQgl0AxajLb+v/Hv8p5lM= +github.com/Two-Hearts/tspclient-go v0.0.0-20240624080215-1284fbf408ce h1:2AP1Rk5iOUQETSeBwst7ZzDsdHTEllMC46FfUBMUGr4= +github.com/Two-Hearts/tspclient-go v0.0.0-20240624080215-1284fbf408ce/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/signer/signer.go b/signer/signer.go index 8db490d1..cc3728ed 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -137,6 +137,7 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts logger.Debugf(" SigningScheme: %v", signReq.SigningScheme) logger.Debugf(" SigningAgent: %v", signReq.SigningAgent) logger.Debugf(" TSAServerURL: %v", signReq.TSAServerURL) + logger.Debugf(" TSARootCertificate Subject: %v", signReq.TSARootCertificate.Subject) // perform signing sigEnv, err := signature.NewEnvelope(opts.SignatureMediaType) From 329760b186ae2eb28e6b10298885973550213cb3 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 24 Jun 2024 17:02:16 +0800 Subject: [PATCH 53/82] updated tsa root cert pool Signed-off-by: Patrick Zheng --- notation.go | 6 +++++- signer/signer.go | 12 ++++++------ 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/notation.go b/notation.go index 967a790f..86fb6173 100644 --- a/notation.go +++ b/notation.go @@ -18,6 +18,7 @@ package notation import ( "context" "crypto/sha256" + "crypto/x509" "encoding/hex" "encoding/json" "errors" @@ -62,8 +63,11 @@ type SignerSignOptions struct { // SigningAgent sets the signing agent name SigningAgent string - // TSA denotes the TSA server URL + // TSAServerURL denotes the TSA server URL TSAServerURL string + + // TSARootCertificate denotes the TSA trust anchor + TSARootCertificate *x509.Certificate } // Signer is a generic interface for signing an OCI artifact. diff --git a/signer/signer.go b/signer/signer.go index cc3728ed..53ad03c5 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -118,11 +118,12 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts ContentType: envelope.MediaTypePayloadV1, Content: payloadBytes, }, - Signer: s.signer, - SigningTime: time.Now(), - SigningScheme: signature.SigningSchemeX509, - SigningAgent: signingAgentId, - TSAServerURL: opts.TSAServerURL, + Signer: s.signer, + SigningTime: time.Now(), + SigningScheme: signature.SigningSchemeX509, + SigningAgent: signingAgentId, + TSAServerURL: opts.TSAServerURL, + TSARootCertificate: opts.TSARootCertificate, } // Add expiry only if ExpiryDuration is not zero @@ -137,7 +138,6 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts logger.Debugf(" SigningScheme: %v", signReq.SigningScheme) logger.Debugf(" SigningAgent: %v", signReq.SigningAgent) logger.Debugf(" TSAServerURL: %v", signReq.TSAServerURL) - logger.Debugf(" TSARootCertificate Subject: %v", signReq.TSARootCertificate.Subject) // perform signing sigEnv, err := signature.NewEnvelope(opts.SignatureMediaType) From 48f244827f15a2c3976979e0e5bb4abbd9cbc392 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 25 Jun 2024 13:03:44 +0800 Subject: [PATCH 54/82] updated timestamp trust policy Signed-off-by: Patrick Zheng --- verifier/helpers_test.go | 2 +- verifier/trustpolicy/trustpolicy.go | 30 ++++++-- verifier/trustpolicy/trustpolicy_test.go | 88 ++++++++++++++++------ verifier/verifier.go | 94 ++++++++---------------- 4 files changed, 117 insertions(+), 97 deletions(-) diff --git a/verifier/helpers_test.go b/verifier/helpers_test.go index e732afd6..b50dac52 100644 --- a/verifier/helpers_test.go +++ b/verifier/helpers_test.go @@ -32,7 +32,7 @@ func dummyPolicyStatement() (policyStatement trustpolicy.TrustPolicy) { policyStatement = trustpolicy.TrustPolicy{ Name: "test-statement-name", RegistryScopes: []string{"registry.acme-rockets.io/software/net-monitor"}, - SignatureVerification: trustpolicy.SignatureVerification{VerificationLevel: "strict"}, + SignatureVerification: trustpolicy.SignatureVerification{VerificationLevel: "strict", VerifyTimestamp: "always"}, TrustStores: []string{"ca:valid-trust-store", "signingAuthority:valid-trust-store"}, TrustedIdentities: []string{"x509.subject:CN=Notation Test Root,O=Notary,L=Seattle,ST=WA,C=US"}, } diff --git a/verifier/trustpolicy/trustpolicy.go b/verifier/trustpolicy/trustpolicy.go index 5f1e6361..370a4d13 100644 --- a/verifier/trustpolicy/trustpolicy.go +++ b/verifier/trustpolicy/trustpolicy.go @@ -44,10 +44,6 @@ type ValidationType string // Enforced, Logged, Skipped. type ValidationAction string -// TimestampOption is an enum for timestamp verifiction options such as Always, -// AfterCertExpiry. -type TimestampOption string - // VerificationLevel encapsulates the signature verification preset and its // actions for each verification type type VerificationLevel struct { @@ -69,8 +65,16 @@ const ( ActionSkip ValidationAction = "skip" ) +// TimestampOption is an enum for timestamp verifiction options such as Always, +// AfterCertExpiry. +type TimestampOption string + const ( - OptionAlways TimestampOption = "always" + // 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" ) @@ -174,9 +178,10 @@ type TrustPolicy struct { // SignatureVerification represents verification configuration in a trust policy type SignatureVerification struct { - VerificationLevel string `json:"level"` - Override map[ValidationType]ValidationAction `json:"override,omitempty"` - VerifyTimestamp TimestampOption `json:"verifyTimestamp,omitempty"` + VerificationLevel string `json:"level"` + Override map[ValidationType]ValidationAction `json:"override,omitempty"` + VerifyTimestamp TimestampOption `json:"verifyTimestamp,omitempty"` + SkipTimestampRevocationCheck bool `json:"skipTimestampRevocationCheck,omitempty"` } // Validate validates a policy document according to its version's rule set. @@ -215,6 +220,9 @@ func (policyDoc *Document) Validate() error { if err != nil { return fmt.Errorf("trust policy statement %q has invalid signatureVerification: %w", statement.Name, err) } + if statement.SignatureVerification.VerifyTimestamp != OptionAlways && statement.SignatureVerification.VerifyTimestamp != OptionAfterCertExpiry { + return fmt.Errorf("trust policy statement %q has invalid signatureVerification: verifyTimestamp must be %q or %q, but got %q", statement.Name, OptionAlways, OptionAfterCertExpiry, statement.SignatureVerification.VerifyTimestamp) + } // Any signature verification other than "skip" needs a trust store and // trusted identities @@ -324,6 +332,12 @@ func LoadDocument() (*Document, error) { if err != nil { return nil, fmt.Errorf("malformed trust policy. To create a trust policy, see: %s", trustPolicyLink) } + for idx, statement := range policyDocument.TrustPolicies { + if statement.SignatureVerification.VerifyTimestamp == "" { + // default value for VerifyTimestamp is "always" + policyDocument.TrustPolicies[idx].SignatureVerification.VerifyTimestamp = OptionAlways + } + } return policyDocument, nil } diff --git a/verifier/trustpolicy/trustpolicy_test.go b/verifier/trustpolicy/trustpolicy_test.go index ead28cae..aa73e606 100644 --- a/verifier/trustpolicy/trustpolicy_test.go +++ b/verifier/trustpolicy/trustpolicy_test.go @@ -30,7 +30,7 @@ func dummyPolicyStatement() (policyStatement TrustPolicy) { policyStatement = TrustPolicy{ Name: "test-statement-name", RegistryScopes: []string{"registry.acme-rockets.io/software/net-monitor"}, - SignatureVerification: SignatureVerification{VerificationLevel: "strict"}, + SignatureVerification: SignatureVerification{VerificationLevel: "strict", VerifyTimestamp: "always"}, TrustStores: []string{"ca:valid-trust-store", "signingAuthority:valid-trust-store"}, TrustedIdentities: []string{"x509.subject:CN=Notation Test Root,O=Notary,L=Seattle,ST=WA,C=US"}, } @@ -54,26 +54,46 @@ func TestValidateValidPolicyDocument(t *testing.T) { policyStatement2 := dummyPolicyStatement() policyStatement2.Name = "test-statement-name-2" policyStatement2.RegistryScopes = []string{"registry.wabbit-networks.io/software/unsigned/net-utils"} - policyStatement2.SignatureVerification = SignatureVerification{VerificationLevel: "permissive"} + policyStatement2.SignatureVerification.VerificationLevel = "permissive" policyStatement3 := dummyPolicyStatement() policyStatement3.Name = "test-statement-name-3" policyStatement3.RegistryScopes = []string{"registry.acme-rockets.io/software/legacy/metrics"} policyStatement3.TrustStores = []string{} policyStatement3.TrustedIdentities = []string{} - policyStatement3.SignatureVerification = SignatureVerification{VerificationLevel: "skip"} + policyStatement3.SignatureVerification.VerificationLevel = "skip" policyStatement4 := dummyPolicyStatement() policyStatement4.Name = "test-statement-name-4" policyStatement4.TrustStores = []string{"ca:valid-trust-store", "signingAuthority:valid-trust-store-2"} policyStatement4.RegistryScopes = []string{"*"} - policyStatement4.SignatureVerification = SignatureVerification{VerificationLevel: "audit"} + policyStatement4.SignatureVerification.VerificationLevel = "audit" policyStatement5 := dummyPolicyStatement() policyStatement5.Name = "test-statement-name-5" policyStatement5.RegistryScopes = []string{"registry.acme-rockets2.io/software"} policyStatement5.TrustedIdentities = []string{"*"} - policyStatement5.SignatureVerification = SignatureVerification{VerificationLevel: "strict"} + policyStatement5.SignatureVerification.VerificationLevel = "strict" + + policyStatement6 := dummyPolicyStatement() + policyStatement6.Name = "test-statement-name-6" + policyStatement6.SignatureVerification.VerifyTimestamp = "" + + policyStatement7 := dummyPolicyStatement() + policyStatement7.Name = "test-statement-name-7" + policyStatement7.SignatureVerification.VerifyTimestamp = OptionAlways + + policyStatement8 := dummyPolicyStatement() + policyStatement8.Name = "test-statement-name-8" + policyStatement8.SignatureVerification.VerifyTimestamp = OptionAfterCertExpiry + + policyStatement9 := dummyPolicyStatement() + policyStatement9.Name = "test-statement-name-9" + policyStatement9.SignatureVerification.SkipTimestampRevocationCheck = true + + policyStatement10 := dummyPolicyStatement() + policyStatement10.Name = "test-statement-name-10" + policyStatement10.SignatureVerification.SkipTimestampRevocationCheck = false policyDoc.TrustPolicies = []TrustPolicy{ policyStatement1, @@ -81,6 +101,11 @@ func TestValidateValidPolicyDocument(t *testing.T) { policyStatement3, policyStatement4, policyStatement5, + policyStatement6, + policyStatement7, + policyStatement8, + policyStatement9, + policyStatement10, } err := policyDoc.Validate() if err != nil { @@ -288,7 +313,7 @@ func TestValidateInvalidPolicyDocument(t *testing.T) { policyDoc.TrustPolicies = []TrustPolicy{policyStatement} err = policyDoc.Validate() if err == nil || err.Error() != "trust policy statement \"test-statement-name\" has zero registry scopes, it must specify registry scopes with at least one value" { - t.Fatalf("policy statement with registry scopes should return error") + t.Fatalf("policy statement with registry scopes should return error, but got %s", err) } // Multiple policy statements with same registry scope @@ -322,6 +347,15 @@ func TestValidateInvalidPolicyDocument(t *testing.T) { t.Fatalf("policy statement with invalid SignatureVerification should return error") } + policyDoc = dummyPolicyDocument() + policyStatement = dummyPolicyStatement() + policyStatement.SignatureVerification.VerifyTimestamp = "invalid" + policyDoc.TrustPolicies = []TrustPolicy{policyStatement} + err = policyDoc.Validate() + if err == nil || err.Error() != "trust policy statement \"test-statement-name\" has invalid signatureVerification: verifyTimestamp must be \"always\" or \"afterCertExpiry\", but got \"invalid\"" { + t.Fatalf("policy statement with invalid SignatureVerification should return error, but got %s", err) + } + // strict SignatureVerification should have a trust store policyDoc = dummyPolicyDocument() policyStatement = dummyPolicyStatement() @@ -345,7 +379,7 @@ func TestValidateInvalidPolicyDocument(t *testing.T) { // skip SignatureVerification should not have trust store or trusted identities policyDoc = dummyPolicyDocument() policyStatement = dummyPolicyStatement() - policyStatement.SignatureVerification = SignatureVerification{VerificationLevel: "skip"} + policyStatement.SignatureVerification.VerificationLevel = "skip" policyDoc.TrustPolicies = []TrustPolicy{policyStatement} err = policyDoc.Validate() if err == nil || err.Error() != "trust policy statement \"test-statement-name\" is set to skip signature verification but configured with trust stores and/or trusted identities, remove them if signature verification needs to be skipped" { @@ -385,7 +419,7 @@ func TestValidateInvalidPolicyDocument(t *testing.T) { // trust store/trusted identites are optional for skip SignatureVerification policyDoc = dummyPolicyDocument() policyStatement = dummyPolicyStatement() - policyStatement.SignatureVerification = SignatureVerification{VerificationLevel: "skip"} + policyStatement.SignatureVerification.VerificationLevel = "skip" policyStatement.TrustStores = []string{} policyStatement.TrustedIdentities = []string{} err = policyDoc.Validate() @@ -467,7 +501,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) } } } @@ -517,7 +551,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) } } } @@ -570,6 +604,26 @@ func TestApplicableTrustPolicy(t *testing.T) { } func TestLoadDocument(t *testing.T) { + t.Run("valid policy file", func(t *testing.T) { + tempRoot := t.TempDir() + dir.UserConfigDir = tempRoot + path := filepath.Join(tempRoot, "trustpolicy.json") + policyDoc1 := dummyPolicyDocument() + policyDoc1.TrustPolicies[0].SignatureVerification.VerifyTimestamp = "" + policyJson, _ := json.Marshal(policyDoc1) + if err := os.WriteFile(path, policyJson, 0600); err != nil { + t.Fatalf("TestLoadPolicyDocument create valid policy file failed. Error: %v", err) + } + policyDoc, err := LoadDocument() + if err != nil { + t.Fatalf("TestLoadPolicyDocument should not throw error for an existing policy file. Error: %v", err) + } + for _, statement := range policyDoc.TrustPolicies { + if statement.SignatureVerification.VerifyTimestamp != OptionAlways { + t.Fatal("expecting to get default VerifyTimestamp value \"always\"") + } + } + }) t.Run("non-existing policy file", func(t *testing.T) { tempRoot := t.TempDir() @@ -591,20 +645,6 @@ func TestLoadDocument(t *testing.T) { } }) - t.Run("valid policy file", func(t *testing.T) { - tempRoot := t.TempDir() - dir.UserConfigDir = tempRoot - path := filepath.Join(tempRoot, "trustpolicy.json") - policyDoc1 := dummyPolicyDocument() - policyJson, _ := json.Marshal(policyDoc1) - if err := os.WriteFile(path, policyJson, 0600); err != nil { - t.Fatalf("TestLoadPolicyDocument create valid policy file failed. Error: %v", err) - } - if _, err := LoadDocument(); err != nil { - t.Fatalf("TestLoadPolicyDocument should not throw error for an existing policy file. Error: %v", err) - } - }) - t.Run("policy file with bad permissions", func(t *testing.T) { if runtime.GOOS == "windows" { t.Skip("skipping test on Windows") diff --git a/verifier/verifier.go b/verifier/verifier.go index bb7daba3..25644ec9 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -653,73 +653,39 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } logger.Info("TSA identity is: ", tsaCertChain[0].Subject) - // 4. Check authenticity of the TSA against trust store - // logger.Info("Checking TSA authenticity against the trust store...") - // trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, trustPolicy, x509TrustStore) - // if err != nil { - // return ¬ation.ValidationResult{ - // Error: fmt.Errorf("failed to load tsa trust store with error: %w", err), - // Type: trustpolicy.TypeAuthenticTimestamp, - // Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - // } - // } - // if len(trustTSACerts) < 1 { - // return ¬ation.ValidationResult{ - // Error: errors.New("no trusted TSA certificate found in trust store"), - // Type: trustpolicy.TypeAuthenticTimestamp, - // Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - // } - // } - // var foundTrustedCert bool - // for _, trust := range trustTSACerts { - // for _, cert := range tsaCertChain { - // if trust.Equal(cert) { - // foundTrustedCert = true - // break - // } - // } - // if foundTrustedCert { - // break - // } - // } - // if !foundTrustedCert { - // return ¬ation.ValidationResult{ - // Error: errors.New("failed to verify the timestamp countersignature with error: tsa certificate chain does not contain trusted certificate in trust store"), - // Type: trustpolicy.TypeAuthenticTimestamp, - // Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - // } - // } - // 5. Perform the timestamping certificate chain revocation check - logger.Info("Checking timestamping certificate chain revocation...") - timeStampLowerLimit = ts.Add(-accuracy) - timeStampUpperLimit = ts.Add(accuracy) - certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit, &http.Client{Timeout: 2 * time.Second}) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - 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 ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamping certificate with subject %q is revoked", problematicCertSubject), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + // 4. Perform the timestamping certificate chain revocation check + if !trustPolicy.SignatureVerification.SkipTimestampRevocationCheck { + logger.Info("Checking timestamping certificate chain revocation...") + timeStampLowerLimit = ts.Add(-accuracy) + timeStampUpperLimit = ts.Add(accuracy) + certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit, &http.Client{Timeout: 2 * time.Second}) + if err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } } - default: - // revocationresult.ResultUnknown - return ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamping certificate with subject %q revocation status is unknown", problematicCertSubject), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + 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 ¬ation.ValidationResult{ + Error: fmt.Errorf("timestamping certificate with subject %q is revoked", problematicCertSubject), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + default: + // revocationresult.ResultUnknown + return ¬ation.ValidationResult{ + Error: fmt.Errorf("timestamping certificate with subject %q revocation status is unknown", problematicCertSubject), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } } } - // 6. Check the timestamp against the signing certificate chain + // 5. Check the timestamp against the signing certificate chain logger.Info("Checking the timestamp against the signing certificate chain...") logger.Infof("Timestamp range: [%v, %v]", timeStampLowerLimit, timeStampUpperLimit) for _, cert := range signerInfo.CertificateChain { From 3a0de5f746e7733c38e2f279231cf18d05928995 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 25 Jun 2024 14:40:17 +0800 Subject: [PATCH 55/82] update timestamp Signed-off-by: Patrick Zheng --- go.mod | 4 ++-- go.sum | 8 ++++---- verifier/verifier.go | 16 +++++++++------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index da70be12..534f18e7 100644 --- a/go.mod +++ b/go.mod @@ -25,6 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240624084736-28b80547d251 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240625061446-64bf87aaf899 -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240624080215-1284fbf408ce +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240625051139-b86a837d928d diff --git a/go.sum b/go.sum index 39236fe1..86a23eac 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,9 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240624084736-28b80547d251 h1:DsSiFI1r5pxwqgpJq739UTW+r2HZWVhDfKzCGPAuC8E= -github.com/Two-Hearts/notation-core-go v0.0.0-20240624084736-28b80547d251/go.mod h1:ziEtD5U/wCeZNoRJo8JeRJxQgl0AxajLb+v/Hv8p5lM= -github.com/Two-Hearts/tspclient-go v0.0.0-20240624080215-1284fbf408ce h1:2AP1Rk5iOUQETSeBwst7ZzDsdHTEllMC46FfUBMUGr4= -github.com/Two-Hearts/tspclient-go v0.0.0-20240624080215-1284fbf408ce/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240625061446-64bf87aaf899 h1:l5T/KFTnK+UIlyGKUgLcp2Up5IXVO1iOuQSrjR5jTt0= +github.com/Two-Hearts/notation-core-go v0.0.0-20240625061446-64bf87aaf899/go.mod h1:DaE3dTbfW9bLOquUENRPwtAE8He+5Oz2lWy3oCpn4RE= +github.com/Two-Hearts/tspclient-go v0.0.0-20240625051139-b86a837d928d h1:PJ4BkFIkKpRYFtuJsE5oOaJt4LY5zf0Zjjd3UE/JhmM= +github.com/Two-Hearts/tspclient-go v0.0.0-20240625051139-b86a837d928d/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= diff --git a/verifier/verifier.go b/verifier/verifier.go index 25644ec9..5d6a9137 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -535,10 +535,12 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } if !tsaEnabled { + logger.Info("Timestamp verification disabled: no tsa trust store is configured in trust policy") performTimestampVerification = false } // check based on 'verifyTimestamp' field - if performTimestampVerification && trustPolicy.SignatureVerification.VerifyTimestamp == trustpolicy.OptionAfterCertExpiry { + if performTimestampVerification && + trustPolicy.SignatureVerification.VerifyTimestamp == trustpolicy.OptionAfterCertExpiry { // check if signing cert chain has expired var expired bool for _, cert := range signerInfo.CertificateChain { @@ -548,13 +550,13 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } if !expired { + logger.Info("Timestamp verification disabled: verifyTimestamp is set to \"afterCertExpiry\" and signing cert chain unexpired") performTimestampVerification = false } } - // not performing any timestamp verification, signing cert chain MUST - // be valid at time of verification + // timestamp verification disabled, signing cert chain MUST be valid + // at time of verification if !performTimestampVerification { - logger.Info("Timestamp verification disabled") for _, cert := range signerInfo.CertificateChain { if timeStampLowerLimit.Before(cert.NotBefore) { return ¬ation.ValidationResult{ @@ -571,7 +573,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } } - // this step is a success + // success return ¬ation.ValidationResult{ Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], @@ -658,7 +660,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus logger.Info("Checking timestamping certificate chain revocation...") timeStampLowerLimit = ts.Add(-accuracy) timeStampUpperLimit = ts.Add(accuracy) - certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit, &http.Client{Timeout: 2 * time.Second}) + certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit, &http.Client{Timeout: 5 * time.Second}) if err != nil { return ¬ation.ValidationResult{ Error: fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err), @@ -719,7 +721,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } - // this step is a success + // success return ¬ation.ValidationResult{ Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], From cfe3428b617356ce04f5d8264577d22b71ece4d3 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 25 Jun 2024 14:42:43 +0800 Subject: [PATCH 56/82] clean up Signed-off-by: Patrick Zheng --- signer/signer_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/signer/signer_test.go b/signer/signer_test.go index 31e16ca5..e6797a71 100644 --- a/signer/signer_test.go +++ b/signer/signer_test.go @@ -117,7 +117,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 +138,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) } @@ -269,7 +269,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 +289,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") } From 573f5929cda9ed472d1d39ac7d4cade676e160d2 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 25 Jun 2024 14:52:37 +0800 Subject: [PATCH 57/82] clean up Signed-off-by: Patrick Zheng --- verifier/trustpolicy/trustpolicy.go | 10 +++------- verifier/trustpolicy/trustpolicy_test.go | 11 ++--------- 2 files changed, 5 insertions(+), 16 deletions(-) diff --git a/verifier/trustpolicy/trustpolicy.go b/verifier/trustpolicy/trustpolicy.go index 370a4d13..885aaab2 100644 --- a/verifier/trustpolicy/trustpolicy.go +++ b/verifier/trustpolicy/trustpolicy.go @@ -220,7 +220,9 @@ func (policyDoc *Document) Validate() error { if err != nil { return fmt.Errorf("trust policy statement %q has invalid signatureVerification: %w", statement.Name, err) } - if statement.SignatureVerification.VerifyTimestamp != OptionAlways && statement.SignatureVerification.VerifyTimestamp != OptionAfterCertExpiry { + if statement.SignatureVerification.VerifyTimestamp != "" && + statement.SignatureVerification.VerifyTimestamp != OptionAlways && + statement.SignatureVerification.VerifyTimestamp != OptionAfterCertExpiry { return fmt.Errorf("trust policy statement %q has invalid signatureVerification: verifyTimestamp must be %q or %q, but got %q", statement.Name, OptionAlways, OptionAfterCertExpiry, statement.SignatureVerification.VerifyTimestamp) } @@ -332,12 +334,6 @@ func LoadDocument() (*Document, error) { if err != nil { return nil, fmt.Errorf("malformed trust policy. To create a trust policy, see: %s", trustPolicyLink) } - for idx, statement := range policyDocument.TrustPolicies { - if statement.SignatureVerification.VerifyTimestamp == "" { - // default value for VerifyTimestamp is "always" - policyDocument.TrustPolicies[idx].SignatureVerification.VerifyTimestamp = OptionAlways - } - } return policyDocument, nil } diff --git a/verifier/trustpolicy/trustpolicy_test.go b/verifier/trustpolicy/trustpolicy_test.go index aa73e606..09f80b22 100644 --- a/verifier/trustpolicy/trustpolicy_test.go +++ b/verifier/trustpolicy/trustpolicy_test.go @@ -30,7 +30,7 @@ func dummyPolicyStatement() (policyStatement TrustPolicy) { policyStatement = TrustPolicy{ Name: "test-statement-name", RegistryScopes: []string{"registry.acme-rockets.io/software/net-monitor"}, - SignatureVerification: SignatureVerification{VerificationLevel: "strict", VerifyTimestamp: "always"}, + SignatureVerification: SignatureVerification{VerificationLevel: "strict"}, TrustStores: []string{"ca:valid-trust-store", "signingAuthority:valid-trust-store"}, TrustedIdentities: []string{"x509.subject:CN=Notation Test Root,O=Notary,L=Seattle,ST=WA,C=US"}, } @@ -609,20 +609,13 @@ func TestLoadDocument(t *testing.T) { dir.UserConfigDir = tempRoot path := filepath.Join(tempRoot, "trustpolicy.json") policyDoc1 := dummyPolicyDocument() - policyDoc1.TrustPolicies[0].SignatureVerification.VerifyTimestamp = "" policyJson, _ := json.Marshal(policyDoc1) if err := os.WriteFile(path, policyJson, 0600); err != nil { t.Fatalf("TestLoadPolicyDocument create valid policy file failed. Error: %v", err) } - policyDoc, err := LoadDocument() - if err != nil { + if _, err := LoadDocument(); err != nil { t.Fatalf("TestLoadPolicyDocument should not throw error for an existing policy file. Error: %v", err) } - for _, statement := range policyDoc.TrustPolicies { - if statement.SignatureVerification.VerifyTimestamp != OptionAlways { - t.Fatal("expecting to get default VerifyTimestamp value \"always\"") - } - } }) t.Run("non-existing policy file", func(t *testing.T) { From 3ad12462ab2200c35469a68cbf7a896f824e230b Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 25 Jun 2024 14:58:22 +0800 Subject: [PATCH 58/82] fixed tests Signed-off-by: Patrick Zheng --- verifier/helpers_test.go | 2 +- verifier/trustpolicy/trustpolicy_test.go | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/verifier/helpers_test.go b/verifier/helpers_test.go index b50dac52..e732afd6 100644 --- a/verifier/helpers_test.go +++ b/verifier/helpers_test.go @@ -32,7 +32,7 @@ func dummyPolicyStatement() (policyStatement trustpolicy.TrustPolicy) { policyStatement = trustpolicy.TrustPolicy{ Name: "test-statement-name", RegistryScopes: []string{"registry.acme-rockets.io/software/net-monitor"}, - SignatureVerification: trustpolicy.SignatureVerification{VerificationLevel: "strict", VerifyTimestamp: "always"}, + SignatureVerification: trustpolicy.SignatureVerification{VerificationLevel: "strict"}, TrustStores: []string{"ca:valid-trust-store", "signingAuthority:valid-trust-store"}, TrustedIdentities: []string{"x509.subject:CN=Notation Test Root,O=Notary,L=Seattle,ST=WA,C=US"}, } diff --git a/verifier/trustpolicy/trustpolicy_test.go b/verifier/trustpolicy/trustpolicy_test.go index 09f80b22..729a7cd4 100644 --- a/verifier/trustpolicy/trustpolicy_test.go +++ b/verifier/trustpolicy/trustpolicy_test.go @@ -77,22 +77,27 @@ func TestValidateValidPolicyDocument(t *testing.T) { policyStatement6 := dummyPolicyStatement() policyStatement6.Name = "test-statement-name-6" + policyStatement6.RegistryScopes = []string{"registry.acme-rockets.io/software/net-monitor6"} policyStatement6.SignatureVerification.VerifyTimestamp = "" policyStatement7 := dummyPolicyStatement() policyStatement7.Name = "test-statement-name-7" + policyStatement7.RegistryScopes = []string{"registry.acme-rockets.io/software/net-monitor7"} policyStatement7.SignatureVerification.VerifyTimestamp = OptionAlways policyStatement8 := dummyPolicyStatement() policyStatement8.Name = "test-statement-name-8" + policyStatement8.RegistryScopes = []string{"registry.acme-rockets.io/software/net-monitor8"} policyStatement8.SignatureVerification.VerifyTimestamp = OptionAfterCertExpiry policyStatement9 := dummyPolicyStatement() policyStatement9.Name = "test-statement-name-9" + policyStatement9.RegistryScopes = []string{"registry.acme-rockets.io/software/net-monitor9"} policyStatement9.SignatureVerification.SkipTimestampRevocationCheck = true policyStatement10 := dummyPolicyStatement() policyStatement10.Name = "test-statement-name-10" + policyStatement10.RegistryScopes = []string{"registry.acme-rockets.io/software/net-monitor10"} policyStatement10.SignatureVerification.SkipTimestampRevocationCheck = false policyDoc.TrustPolicies = []TrustPolicy{ From ac78ce19b1a729ddc61f0a9d74d69e6bd81916ac Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 25 Jun 2024 15:20:06 +0800 Subject: [PATCH 59/82] update timestamp Signed-off-by: Patrick Zheng --- verifier/verifier.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 5d6a9137..e8b30527 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -655,11 +655,11 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } logger.Info("TSA identity is: ", tsaCertChain[0].Subject) + timeStampLowerLimit = ts.Add(-accuracy) + timeStampUpperLimit = ts.Add(accuracy) // 4. Perform the timestamping certificate chain revocation check if !trustPolicy.SignatureVerification.SkipTimestampRevocationCheck { logger.Info("Checking timestamping certificate chain revocation...") - timeStampLowerLimit = ts.Add(-accuracy) - timeStampUpperLimit = ts.Add(accuracy) certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit, &http.Client{Timeout: 5 * time.Second}) if err != nil { return ¬ation.ValidationResult{ From 925801f5ceb3a5845f4779ed4a0c1b91691ea965 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 25 Jun 2024 16:25:59 +0800 Subject: [PATCH 60/82] updated log Signed-off-by: Patrick Zheng --- verifier/verifier.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index e8b30527..9f40ea57 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -550,7 +550,7 @@ func verifyAuthenticTimestamp(ctx context.Context, trustPolicy *trustpolicy.Trus } } if !expired { - logger.Info("Timestamp verification disabled: verifyTimestamp is set to \"afterCertExpiry\" and signing cert chain unexpired") + logger.Infof("Timestamp verification disabled: verifyTimestamp is set to %q and signing cert chain unexpired", trustpolicy.OptionAfterCertExpiry) performTimestampVerification = false } } From c1621e267e61906ff63fb0aab728846d03501cc8 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 26 Jun 2024 18:22:06 +0800 Subject: [PATCH 61/82] added exmaple tests for timestamp Signed-off-by: Patrick Zheng --- example_localVerify_test.go | 6 +- example_remoteVerify_test.go | 10 +- example_signWithTimestmap_test.go | 124 ++++++++++++++++++ example_verifyWithTimestamp_test.go | 196 ++++++++++++++++++++++++++++ 4 files changed, 328 insertions(+), 8 deletions(-) create mode 100644 example_signWithTimestmap_test.go create mode 100644 example_verifyWithTimestamp_test.go 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..273ebdeb --- /dev/null +++ b/example_signWithTimestmap_test.go @@ -0,0 +1,124 @@ +// 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" +) + +// 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() { + // exampleRFC3161TSAServer is the URL of a valid example TSA server + var exampleRFC3161TSAServer = "http://timestamp.digicert.com" + + // exampleTSARootCertPem is the example TSA's root certificate + var exampleTSARootCertPem = `-----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-----` + + // 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) + + 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()) + } + + // exampleSignOptions is an example of notation.SignOptions. + exampleSignOptions := notation.SignOptions{ + SignerSignOptions: notation.SignerSignOptions{ + SignatureMediaType: exampleSignatureMediaType, + TSAServerURL: exampleRFC3161TSAServer, + TSARootCertificate: tsaRootCert, + }, + 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..43ddda4a --- /dev/null +++ b/example_verifyWithTimestamp_test.go @@ -0,0 +1,196 @@ +// 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. + // 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, + + // verify timestamp countersignature but skip timestamp + // certificate chain revocation check. + // Default: false + SkipTimestampRevocationCheck: true, + }, + + // `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) +} From f987d280470a54246e6d6244fb5714937f48e6ce Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 27 Jun 2024 08:57:22 +0800 Subject: [PATCH 62/82] test Signed-off-by: Patrick Zheng --- .github/workflows/build.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6e9b6765..5c9e8c00 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,6 +22,7 @@ on: branches: - main - release-* + - tsa jobs: build: From 12b393e3615320435b67679d5f9db69839d0d44d Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 27 Jun 2024 08:59:58 +0800 Subject: [PATCH 63/82] clean up Signed-off-by: Patrick Zheng --- .github/workflows/build.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5c9e8c00..6e9b6765 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -22,7 +22,6 @@ on: branches: - main - release-* - - tsa jobs: build: From 13006cec009a47505f795ec1f4b2ac5d16639f8a Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 27 Jun 2024 18:25:30 +0800 Subject: [PATCH 64/82] fix tests Signed-off-by: Patrick Zheng --- verifier/trustpolicy/oci_test.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/verifier/trustpolicy/oci_test.go b/verifier/trustpolicy/oci_test.go index 85a2f4bb..672b9ab2 100644 --- a/verifier/trustpolicy/oci_test.go +++ b/verifier/trustpolicy/oci_test.go @@ -178,9 +178,10 @@ func TestValidateInvalidPolicyDocument(t *testing.T) { // 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() != "trust policy statement \"test-statement-name\" has invalid signatureVerification: verifyTimestamp must be \"always\" or \"afterCertExpiry\", but got \"invalid\"" { - t.Fatalf("policy statement with invalid SignatureVerification should return error, but got %s", err) + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) } // strict SignatureVerification should have a trust store From 938762ed78bf8d8109bac289caea9965d47c15eb Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 1 Jul 2024 10:49:44 +0800 Subject: [PATCH 65/82] updated timestamping Signed-off-by: Patrick Zheng --- example_signWithTimestmap_test.go | 4 +- go.mod | 6 +- go.sum | 12 ++-- notation.go | 15 ++--- signer/signer.go | 12 ++-- verifier/timestamp_test.go | 45 ++++++++------- verifier/trustpolicy/trustpolicy_test.go | 6 ++ verifier/verifier.go | 70 ++++++++++++++---------- verifier/verifier_test.go | 14 +++-- 9 files changed, 109 insertions(+), 75 deletions(-) diff --git a/example_signWithTimestmap_test.go b/example_signWithTimestmap_test.go index 273ebdeb..5f3ee7b2 100644 --- a/example_signWithTimestmap_test.go +++ b/example_signWithTimestmap_test.go @@ -101,13 +101,15 @@ gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ 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, TSAServerURL: exampleRFC3161TSAServer, - TSARootCertificate: tsaRootCert, + TSARootCAs: tsaRootCAs, }, ArtifactReference: exampleArtifactReference, } diff --git a/go.mod b/go.mod index 701e5718..bda0a29e 100644 --- a/go.mod +++ b/go.mod @@ -17,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 @@ -25,4 +25,6 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240627051425-a24facd24315 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240628104035-de8a46ce468e + +replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240628085816-98b1c64c4172 diff --git a/go.sum b/go.sum index 580bc58a..5ca06941 100644 --- a/go.sum +++ b/go.sum @@ -1,14 +1,16 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240627051425-a24facd24315 h1:8wDwsk1Rcs+7dmFFlSNzmj2tgBmD0m/vjjVh6eaozcM= -github.com/Two-Hearts/notation-core-go v0.0.0-20240627051425-a24facd24315/go.mod h1:4b60hxCB4gB0q1K2QRxycj0TGhLvylSSR1RWCG0ilYs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240628104035-de8a46ce468e h1:yDGu0wnuX+3xSDLXeIPV751jaBaTjMjcpVz5NwTypm4= +github.com/Two-Hearts/notation-core-go v0.0.0-20240628104035-de8a46ce468e/go.mod h1:hXbhc81hiH9tQOZ4w5pI+Z83y8qhpXKbsLXHWA/74TE= +github.com/Two-Hearts/tspclient-go v0.0.0-20240628085816-98b1c64c4172 h1:ME+WMRNcucfmJ9Le8eCtdV1gR3Xc8ve6Ab/cPnN/z48= +github.com/Two-Hearts/tspclient-go v0.0.0-20240628085816-98b1c64c4172/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= 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= @@ -36,8 +38,6 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= 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.0.0-20240627050441-dcff9b7c23fe h1:1psX5fHzB0ZGshHkaGlERh0eBX4EapizcVyQwX+YydE= -github.com/notaryproject/tspclient-go v0.0.0-20240627050441-dcff9b7c23fe/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/notation.go b/notation.go index a5aa85b4..2bed4f1c 100644 --- a/notation.go +++ b/notation.go @@ -66,8 +66,8 @@ type SignerSignOptions struct { // TSAServerURL denotes the TSA server URL TSAServerURL string - // TSARootCertificate denotes the TSA trust anchor - TSARootCertificate *x509.Certificate + // TSARootCAs is the cert pool holding caller's TSA trust anchor + TSARootCAs *x509.CertPool } // Signer is a generic interface for signing an OCI artifact. @@ -91,11 +91,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/signer/signer.go b/signer/signer.go index 53ad03c5..5f117391 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -118,12 +118,12 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts ContentType: envelope.MediaTypePayloadV1, Content: payloadBytes, }, - Signer: s.signer, - SigningTime: time.Now(), - SigningScheme: signature.SigningSchemeX509, - SigningAgent: signingAgentId, - TSAServerURL: opts.TSAServerURL, - TSARootCertificate: opts.TSARootCertificate, + Signer: s.signer, + SigningTime: time.Now(), + SigningScheme: signature.SigningSchemeX509, + SigningAgent: signingAgentId, + TSAServerURL: opts.TSAServerURL, + TSARootCAs: opts.TSARootCAs, } // Add expiry only if ExpiryDuration is not zero diff --git a/verifier/timestamp_test.go b/verifier/timestamp_test.go index f0a717d6..288014de 100644 --- a/verifier/timestamp_test.go +++ b/verifier/timestamp_test.go @@ -16,9 +16,12 @@ 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" @@ -41,6 +44,10 @@ func TestAuthenticTimestamp(t *testing.T) { 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 { @@ -58,7 +65,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: jwsEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) } @@ -69,7 +76,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) } @@ -84,7 +91,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: jwsEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) } @@ -99,7 +106,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) } @@ -120,7 +127,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) } @@ -141,7 +148,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: jwsEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) @@ -167,7 +174,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) @@ -183,7 +190,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) @@ -204,7 +211,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) @@ -225,7 +232,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) @@ -247,7 +254,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) @@ -269,7 +276,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) @@ -291,7 +298,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) @@ -313,7 +320,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, dummyTrustStore{}, outcome) + 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) @@ -335,7 +342,7 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: coseEnvContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) + 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) @@ -361,8 +368,8 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) - expectedErrMsg := "timestamp lower limit \"Wed, 19 Jun 2024 09:30:13 +0000\" is 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\"" + 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) } @@ -387,8 +394,8 @@ func TestAuthenticTimestamp(t *testing.T) { EnvelopeContent: envContent, VerificationLevel: trustpolicy.LevelStrict, } - authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, outcome) - expectedErrMsg := "timestamp upper limit \"Wed, 19 Jun 2024 09:35:59 +0000\" is 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\"" + 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) } diff --git a/verifier/trustpolicy/trustpolicy_test.go b/verifier/trustpolicy/trustpolicy_test.go index 5cf37a28..f58cadcc 100644 --- a/verifier/trustpolicy/trustpolicy_test.go +++ b/verifier/trustpolicy/trustpolicy_test.go @@ -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/verifier.go b/verifier/verifier.go index e4af3682..ece9e396 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -58,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 @@ -124,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: 5 * time.Second}) + if err != nil { + return nil, err + } + } + if trustStore == nil { return nil, errors.New("trustStore cannot be nil") } @@ -145,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 @@ -447,7 +461,7 @@ func (v *verifier) processSignature(ctx context.Context, sigBlob []byte, envelop // verify authentic timestamp logger.Debug("Validating authentic timestamp") - authenticTimestampResult := verifyAuthenticTimestamp(ctx, policyName, trustStores, signatureVerification, v.trustStore, outcome) + authenticTimestampResult := verifyAuthenticTimestamp(ctx, policyName, trustStores, signatureVerification, v.trustStore, v.revocationTimestampClient, outcome) outcome.VerificationResults = append(outcome.VerificationResults, authenticTimestampResult) logVerificationResult(logger, authenticTimestampResult) if isCriticalFailure(authenticTimestampResult) { @@ -664,15 +678,13 @@ func verifyExpiry(outcome *notation.VerificationOutcome) *notation.ValidationRes } } -func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStores []string, signatureVerification trustpolicy.SignatureVerification, x509TrustStore truststore.X509TrustStore, outcome *notation.VerificationOutcome) *notation.ValidationResult { +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) // under signing scheme notary.x509 if signerInfo := outcome.EnvelopeContent.SignerInfo; signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { logger.Info("Under signing scheme notary.x509...") performTimestampVerification := true - timeStampLowerLimit := time.Now() - timeStampUpperLimit := timeStampLowerLimit // check if tsa trust store is configured in trust policy tsaEnabled, err := isTSATrustStoreInPolicy(policyName, trustStores) if err != nil { @@ -705,15 +717,17 @@ func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStore // timestamp verification disabled, signing cert chain MUST be valid // at time of verification if !performTimestampVerification { + timestampLowerLimit := time.Now() + timestampUpperLimit := timestampLowerLimit for _, cert := range signerInfo.CertificateChain { - if timeStampLowerLimit.Before(cert.NotBefore) { + if timestampLowerLimit.Before(cert.NotBefore) { return ¬ation.ValidationResult{ Error: fmt.Errorf("verification time is before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - if timeStampUpperLimit.After(cert.NotAfter) { + if timestampUpperLimit.After(cert.NotAfter) { return ¬ation.ValidationResult{ Error: fmt.Errorf("verification time is after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.Format(time.RFC1123Z)), Type: trustpolicy.TypeAuthenticTimestamp, @@ -774,7 +788,7 @@ func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStore for _, trustedCerts := range trustTSACerts { rootCertPool.AddCert(trustedCerts) } - ts, accuracy, err := info.Validate(signerInfo.Signature) + timestamp, err := info.Validate(signerInfo.Signature) if err != nil { return ¬ation.ValidationResult{ Error: fmt.Errorf("failed to get timestamp from timestamp countersignature with error: %w", err), @@ -783,7 +797,7 @@ func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStore } } tsaCertChain, err := signedToken.Verify(ctx, x509.VerifyOptions{ - CurrentTime: ts, + CurrentTime: timestamp.Value, Roots: rootCertPool, }) if err != nil { @@ -795,7 +809,7 @@ func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStore } // 3. Validate timestamping certificate chain logger.Info("Validating timestamping certificate chain...") - if err := nx509.ValidateTimeStampingCertChain(tsaCertChain, nil); err != nil { + if err := nx509.ValidateTimestampingCertChain(tsaCertChain, nil); err != nil { return ¬ation.ValidationResult{ Error: fmt.Errorf("failed to validate the timestamping certificate chain with error: %w", err), Type: trustpolicy.TypeAuthenticTimestamp, @@ -803,12 +817,10 @@ func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStore } } logger.Info("TSA identity is: ", tsaCertChain[0].Subject) - timeStampLowerLimit = ts.Add(-accuracy) - timeStampUpperLimit = ts.Add(accuracy) // 4. Perform the timestamping certificate chain revocation check if !signatureVerification.SkipTimestampRevocationCheck { logger.Info("Checking timestamping certificate chain revocation...") - certResults, err := revocation.ValidateTimestampCertChain(tsaCertChain, timeStampUpperLimit, &http.Client{Timeout: 5 * time.Second}) + certResults, err := r.Validate(tsaCertChain, timestamp.Value) if err != nil { return ¬ation.ValidationResult{ Error: fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err), @@ -837,18 +849,18 @@ func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStore } // 5. Check the timestamp against the signing certificate chain logger.Info("Checking the timestamp against the signing certificate chain...") - logger.Infof("Timestamp range: [%v, %v]", timeStampLowerLimit, timeStampUpperLimit) + logger.Infof("Timestamp range: [%v, %v]", timestamp.Value.Add(-timestamp.Accuracy), timestamp.Value.Add(timestamp.Accuracy)) for _, cert := range signerInfo.CertificateChain { - if timeStampLowerLimit.Before(cert.NotBefore) { + if !timestamp.BoundedAfter(cert.NotBefore) { return ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamp lower limit %q is before certificate %q validity period, it will be valid from %q", timeStampLowerLimit.Format(time.RFC1123Z), cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), + Error: fmt.Errorf("timestamp can be before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } - if timeStampUpperLimit.After(cert.NotAfter) { + if !timestamp.BoundedBefore(cert.NotAfter) { return ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamp upper limit %q is after certificate %q validity period, it was expired at %q", timeStampUpperLimit.Format(time.RFC1123Z), cert.Subject, cert.NotAfter.Format(time.RFC1123Z)), + Error: fmt.Errorf("timestamp can be after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.Format(time.RFC1123Z)), Type: trustpolicy.TypeAuthenticTimestamp, Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } 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)) From d94d7b32eb2ec758dc62e812761542a68df814e4 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 3 Jul 2024 14:11:59 +0800 Subject: [PATCH 66/82] added more tests Signed-off-by: Patrick Zheng --- config/base_test.go | 4 +++ example_signWithTimestmap_test.go | 7 ++++- go.mod | 6 ++-- go.sum | 8 +++--- internal/mock/ocilayout/ocilayout_test.go | 6 +++- notation.go | 5 ++-- registry/repository_test.go | 4 +++ signer/signer.go | 6 ++-- signer/signer_test.go | 32 ++++++++++++++++++++-- signer/testdata/DigiCertTSARootSHA384.cer | Bin 0 -> 1428 bytes verifier/verifier.go | 2 +- 11 files changed, 63 insertions(+), 17 deletions(-) create mode 100644 signer/testdata/DigiCertTSARootSHA384.cer 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_signWithTimestmap_test.go b/example_signWithTimestmap_test.go index 5f3ee7b2..5be401a6 100644 --- a/example_signWithTimestmap_test.go +++ b/example_signWithTimestmap_test.go @@ -25,6 +25,7 @@ import ( "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 @@ -105,10 +106,14 @@ gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ tsaRootCAs.AddCert(tsaRootCert) // exampleSignOptions is an example of notation.SignOptions. + httpTimestamper, err := tspclient.NewHTTPTimestamper(nil, exampleRFC3161TSAServer) + if err != nil { + panic(err) // Handle error + } exampleSignOptions := notation.SignOptions{ SignerSignOptions: notation.SignerSignOptions{ SignatureMediaType: exampleSignatureMediaType, - TSAServerURL: exampleRFC3161TSAServer, + Timestamper: httpTimestamper, TSARootCAs: tsaRootCAs, }, ArtifactReference: exampleArtifactReference, diff --git a/go.mod b/go.mod index bda0a29e..60792761 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/go-ldap/ldap/v3 v3.4.8 github.com/notaryproject/notation-core-go v1.0.3 github.com/notaryproject/notation-plugin-framework-go v1.0.0 - github.com/notaryproject/tspclient-go v0.0.0-20240627050441-dcff9b7c23fe + github.com/notaryproject/tspclient-go v0.0.0-20240702050734-d91848411058 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/veraison/go-cose v1.1.0 @@ -25,6 +25,4 @@ require ( golang.org/x/sync v0.6.0 // indirect ) -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240628104035-de8a46ce468e - -replace github.com/notaryproject/tspclient-go => github.com/Two-Hearts/tspclient-go v0.0.0-20240628085816-98b1c64c4172 +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240703022152-7f0c50591e18 diff --git a/go.sum b/go.sum index 5ca06941..4a361236 100644 --- a/go.sum +++ b/go.sum @@ -1,9 +1,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240628104035-de8a46ce468e h1:yDGu0wnuX+3xSDLXeIPV751jaBaTjMjcpVz5NwTypm4= -github.com/Two-Hearts/notation-core-go v0.0.0-20240628104035-de8a46ce468e/go.mod h1:hXbhc81hiH9tQOZ4w5pI+Z83y8qhpXKbsLXHWA/74TE= -github.com/Two-Hearts/tspclient-go v0.0.0-20240628085816-98b1c64c4172 h1:ME+WMRNcucfmJ9Le8eCtdV1gR3Xc8ve6Ab/cPnN/z48= -github.com/Two-Hearts/tspclient-go v0.0.0-20240628085816-98b1c64c4172/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/Two-Hearts/notation-core-go v0.0.0-20240703022152-7f0c50591e18 h1:lYX4Y5ZkbWbsAJkdMCSfg0Nc3lxsKWmOaHtnKejoIMY= +github.com/Two-Hearts/notation-core-go v0.0.0-20240703022152-7f0c50591e18/go.mod h1:6DN+zUYRhXx7swFMVSrai5J+7jqyuOCru1q9G+SbFno= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -38,6 +36,8 @@ github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZ github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= 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.0.0-20240702050734-d91848411058 h1:FlGmQAwbf78rw12fXT4+9EkmD9+ZWuqH08v0fE3sqHc= +github.com/notaryproject/tspclient-go v0.0.0-20240702050734-d91848411058/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 2bed4f1c..fcad813c 100644 --- a/notation.go +++ b/notation.go @@ -38,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" ) @@ -63,8 +64,8 @@ type SignerSignOptions struct { // SigningAgent sets the signing agent name SigningAgent string - // TSAServerURL denotes the TSA server URL - TSAServerURL 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 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 5f117391..eea87651 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -122,7 +122,7 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts SigningTime: time.Now(), SigningScheme: signature.SigningSchemeX509, SigningAgent: signingAgentId, - TSAServerURL: opts.TSAServerURL, + Timestamper: opts.Timestamper, TSARootCAs: opts.TSARootCAs, } @@ -137,7 +137,9 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts logger.Debugf(" Expiry: %v", signReq.Expiry) logger.Debugf(" SigningScheme: %v", signReq.SigningScheme) logger.Debugf(" SigningAgent: %v", signReq.SigningAgent) - logger.Debugf(" TSAServerURL: %v", signReq.TSAServerURL) + + // Add ctx to the SignRequest + signReq = signReq.WithContext(ctx) // perform signing sigEnv, err := signature.NewEnvelope(opts.SignatureMediaType) diff --git a/signer/signer_test.go b/signer/signer_test.go index e6797a71..ebfe8a0c 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 @@ -208,7 +212,18 @@ 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) }) } } @@ -354,7 +369,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 +378,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/verifier.go b/verifier/verifier.go index ece9e396..6ef4ab27 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -809,7 +809,7 @@ func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStore } // 3. Validate timestamping certificate chain logger.Info("Validating timestamping certificate chain...") - if err := nx509.ValidateTimestampingCertChain(tsaCertChain, nil); err != nil { + if err := nx509.ValidateTimestampingCertChain(tsaCertChain); err != nil { return ¬ation.ValidationResult{ Error: fmt.Errorf("failed to validate the timestamping certificate chain with error: %w", err), Type: trustpolicy.TypeAuthenticTimestamp, From 5aeef6851f90d0a93e61e877585aabdd3bf4782a Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 3 Jul 2024 14:13:59 +0800 Subject: [PATCH 67/82] fixed build Signed-off-by: Patrick Zheng --- .github/workflows/build.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6e9b6765..8b6e5c5e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -26,3 +26,5 @@ on: jobs: build: uses: notaryproject/notation-core-go/.github/workflows/reusable-build.yml@main + secrets: + CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} From eb3eb887960dbe7e382e39c262e8df0074925320 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 8 Jul 2024 13:33:10 +0800 Subject: [PATCH 68/82] updated per code review Signed-off-by: Patrick Zheng --- example_signWithTimestmap_test.go | 50 ++----- example_verifyWithTimestamp_test.go | 3 +- go.mod | 4 +- go.sum | 4 +- verifier/helpers.go | 199 +++++++++++++++++++++++++++ verifier/verifier.go | 205 ++-------------------------- 6 files changed, 224 insertions(+), 241 deletions(-) diff --git a/example_signWithTimestmap_test.go b/example_signWithTimestmap_test.go index 5be401a6..8e0ebe5c 100644 --- a/example_signWithTimestmap_test.go +++ b/example_signWithTimestmap_test.go @@ -32,43 +32,6 @@ import ( // artifact with a RFC 3161 compliant timestamp countersignature and // user trusted TSA root certificate func Example_signWithTimestamp() { - // exampleRFC3161TSAServer is the URL of a valid example TSA server - var exampleRFC3161TSAServer = "http://timestamp.digicert.com" - - // exampleTSARootCertPem is the example TSA's root certificate - var exampleTSARootCertPem = `-----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-----` - // exampleArtifactReference is an example of the target artifact reference var exampleArtifactReference = "localhost:5000/software@sha256:60043cf45eaebc4c0867fea485a039b598f52fd09fd5b07b0b2d2f88fad9d74e" @@ -94,6 +57,15 @@ gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ } 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") @@ -106,10 +78,6 @@ gKDWHrO8Dw9TdSmq6hN35N6MgSGtBxBHEa2HPQfRdbzP82Z+ tsaRootCAs.AddCert(tsaRootCert) // exampleSignOptions is an example of notation.SignOptions. - httpTimestamper, err := tspclient.NewHTTPTimestamper(nil, exampleRFC3161TSAServer) - if err != nil { - panic(err) // Handle error - } exampleSignOptions := notation.SignOptions{ SignerSignOptions: notation.SignerSignOptions{ SignatureMediaType: exampleSignatureMediaType, diff --git a/example_verifyWithTimestamp_test.go b/example_verifyWithTimestamp_test.go index 43ddda4a..95af4856 100644 --- a/example_verifyWithTimestamp_test.go +++ b/example_verifyWithTimestamp_test.go @@ -35,7 +35,8 @@ 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. + // 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{ diff --git a/go.mod b/go.mod index 60792761..5fb9c738 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ 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.0.0-20240702050734-d91848411058 github.com/opencontainers/go-digest v1.0.0 @@ -24,5 +24,3 @@ require ( github.com/x448/float16 v0.8.4 // indirect golang.org/x/sync v0.6.0 // indirect ) - -replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20240703022152-7f0c50591e18 diff --git a/go.sum b/go.sum index 4a361236..5548eb90 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,5 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+s7s0MwaRv9igoPqLRdzOLzw/8Xvq8= github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= -github.com/Two-Hearts/notation-core-go v0.0.0-20240703022152-7f0c50591e18 h1:lYX4Y5ZkbWbsAJkdMCSfg0Nc3lxsKWmOaHtnKejoIMY= -github.com/Two-Hearts/notation-core-go v0.0.0-20240703022152-7f0c50591e18/go.mod h1:6DN+zUYRhXx7swFMVSrai5J+7jqyuOCru1q9G+SbFno= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa h1:LHTHcTQiSGT7VVbI0o4wBRNQIgn917usHWOd6VAffYI= github.com/alexbrainman/sspi v0.0.0-20231016080023-1a75b4708caa/go.mod h1:cEWa1LVoE5KvSD9ONXsZrj0z6KqySlCCNKHlLzbqAt4= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= @@ -34,6 +32,8 @@ 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.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.0.0-20240702050734-d91848411058 h1:FlGmQAwbf78rw12fXT4+9EkmD9+ZWuqH08v0fE3sqHc= diff --git a/verifier/helpers.go b/verifier/helpers.go index f1835f8d..7294dbc4 100644 --- a/verifier/helpers.go +++ b/verifier/helpers.go @@ -19,14 +19,20 @@ import ( "errors" "fmt" "strings" + "time" + "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" set "github.com/notaryproject/notation-go/internal/container" notationsemver "github.com/notaryproject/notation-go/internal/semver" "github.com/notaryproject/notation-go/internal/slices" + "github.com/notaryproject/notation-go/log" "github.com/notaryproject/notation-go/verifier/trustpolicy" "github.com/notaryproject/notation-go/verifier/truststore" + "github.com/notaryproject/tspclient-go" ) const ( @@ -183,3 +189,196 @@ func isTSATrustStoreInPolicy(policyName string, trustStores []string) (bool, err } return false, nil } + +func verifyTimestamp(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) + + 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 ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to check tsa trust store configuration in turst policy with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + if !tsaEnabled { + logger.Info("Timestamp verification disabled: no tsa trust store is configured in trust policy") + performTimestampVerification = false + } + // check based on 'verifyTimestamp' field + if performTimestampVerification && + signatureVerification.VerifyTimestamp == trustpolicy.OptionAfterCertExpiry { + // check if signing cert chain has expired + var expired bool + for _, cert := range signerInfo.CertificateChain { + if time.Now().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 { + timeOfVerification := time.Now() + for _, cert := range signerInfo.CertificateChain { + if timeOfVerification.Before(cert.NotBefore) { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("verification time is before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + if timeOfVerification.After(cert.NotAfter) { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("verification time is after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.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], + } + } + // Performing timestamp verification + // 1. Timestamp countersignature MUST be present + logger.Info("Checking timestamp countersignature existence...") + if len(signerInfo.UnsignedAttributes.TimestampSignature) == 0 { + return ¬ation.ValidationResult{ + Error: errors.New("no timestamp countersignature was found in the signature envelope"), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + // 2. Verify the timestamp countersignature + logger.Info("Verifying the timestamp countersignature...") + signedToken, err := tspclient.ParseSignedToken(signerInfo.UnsignedAttributes.TimestampSignature) + if err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to parse timestamp countersignature with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + info, err := signedToken.Info() + if err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to get the timestamp TSTInfo with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, policyName, trustStores, x509TrustStore) + if err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to load tsa trust store with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + if len(trustTSACerts) == 0 { + return ¬ation.ValidationResult{ + Error: errors.New("no trusted TSA certificate found in trust store"), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + rootCertPool := x509.NewCertPool() + for _, trustedCerts := range trustTSACerts { + rootCertPool.AddCert(trustedCerts) + } + timestamp, err := info.Validate(signerInfo.Signature) + if err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to get timestamp from timestamp countersignature with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + tsaCertChain, err := signedToken.Verify(ctx, x509.VerifyOptions{ + CurrentTime: timestamp.Value, + Roots: rootCertPool, + }) + if err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to verify the timestamp countersignature with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + // 3. Validate timestamping certificate chain + logger.Info("Validating timestamping certificate chain...") + if err := nx509.ValidateTimestampingCertChain(tsaCertChain); err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to validate the timestamping certificate chain with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + logger.Info("TSA identity is: ", tsaCertChain[0].Subject) + // 4. Perform the timestamping certificate chain revocation check + if !signatureVerification.SkipTimestampRevocationCheck { + logger.Info("Checking timestamping certificate chain revocation...") + certResults, err := r.Validate(tsaCertChain, timestamp.Value) + if err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + 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 ¬ation.ValidationResult{ + Error: fmt.Errorf("timestamping certificate with subject %q is revoked", problematicCertSubject), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + default: + // revocationresult.ResultUnknown + return ¬ation.ValidationResult{ + Error: fmt.Errorf("timestamping certificate with subject %q revocation status is unknown", problematicCertSubject), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + } + // 5. Check the timestamp against the signing certificate chain + logger.Info("Checking the timestamp against the signing certificate chain...") + logger.Infof("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 ¬ation.ValidationResult{ + Error: fmt.Errorf("timestamp can be before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + } + if !timestamp.BoundedBefore(cert.NotAfter) { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("timestamp can be after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.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], + } +} diff --git a/verifier/verifier.go b/verifier/verifier.go index 6ef4ab27..169bd743 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -32,7 +32,6 @@ 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" @@ -45,7 +44,6 @@ 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" ) @@ -681,206 +679,25 @@ func verifyExpiry(outcome *notation.VerificationOutcome) *notation.ValidationRes 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) + signerInfo := outcome.EnvelopeContent.SignerInfo // under signing scheme notary.x509 - if signerInfo := outcome.EnvelopeContent.SignerInfo; signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { + if signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { logger.Info("Under signing scheme notary.x509...") - performTimestampVerification := true - // check if tsa trust store is configured in trust policy - tsaEnabled, err := isTSATrustStoreInPolicy(policyName, trustStores) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to check tsa trust store configuration in turst policy with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - if !tsaEnabled { - logger.Info("Timestamp verification disabled: no tsa trust store is configured in trust policy") - performTimestampVerification = false - } - // check based on 'verifyTimestamp' field - if performTimestampVerification && - signatureVerification.VerifyTimestamp == trustpolicy.OptionAfterCertExpiry { - // check if signing cert chain has expired - var expired bool - for _, cert := range signerInfo.CertificateChain { - if time.Now().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 { - timestampLowerLimit := time.Now() - timestampUpperLimit := timestampLowerLimit - for _, cert := range signerInfo.CertificateChain { - if timestampLowerLimit.Before(cert.NotBefore) { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("verification time is before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - if timestampUpperLimit.After(cert.NotAfter) { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("verification time is after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.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], - } - } - // Performing timestamp verification - // 1. Timestamp countersignature MUST be present - logger.Info("Checking timestamp countersignature existence...") - if len(signerInfo.UnsignedAttributes.TimestampSignature) == 0 { - return ¬ation.ValidationResult{ - Error: errors.New("no timestamp countersignature was found in the signature envelope"), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - // 2. Verify the timestamp countersignature - logger.Info("Verifying the timestamp countersignature...") - signedToken, err := tspclient.ParseSignedToken(signerInfo.UnsignedAttributes.TimestampSignature) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to parse timestamp countersignature with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - info, err := signedToken.Info() - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to get the timestamp TSTInfo with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, policyName, trustStores, x509TrustStore) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to load tsa trust store with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - if len(trustTSACerts) < 1 { - return ¬ation.ValidationResult{ - Error: errors.New("no trusted TSA certificate found in trust store"), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - rootCertPool := x509.NewCertPool() - for _, trustedCerts := range trustTSACerts { - rootCertPool.AddCert(trustedCerts) - } - timestamp, err := info.Validate(signerInfo.Signature) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to get timestamp from timestamp countersignature with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - tsaCertChain, err := signedToken.Verify(ctx, x509.VerifyOptions{ - CurrentTime: timestamp.Value, - Roots: rootCertPool, - }) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to verify the timestamp countersignature with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - // 3. Validate timestamping certificate chain - logger.Info("Validating timestamping certificate chain...") - if err := nx509.ValidateTimestampingCertChain(tsaCertChain); err != nil { + return verifyTimestamp(ctx, policyName, trustStores, signatureVerification, x509TrustStore, r, outcome) + } + + // under signing scheme notary.x509.signingAuthority + logger.Info("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("failed to validate the timestamping certificate chain with error: %w", err), + 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], } } - logger.Info("TSA identity is: ", tsaCertChain[0].Subject) - // 4. Perform the timestamping certificate chain revocation check - if !signatureVerification.SkipTimestampRevocationCheck { - logger.Info("Checking timestamping certificate chain revocation...") - certResults, err := r.Validate(tsaCertChain, timestamp.Value) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - 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 ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamping certificate with subject %q is revoked", problematicCertSubject), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - default: - // revocationresult.ResultUnknown - return ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamping certificate with subject %q revocation status is unknown", problematicCertSubject), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - } - // 5. Check the timestamp against the signing certificate chain - logger.Info("Checking the timestamp against the signing certificate chain...") - logger.Infof("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 ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamp can be before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - if !timestamp.BoundedBefore(cert.NotAfter) { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamp can be after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.Format(time.RFC1123Z)), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - } - } else if signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509SigningAuthority { - // under signing scheme notary.x509.signingAuthority - logger.Info("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, From 78999aaba7184167cc22f09586269045a3313b94 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 8 Jul 2024 13:39:58 +0800 Subject: [PATCH 69/82] updated per code review Signed-off-by: Patrick Zheng --- verifier/helpers.go | 2 ++ 1 file changed, 2 insertions(+) diff --git a/verifier/helpers.go b/verifier/helpers.go index 7294dbc4..752a666d 100644 --- a/verifier/helpers.go +++ b/verifier/helpers.go @@ -190,6 +190,8 @@ func isTSATrustStoreInPolicy(policyName string, trustStores []string) (bool, err return false, nil } +// 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) *notation.ValidationResult { logger := log.GetLogger(ctx) From 1235960e1938676a6ad1e0fe8979bd6c2ae6d834 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 9 Jul 2024 09:40:26 +0800 Subject: [PATCH 70/82] update Signed-off-by: Patrick Zheng --- example_verifyWithTimestamp_test.go | 5 --- verifier/helpers.go | 51 ++++++++++++++--------------- verifier/trustpolicy/oci_test.go | 12 ------- verifier/trustpolicy/trustpolicy.go | 7 ++-- 4 files changed, 27 insertions(+), 48 deletions(-) diff --git a/example_verifyWithTimestamp_test.go b/example_verifyWithTimestamp_test.go index 95af4856..56c21d59 100644 --- a/example_verifyWithTimestamp_test.go +++ b/example_verifyWithTimestamp_test.go @@ -52,11 +52,6 @@ func Example_verifyWithTimestamp() { // certificate chain has expired. // Default: trustpolicy.OptionAlways VerifyTimestamp: trustpolicy.OptionAfterCertExpiry, - - // verify timestamp countersignature but skip timestamp - // certificate chain revocation check. - // Default: false - SkipTimestampRevocationCheck: true, }, // `tsa` trust store type MUST be configured to enable diff --git a/verifier/helpers.go b/verifier/helpers.go index 752a666d..00f94db9 100644 --- a/verifier/helpers.go +++ b/verifier/helpers.go @@ -329,33 +329,31 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin } logger.Info("TSA identity is: ", tsaCertChain[0].Subject) // 4. Perform the timestamping certificate chain revocation check - if !signatureVerification.SkipTimestampRevocationCheck { - logger.Info("Checking timestamping certificate chain revocation...") - certResults, err := r.Validate(tsaCertChain, timestamp.Value) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } + logger.Info("Checking timestamping certificate chain revocation...") + certResults, err := r.Validate(tsaCertChain, timestamp.Value) + if err != nil { + return ¬ation.ValidationResult{ + Error: fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } - 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 ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamping certificate with subject %q is revoked", problematicCertSubject), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - default: - // revocationresult.ResultUnknown - return ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamping certificate with subject %q revocation status is unknown", problematicCertSubject), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } + } + 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 ¬ation.ValidationResult{ + Error: fmt.Errorf("timestamping certificate with subject %q is revoked", problematicCertSubject), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } + default: + // revocationresult.ResultUnknown + return ¬ation.ValidationResult{ + Error: fmt.Errorf("timestamping certificate with subject %q revocation status is unknown", problematicCertSubject), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], } } // 5. Check the timestamp against the signing certificate chain @@ -377,7 +375,6 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin } } } - // success return ¬ation.ValidationResult{ Type: trustpolicy.TypeAuthenticTimestamp, diff --git a/verifier/trustpolicy/oci_test.go b/verifier/trustpolicy/oci_test.go index 672b9ab2..e0d6beb5 100644 --- a/verifier/trustpolicy/oci_test.go +++ b/verifier/trustpolicy/oci_test.go @@ -376,16 +376,6 @@ func TestValidateValidPolicyDocument(t *testing.T) { policyStatement8.RegistryScopes = []string{"registry.acme-rockets.io/software/net-monitor8"} policyStatement8.SignatureVerification.VerifyTimestamp = OptionAfterCertExpiry - policyStatement9 := policyStatement1.clone() - policyStatement9.Name = "test-statement-name-9" - policyStatement9.RegistryScopes = []string{"registry.acme-rockets.io/software/net-monitor9"} - policyStatement9.SignatureVerification.SkipTimestampRevocationCheck = true - - policyStatement10 := policyStatement1.clone() - policyStatement10.Name = "test-statement-name-10" - policyStatement10.RegistryScopes = []string{"registry.acme-rockets.io/software/net-monitor10"} - policyStatement10.SignatureVerification.SkipTimestampRevocationCheck = false - policyDoc.TrustPolicies = []OCITrustPolicy{ *policyStatement1, *policyStatement2, @@ -395,8 +385,6 @@ func TestValidateValidPolicyDocument(t *testing.T) { *policyStatement6, *policyStatement7, *policyStatement8, - *policyStatement9, - *policyStatement10, } err := policyDoc.Validate() diff --git a/verifier/trustpolicy/trustpolicy.go b/verifier/trustpolicy/trustpolicy.go index 8c23e0a0..cbab4275 100644 --- a/verifier/trustpolicy/trustpolicy.go +++ b/verifier/trustpolicy/trustpolicy.go @@ -147,10 +147,9 @@ var ( // SignatureVerification represents verification configuration in a trust policy type SignatureVerification struct { - VerificationLevel string `json:"level"` - Override map[ValidationType]ValidationAction `json:"override,omitempty"` - VerifyTimestamp TimestampOption `json:"verifyTimestamp,omitempty"` - SkipTimestampRevocationCheck bool `json:"skipTimestampRevocationCheck,omitempty"` + VerificationLevel string `json:"level"` + Override map[ValidationType]ValidationAction `json:"override,omitempty"` + VerifyTimestamp TimestampOption `json:"verifyTimestamp,omitempty"` } type errPolicyNotExist struct{} From 830b2bdb4ac4a1c26e49f7b207bf8bb37b83c7d6 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Wed, 10 Jul 2024 16:44:53 +0800 Subject: [PATCH 71/82] updated to tspclient-go v0.1.0 Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 5fb9c738..95996fd9 100644 --- a/go.mod +++ b/go.mod @@ -6,7 +6,7 @@ require ( github.com/go-ldap/ldap/v3 v3.4.8 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.0.0-20240702050734-d91848411058 + 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 diff --git a/go.sum b/go.sum index 5548eb90..577b3197 100644 --- a/go.sum +++ b/go.sum @@ -36,8 +36,8 @@ github.com/notaryproject/notation-core-go v1.0.4-0.20240708015912-faac9b7f3f10 h 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.0.0-20240702050734-d91848411058 h1:FlGmQAwbf78rw12fXT4+9EkmD9+ZWuqH08v0fE3sqHc= -github.com/notaryproject/tspclient-go v0.0.0-20240702050734-d91848411058/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +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= From d8498e52d53ac5fbfebc6bbaf1f068e99d2ac8e5 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 11 Jul 2024 10:14:09 +0800 Subject: [PATCH 72/82] updated per code review Signed-off-by: Patrick Zheng --- verifier/helpers.go | 198 ------------------------------------------- verifier/verifier.go | 130 +++++++++++++++++++++++++++- 2 files changed, 129 insertions(+), 199 deletions(-) diff --git a/verifier/helpers.go b/verifier/helpers.go index 00f94db9..f1835f8d 100644 --- a/verifier/helpers.go +++ b/verifier/helpers.go @@ -19,20 +19,14 @@ import ( "errors" "fmt" "strings" - "time" - "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" set "github.com/notaryproject/notation-go/internal/container" notationsemver "github.com/notaryproject/notation-go/internal/semver" "github.com/notaryproject/notation-go/internal/slices" - "github.com/notaryproject/notation-go/log" "github.com/notaryproject/notation-go/verifier/trustpolicy" "github.com/notaryproject/notation-go/verifier/truststore" - "github.com/notaryproject/tspclient-go" ) const ( @@ -189,195 +183,3 @@ func isTSATrustStoreInPolicy(policyName string, trustStores []string) (bool, err } return false, nil } - -// 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) *notation.ValidationResult { - 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 ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to check tsa trust store configuration in turst policy with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - if !tsaEnabled { - logger.Info("Timestamp verification disabled: no tsa trust store is configured in trust policy") - performTimestampVerification = false - } - // check based on 'verifyTimestamp' field - if performTimestampVerification && - signatureVerification.VerifyTimestamp == trustpolicy.OptionAfterCertExpiry { - // check if signing cert chain has expired - var expired bool - for _, cert := range signerInfo.CertificateChain { - if time.Now().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 { - timeOfVerification := time.Now() - for _, cert := range signerInfo.CertificateChain { - if timeOfVerification.Before(cert.NotBefore) { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("verification time is before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - if timeOfVerification.After(cert.NotAfter) { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("verification time is after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.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], - } - } - // Performing timestamp verification - // 1. Timestamp countersignature MUST be present - logger.Info("Checking timestamp countersignature existence...") - if len(signerInfo.UnsignedAttributes.TimestampSignature) == 0 { - return ¬ation.ValidationResult{ - Error: errors.New("no timestamp countersignature was found in the signature envelope"), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - // 2. Verify the timestamp countersignature - logger.Info("Verifying the timestamp countersignature...") - signedToken, err := tspclient.ParseSignedToken(signerInfo.UnsignedAttributes.TimestampSignature) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to parse timestamp countersignature with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - info, err := signedToken.Info() - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to get the timestamp TSTInfo with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - trustTSACerts, err := loadX509TSATrustStores(ctx, outcome.EnvelopeContent.SignerInfo.SignedAttributes.SigningScheme, policyName, trustStores, x509TrustStore) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to load tsa trust store with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - if len(trustTSACerts) == 0 { - return ¬ation.ValidationResult{ - Error: errors.New("no trusted TSA certificate found in trust store"), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - rootCertPool := x509.NewCertPool() - for _, trustedCerts := range trustTSACerts { - rootCertPool.AddCert(trustedCerts) - } - timestamp, err := info.Validate(signerInfo.Signature) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to get timestamp from timestamp countersignature with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - tsaCertChain, err := signedToken.Verify(ctx, x509.VerifyOptions{ - CurrentTime: timestamp.Value, - Roots: rootCertPool, - }) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to verify the timestamp countersignature with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - // 3. Validate timestamping certificate chain - logger.Info("Validating timestamping certificate chain...") - if err := nx509.ValidateTimestampingCertChain(tsaCertChain); err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to validate the timestamping certificate chain with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - logger.Info("TSA identity is: ", tsaCertChain[0].Subject) - // 4. Perform the timestamping certificate chain revocation check - logger.Info("Checking timestamping certificate chain revocation...") - certResults, err := r.Validate(tsaCertChain, timestamp.Value) - if err != nil { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - 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 ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamping certificate with subject %q is revoked", problematicCertSubject), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - default: - // revocationresult.ResultUnknown - return ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamping certificate with subject %q revocation status is unknown", problematicCertSubject), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - // 5. Check the timestamp against the signing certificate chain - logger.Info("Checking the timestamp against the signing certificate chain...") - logger.Infof("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 ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamp can be before certificate %q validity period, it will be valid from %q", cert.Subject, cert.NotBefore.Format(time.RFC1123Z)), - Type: trustpolicy.TypeAuthenticTimestamp, - Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], - } - } - if !timestamp.BoundedBefore(cert.NotAfter) { - return ¬ation.ValidationResult{ - Error: fmt.Errorf("timestamp can be after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.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], - } -} diff --git a/verifier/verifier.go b/verifier/verifier.go index 169bd743..a2093556 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" ) @@ -683,7 +685,11 @@ func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStore // under signing scheme notary.x509 if signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { logger.Info("Under signing scheme notary.x509...") - return verifyTimestamp(ctx, policyName, trustStores, signatureVerification, x509TrustStore, r, outcome) + return ¬ation.ValidationResult{ + Error: verifyTimestamp(ctx, policyName, trustStores, signatureVerification, x509TrustStore, r, outcome), + Type: trustpolicy.TypeAuthenticTimestamp, + Action: outcome.VerificationLevel.Enforcement[trustpolicy.TypeAuthenticTimestamp], + } } // under signing scheme notary.x509.signingAuthority @@ -896,3 +902,125 @@ 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 + if performTimestampVerification && + signatureVerification.VerifyTimestamp == trustpolicy.OptionAfterCertExpiry { + // check if signing cert chain has expired + var expired bool + for _, cert := range signerInfo.CertificateChain { + if time.Now().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 { + timeOfVerification := time.Now() + 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 + // 1. Timestamp countersignature MUST be present + logger.Info("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.Info("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) + } + 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) + } + timestamp, err := info.Validate(signerInfo.Signature) + if err != nil { + return fmt.Errorf("failed to get timestamp from timestamp countersignature with error: %w", err) + } + 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.Info("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. Perform the timestamping certificate chain revocation check + logger.Info("Checking timestamping certificate chain revocation...") + certResults, err := r.Validate(tsaCertChain, timestamp.Value) + 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) + } + // 5. Check the timestamp against the signing certificate chain + logger.Info("Checking the timestamp against the signing certificate chain...") + logger.Infof("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)) + } + } + // success + return nil +} From a601fceb37c7f0ba6c736f211c75996e8a342af5 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 11 Jul 2024 13:19:39 +0800 Subject: [PATCH 73/82] update Signed-off-by: Patrick Zheng --- verifier/verifier.go | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index a2093556..2d6815aa 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -910,6 +910,7 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin signerInfo := outcome.EnvelopeContent.SignerInfo performTimestampVerification := true + // check if tsa trust store is configured in trust policy tsaEnabled, err := isTSATrustStoreInPolicy(policyName, trustStores) if err != nil { @@ -919,13 +920,15 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin 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 time.Now().After(cert.NotAfter) { + if timeOfVerification.After(cert.NotAfter) { expired = true break } @@ -935,10 +938,10 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin performTimestampVerification = false } } + // timestamp verification disabled, signing cert chain MUST be valid // at time of verification if !performTimestampVerification { - timeOfVerification := time.Now() 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)) @@ -947,15 +950,18 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin 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 // 1. Timestamp countersignature MUST be present logger.Info("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.Info("Verifying the timestamp countersignature...") signedToken, err := tspclient.ParseSignedToken(signerInfo.UnsignedAttributes.TimestampSignature) @@ -988,12 +994,14 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin if err != nil { return fmt.Errorf("failed to verify the timestamp countersignature with error: %w", err) } + // 3. Validate timestamping certificate chain logger.Info("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. Perform the timestamping certificate chain revocation check logger.Info("Checking timestamping certificate chain revocation...") certResults, err := r.Validate(tsaCertChain, timestamp.Value) @@ -1010,6 +1018,7 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin // revocationresult.ResultUnknown return fmt.Errorf("timestamping certificate with subject %q revocation status is unknown", problematicCertSubject) } + // 5. Check the timestamp against the signing certificate chain logger.Info("Checking the timestamp against the signing certificate chain...") logger.Infof("Timestamp range: [%v, %v]", timestamp.Value.Add(-timestamp.Accuracy), timestamp.Value.Add(timestamp.Accuracy)) @@ -1021,6 +1030,7 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin return fmt.Errorf("timestamp can be after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.Format(time.RFC1123Z)) } } + // success return nil } From 9f45e9717bc6fca19d2d109d47157b21aaca1b21 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 11 Jul 2024 15:29:17 +0800 Subject: [PATCH 74/82] update Signed-off-by: Patrick Zheng --- verifier/verifier.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 2d6815aa..4a82f64f 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -1004,7 +1004,7 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin // 4. Perform the timestamping certificate chain revocation check logger.Info("Checking timestamping certificate chain revocation...") - certResults, err := r.Validate(tsaCertChain, timestamp.Value) + certResults, err := r.Validate(tsaCertChain, time.Time{}) if err != nil { return fmt.Errorf("failed to check timestamping certificate chain revocation with error: %w", err) } From 45f34958dfa22d0f9dfc3eef36f0dc831a50fb86 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Thu, 11 Jul 2024 15:29:43 +0800 Subject: [PATCH 75/82] update Signed-off-by: Patrick Zheng --- verifier/verifier.go | 1 + 1 file changed, 1 insertion(+) diff --git a/verifier/verifier.go b/verifier/verifier.go index 4a82f64f..1d3cd730 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -704,6 +704,7 @@ func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStore } } } + // success return ¬ation.ValidationResult{ Type: trustpolicy.TypeAuthenticTimestamp, From 5c1a4b74c5a1c96a3c470ad5f80a9351a371904a Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 12 Jul 2024 15:24:57 +0800 Subject: [PATCH 76/82] updated per code review Signed-off-by: Patrick Zheng --- verifier/verifier.go | 50 ++++++++++++++++++++++---------------------- 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 1d3cd730..2f960399 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -132,7 +132,7 @@ func NewVerifierWithOptions(ociTrustPolicy *trustpolicy.OCIDocument, blobTrustPo revocationTimestampClient := verifierOptions.RevocationTimestampClient if revocationTimestampClient == nil { var err error - revocationTimestampClient, err = revocation.NewTimestamp(&http.Client{Timeout: 5 * time.Second}) + revocationTimestampClient, err = revocation.NewTimestamp(&http.Client{Timeout: 2 * time.Second}) if err != nil { return nil, err } @@ -918,7 +918,7 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin 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") + logger.Debug("Timestamp verification disabled: no tsa trust store is configured in trust policy") performTimestampVerification = false } @@ -935,7 +935,7 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin } } if !expired { - logger.Infof("Timestamp verification disabled: verifyTimestamp is set to %q and signing cert chain unexpired", trustpolicy.OptionAfterCertExpiry) + logger.Debugf("Timestamp verification disabled: verifyTimestamp is set to %q and signing cert chain unexpired", trustpolicy.OptionAfterCertExpiry) performTimestampVerification = false } } @@ -958,13 +958,13 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin // Performing timestamp verification // 1. Timestamp countersignature MUST be present - logger.Info("Checking timestamp countersignature existence...") + 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.Info("Verifying 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) @@ -973,6 +973,10 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin 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) @@ -984,10 +988,6 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin for _, trustedCerts := range trustTSACerts { rootCertPool.AddCert(trustedCerts) } - timestamp, err := info.Validate(signerInfo.Signature) - if err != nil { - return fmt.Errorf("failed to get timestamp from timestamp countersignature with error: %w", err) - } tsaCertChain, err := signedToken.Verify(ctx, x509.VerifyOptions{ CurrentTime: timestamp.Value, Roots: rootCertPool, @@ -997,14 +997,26 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin } // 3. Validate timestamping certificate chain - logger.Info("Validating 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) + logger.Debug("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)) + } + } - // 4. Perform the timestamping certificate chain revocation check - logger.Info("Checking timestamping certificate chain revocation...") + // 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) @@ -1020,18 +1032,6 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin return fmt.Errorf("timestamping certificate with subject %q revocation status is unknown", problematicCertSubject) } - // 5. Check the timestamp against the signing certificate chain - logger.Info("Checking the timestamp against the signing certificate chain...") - logger.Infof("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)) - } - } - // success return nil } From bf97c572da637a04496dc62c374f3a8b6d019bbd Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 12 Jul 2024 15:46:34 +0800 Subject: [PATCH 77/82] updated per code review Signed-off-by: Patrick Zheng --- signer/signer.go | 8 ++++++-- signer/signer_test.go | 30 ++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 2 deletions(-) diff --git a/signer/signer.go b/signer/signer.go index eea87651..7336cffb 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -122,8 +122,12 @@ 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, + } + if opts.Timestamper != nil && opts.TSARootCAs != nil { + signReq.Timestamper = opts.Timestamper + signReq.TSARootCAs = opts.TSARootCAs + } else if opts.Timestamper != nil || opts.TSARootCAs != nil { + return nil, nil, errors.New("timestamping: both Timestamper and TSARootCAs must be provided") } // Add expiry only if ExpiryDuration is not zero diff --git a/signer/signer_test.go b/signer/signer_test.go index ebfe8a0c..2482713a 100644 --- a/signer/signer_test.go +++ b/signer/signer_test.go @@ -227,6 +227,36 @@ func TestSignWithTimestamping(t *testing.T) { }) } } + + // 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: both Timestamper and TSARootCAs must be provided" + 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: both Timestamper and TSARootCAs must be provided" + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } } func TestSignBlobWithCertChain(t *testing.T) { From 7d03fd23bc44d1db74b04debc53e4ce182475f7b Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 12 Jul 2024 15:57:09 +0800 Subject: [PATCH 78/82] updated per code review Signed-off-by: Patrick Zheng --- verifier/verifier.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 2f960399..2dcd112b 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -684,7 +684,7 @@ func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStore signerInfo := outcome.EnvelopeContent.SignerInfo // under signing scheme notary.x509 if signerInfo.SignedAttributes.SigningScheme == signature.SigningSchemeX509 { - logger.Info("Under signing scheme notary.x509...") + logger.Debug("Under signing scheme notary.x509...") return ¬ation.ValidationResult{ Error: verifyTimestamp(ctx, policyName, trustStores, signatureVerification, x509TrustStore, r, outcome), Type: trustpolicy.TypeAuthenticTimestamp, @@ -693,7 +693,7 @@ func verifyAuthenticTimestamp(ctx context.Context, policyName string, trustStore } // under signing scheme notary.x509.signingAuthority - logger.Info("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) { From e0eb1b6639ffcd5d591e9b8eb8f3ce1ce9c744a2 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 12 Jul 2024 16:12:22 +0800 Subject: [PATCH 79/82] update Signed-off-by: Patrick Zheng --- verifier/verifier.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 2dcd112b..a17282d4 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -918,7 +918,7 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin return fmt.Errorf("failed to check tsa trust store configuration in turst policy with error: %w", err) } if !tsaEnabled { - logger.Debug("Timestamp verification disabled: no tsa trust store is configured in trust policy") + logger.Info("Timestamp verification disabled: no tsa trust store is configured in trust policy") performTimestampVerification = false } @@ -935,7 +935,7 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin } } if !expired { - logger.Debugf("Timestamp verification disabled: verifyTimestamp is set to %q and signing cert chain unexpired", trustpolicy.OptionAfterCertExpiry) + logger.Infof("Timestamp verification disabled: verifyTimestamp is set to %q and signing cert chain unexpired", trustpolicy.OptionAfterCertExpiry) performTimestampVerification = false } } From c962941db743f0028214ab73187302336c4a94f1 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 12 Jul 2024 16:24:44 +0800 Subject: [PATCH 80/82] update Signed-off-by: Patrick Zheng --- verifier/verifier.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index a17282d4..58dd403b 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -1001,11 +1001,11 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin if err := nx509.ValidateTimestampingCertChain(tsaCertChain); err != nil { return fmt.Errorf("failed to validate the timestamping certificate chain with error: %w", err) } - logger.Debug("TSA identity is: ", tsaCertChain[0].Subject) + 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)) + logger.Infof("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)) From e50cf0a1ca90a8cbc2095b82827aca9c9590bd0b Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 12 Jul 2024 16:30:15 +0800 Subject: [PATCH 81/82] updated log Signed-off-by: Patrick Zheng --- verifier/verifier.go | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/verifier/verifier.go b/verifier/verifier.go index 58dd403b..4eeca168 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -957,6 +957,8 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin } // 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 { @@ -1005,7 +1007,7 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin // 4. Check the timestamp against the signing certificate chain logger.Debug("Checking the timestamp against the signing certificate chain...") - logger.Infof("Timestamp range: [%v, %v]", timestamp.Value.Add(-timestamp.Accuracy), timestamp.Value.Add(timestamp.Accuracy)) + 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)) From b94b3fd1fa8ed871796a8e16ab3e025642ed066b Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 12 Jul 2024 17:09:32 +0800 Subject: [PATCH 82/82] updated per code review Signed-off-by: Patrick Zheng --- signer/signer.go | 14 ++++++++------ signer/signer_test.go | 4 ++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/signer/signer.go b/signer/signer.go index 7336cffb..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,12 +128,8 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts SigningTime: time.Now(), SigningScheme: signature.SigningSchemeX509, SigningAgent: signingAgentId, - } - if opts.Timestamper != nil && opts.TSARootCAs != nil { - signReq.Timestamper = opts.Timestamper - signReq.TSARootCAs = opts.TSARootCAs - } else if opts.Timestamper != nil || opts.TSARootCAs != nil { - return nil, nil, errors.New("timestamping: both Timestamper and TSARootCAs must be provided") + Timestamper: opts.Timestamper, + TSARootCAs: opts.TSARootCAs, } // Add expiry only if ExpiryDuration is not zero diff --git a/signer/signer_test.go b/signer/signer_test.go index 2482713a..fd1f4fb5 100644 --- a/signer/signer_test.go +++ b/signer/signer_test.go @@ -240,7 +240,7 @@ func TestSignWithTimestamping(t *testing.T) { sOpts.SignatureMediaType = envelopeType sOpts.TSARootCAs = x509.NewCertPool() _, _, err = s.Sign(ctx, desc, sOpts) - expectedErrMsg := "timestamping: both Timestamper and TSARootCAs must be provided" + expectedErrMsg := "timestamping: got TSARootCAs but nil Timestamper" if err == nil || err.Error() != expectedErrMsg { t.Fatalf("expected %s, but got %s", expectedErrMsg, err) } @@ -253,7 +253,7 @@ func TestSignWithTimestamping(t *testing.T) { t.Fatal(err) } _, _, err = s.Sign(ctx, desc, sOpts) - expectedErrMsg = "timestamping: both Timestamper and TSARootCAs must be provided" + expectedErrMsg = "timestamping: got Timestamper but nil TSARootCAs" if err == nil || err.Error() != expectedErrMsg { t.Fatalf("expected %s, but got %s", expectedErrMsg, err) }