diff --git a/cmd/notation/sign.go b/cmd/notation/sign.go index 30b4e0a6..4881ee9d 100644 --- a/cmd/notation/sign.go +++ b/cmd/notation/sign.go @@ -22,6 +22,7 @@ import ( "strings" "time" + "github.com/notaryproject/notation-core-go/revocation/purpose" corex509 "github.com/notaryproject/notation-core-go/x509" "github.com/notaryproject/notation-go" "github.com/notaryproject/notation-go/log" @@ -29,6 +30,7 @@ import ( "github.com/notaryproject/notation/internal/cmd" "github.com/notaryproject/notation/internal/envelope" "github.com/notaryproject/notation/internal/httputil" + clirev "github.com/notaryproject/notation/internal/revocation" nx509 "github.com/notaryproject/notation/internal/x509" "github.com/notaryproject/tspclient-go" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -251,6 +253,11 @@ func prepareSigningOpts(ctx context.Context, opts *signOpts) (notation.SignOptio rootCAs := x509.NewCertPool() rootCAs.AddCert(tsaRootCert) signOpts.TSARootCAs = rootCAs + revocationTimestampingValidator, err := clirev.NewRevocationValidator(ctx, purpose.Timestamping) + if err != nil { + return notation.SignOptions{}, fmt.Errorf("failed to create timestamping revocation validator: %w", err) + } + signOpts.RevocationTimestampingValidator = revocationTimestampingValidator } return signOpts, nil } diff --git a/cmd/notation/verify.go b/cmd/notation/verify.go index 66cc0df0..bfcb36d6 100644 --- a/cmd/notation/verify.go +++ b/cmd/notation/verify.go @@ -18,28 +18,22 @@ import ( "errors" "fmt" "io/fs" - "net/http" "os" "reflect" - "time" - "github.com/notaryproject/notation-core-go/revocation" "github.com/notaryproject/notation-core-go/revocation/purpose" "github.com/notaryproject/notation-go" "github.com/notaryproject/notation-go/dir" "github.com/notaryproject/notation-go/plugin" "github.com/notaryproject/notation-go/verifier" - "github.com/notaryproject/notation-go/verifier/crl" "github.com/notaryproject/notation-go/verifier/trustpolicy" "github.com/notaryproject/notation-go/verifier/truststore" "github.com/notaryproject/notation/cmd/notation/internal/experimental" "github.com/notaryproject/notation/internal/cmd" - "github.com/notaryproject/notation/internal/httputil" "github.com/notaryproject/notation/internal/ioutil" "github.com/spf13/cobra" - corecrl "github.com/notaryproject/notation-core-go/revocation/crl" - clicrl "github.com/notaryproject/notation/internal/crl" + clirev "github.com/notaryproject/notation/internal/revocation" ) type verifyOpts struct { @@ -234,39 +228,11 @@ func printMetadataIfPresent(outcome *notation.VerificationOutcome) { func getVerifier(ctx context.Context) (notation.Verifier, error) { // revocation check - ocspHttpClient := httputil.NewClient(ctx, &http.Client{Timeout: 2 * time.Second}) - crlFetcher, err := corecrl.NewHTTPFetcher(httputil.NewClient(ctx, &http.Client{Timeout: 5 * time.Second})) + revocationCodeSigningValidator, err := clirev.NewRevocationValidator(ctx, purpose.CodeSigning) if err != nil { return nil, err } - crlFetcher.DiscardCacheError = true // discard crl cache error - cacheRoot, err := dir.CacheFS().SysPath(dir.PathCRLCache) - if err != nil { - return nil, err - } - fileCache, err := crl.NewFileCache(cacheRoot) - if err != nil { - // discard NewFileCache error as cache errors are not critical - fmt.Fprintf(os.Stderr, "Warning: %v\n", err) - } else { - crlFetcher.Cache = &clicrl.CacheWithLog{ - Cache: fileCache, - DiscardCacheError: crlFetcher.DiscardCacheError, - } - } - revocationCodeSigningValidator, err := revocation.NewWithOptions(revocation.Options{ - OCSPHTTPClient: ocspHttpClient, - CRLFetcher: crlFetcher, - CertChainPurpose: purpose.CodeSigning, - }) - if err != nil { - return nil, err - } - revocationTimestampingValidator, err := revocation.NewWithOptions(revocation.Options{ - OCSPHTTPClient: ocspHttpClient, - CRLFetcher: crlFetcher, - CertChainPurpose: purpose.Timestamping, - }) + revocationTimestampingValidator, err := clirev.NewRevocationValidator(ctx, purpose.Timestamping) if err != nil { return nil, err } diff --git a/go.mod b/go.mod index 59a86370..5ab1b6cb 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,9 @@ module github.com/notaryproject/notation go 1.23 require ( - github.com/notaryproject/notation-core-go v1.2.0-rc.1 + github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241112001243-33af15a18954 github.com/notaryproject/notation-go v1.2.0-beta.1.0.20240926015724-84c2ec076201 - github.com/notaryproject/tspclient-go v0.2.0 + github.com/notaryproject/tspclient-go v0.2.1-0.20241030015323-90a141e7525c github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/sirupsen/logrus v1.9.3 @@ -25,10 +25,14 @@ require ( github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/notaryproject/notation-plugin-framework-go v1.0.0 // indirect - github.com/veraison/go-cose v1.1.0 // indirect + github.com/veraison/go-cose v1.3.0 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/crypto v0.29.0 // indirect - golang.org/x/mod v0.21.0 // indirect + golang.org/x/mod v0.22.0 // indirect golang.org/x/sync v0.6.0 // indirect golang.org/x/sys v0.27.0 // indirect ) + +replace github.com/notaryproject/notation-go => github.com/Two-Hearts/notation-go v0.0.0-20241121055318-95c089b05295 + +replace github.com/notaryproject/notation-core-go => github.com/Two-Hearts/notation-core-go v0.0.0-20241121052224-0fcd11654a68 diff --git a/go.sum b/go.sum index 3533edac..3b503925 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +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-20241121052224-0fcd11654a68 h1:SnQGrOkslzR0yh36nUtrIXXCy8radd+4NfufX4E1Ey0= +github.com/Two-Hearts/notation-core-go v0.0.0-20241121052224-0fcd11654a68/go.mod h1:Umjn4NKGmuHpVffMgKVcUnArNG3Qtd3duKYpPILUBg4= +github.com/Two-Hearts/notation-go v0.0.0-20241121055318-95c089b05295 h1:Rzqvvuec6E/9Q+uQkK1HyP8Gvld5wZeKBAJ4exxtUA8= +github.com/Two-Hearts/notation-go v0.0.0-20241121055318-95c089b05295/go.mod h1:WlEZnYhIq37R7eZfLxyrFswHAwXuKJ53iYhVp84QJ9c= 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/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= @@ -35,14 +39,10 @@ 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.2.0-rc.1 h1:VMFlG+9a1JoNAQ3M96g8iqCq0cDRtE7XBaiTD8Ouvqw= -github.com/notaryproject/notation-core-go v1.2.0-rc.1/go.mod h1:b/70rA4OgOHlg0A7pb8zTWKJadFO6781zS3a37KHEJQ= -github.com/notaryproject/notation-go v1.2.0-beta.1.0.20240926015724-84c2ec076201 h1:2QBYa9Df+vMwMiaHaFqPoUiwfx5vcPEgM7KbusivTpw= -github.com/notaryproject/notation-go v1.2.0-beta.1.0.20240926015724-84c2ec076201/go.mod h1:F6zMQl3PhVdCsI1xlIjK66kCorUQhWkoMtlZdvJWxFI= 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.2.0 h1:g/KpQGmyk/h7j60irIRG1mfWnibNOzJ8WhLqAzuiQAQ= -github.com/notaryproject/tspclient-go v0.2.0/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/notaryproject/tspclient-go v0.2.1-0.20241030015323-90a141e7525c h1:bX6gGxFw9+DShmYTgbD+vr6neF1SoXIMUU2fDgdLsfA= +github.com/notaryproject/tspclient-go v0.2.1-0.20241030015323-90a141e7525c/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= @@ -65,8 +65,8 @@ github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/ github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= -github.com/veraison/go-cose v1.1.0 h1:AalPS4VGiKavpAzIlBjrn7bhqXiXi4jbMYY/2+UC+4o= -github.com/veraison/go-cose v1.1.0/go.mod h1:7ziE85vSq4ScFTg6wyoMXjucIGOf4JkFEZi/an96Ct4= +github.com/veraison/go-cose v1.3.0 h1:2/H5w8kdSpQJyVtIhx8gmwPJ2uSz1PkyWFx0idbd7rk= +github.com/veraison/go-cose v1.3.0/go.mod h1:df09OV91aHoQWLmy1KsDdYiagtXgyAwAl8vFeFn1gMc= github.com/x448/float16 v0.8.4 h1:qLwI1I70+NjRFUR3zs1JPUCgaCXSh3SW62uAKT1mSBM= github.com/x448/float16 v0.8.4/go.mod h1:14CWIYCyZA/cWjXOioeEpHeN/83MdbZDRQHoFcYsOfg= github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= @@ -79,8 +79,8 @@ golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= 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.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= diff --git a/internal/revocation/revocation.go b/internal/revocation/revocation.go new file mode 100644 index 00000000..f9d940b4 --- /dev/null +++ b/internal/revocation/revocation.go @@ -0,0 +1,60 @@ +// 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 revocation + +import ( + "context" + "fmt" + "net/http" + "os" + "time" + + "github.com/notaryproject/notation-core-go/revocation" + corecrl "github.com/notaryproject/notation-core-go/revocation/crl" + "github.com/notaryproject/notation-core-go/revocation/purpose" + "github.com/notaryproject/notation-go/dir" + "github.com/notaryproject/notation-go/verifier/crl" + clicrl "github.com/notaryproject/notation/internal/crl" + "github.com/notaryproject/notation/internal/httputil" +) + +// NewRevocationValidator returns a revocation.Validator given the certificate +// purpose +func NewRevocationValidator(ctx context.Context, purpose purpose.Purpose) (revocation.Validator, error) { + ocspHttpClient := httputil.NewClient(ctx, &http.Client{Timeout: 2 * time.Second}) + crlFetcher, err := corecrl.NewHTTPFetcher(httputil.NewClient(ctx, &http.Client{Timeout: 5 * time.Second})) + if err != nil { + return nil, err + } + crlFetcher.DiscardCacheError = true // discard crl cache error + cacheRoot, err := dir.CacheFS().SysPath(dir.PathCRLCache) + if err != nil { + return nil, err + } + fileCache, err := crl.NewFileCache(cacheRoot) + if err != nil { + // discard NewFileCache error as cache errors are not critical + fmt.Fprintf(os.Stderr, "Warning: %v\n", err) + } else { + crlFetcher.Cache = &clicrl.CacheWithLog{ + Cache: fileCache, + DiscardCacheError: crlFetcher.DiscardCacheError, + } + } + return revocation.NewWithOptions(revocation.Options{ + OCSPHTTPClient: ocspHttpClient, + CRLFetcher: crlFetcher, + CertChainPurpose: purpose, + }) +} diff --git a/internal/revocation/revocation_test.go b/internal/revocation/revocation_test.go new file mode 100644 index 00000000..7c1aedd9 --- /dev/null +++ b/internal/revocation/revocation_test.go @@ -0,0 +1,59 @@ +// 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 revocation + +import ( + "context" + "os" + "runtime" + "testing" + + "github.com/notaryproject/notation-core-go/revocation/purpose" + "github.com/notaryproject/notation-go/dir" +) + +func TestNewRevocationValidator(t *testing.T) { + defer func(oldCacheDir string) { + dir.UserCacheDir = oldCacheDir + }(dir.UserCacheDir) + + t.Run("Success", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } + if _, err := NewRevocationValidator(context.Background(), purpose.Timestamping); err != nil { + t.Fatal(err) + } + }) + + tempRoot := t.TempDir() + t.Run("Success but without permission to create cache directory", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } + dir.UserCacheDir = tempRoot + if err := os.Chmod(tempRoot, 0); err != nil { + t.Fatal(err) + } + defer func() { + // restore permission + if err := os.Chmod(tempRoot, 0755); err != nil { + t.Fatalf("failed to change permission: %v", err) + } + }() + if _, err := NewRevocationValidator(context.Background(), purpose.Timestamping); err != nil { + t.Fatal(err) + } + }) +}