diff --git a/.github/.codecov.yml b/.github/.codecov.yml index f1f634615..5cb09045b 100644 --- a/.github/.codecov.yml +++ b/.github/.codecov.yml @@ -15,4 +15,7 @@ coverage: status: project: default: - target: 70% \ No newline at end of file + target: 70% + patch: + default: + target: 80% diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a53ff7df9..8f4ae073b 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -31,14 +31,14 @@ jobs: fail-fast: true steps: - name: Set up Go ${{ matrix.go-version }} - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: ${{ matrix.go-version }} check-latest: true - name: Check out code - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Cache Go modules - uses: actions/cache@0c45773b623bea8c8e75f6c82b208c3cf94ea4f9 # v4.0.2 + uses: actions/cache@1bd1e32a3bdc45362d1e726936510720a7c30a57 # v4.2.0 id: go-mod-cache with: path: ~/go/pkg/mod @@ -59,6 +59,6 @@ jobs: make e2e-covdata fi - name: Upload coverage to codecov.io - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 # v4.5.0 + uses: codecov/codecov-action@7f8b4b4bde536c465e797be725718b88c5d95e0e # v5.1.1 env: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index 53fec1f03..00ae70369 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -42,15 +42,15 @@ jobs: fail-fast: false steps: - name: Checkout repository - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 - name: Set up Go ${{ matrix.go-version }} environment - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: ${{ matrix.go-version }} check-latest: true - name: Initialize CodeQL - uses: github/codeql-action/init@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 + uses: github/codeql-action/init@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3.27.6 with: languages: go - name: Perform CodeQL Analysis - uses: github/codeql-action/analyze@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 + uses: github/codeql-action/analyze@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3.27.6 diff --git a/.github/workflows/license-checker.yml b/.github/workflows/license-checker.yml index 54e121173..ead1dcdd3 100644 --- a/.github/workflows/license-checker.yml +++ b/.github/workflows/license-checker.yml @@ -28,7 +28,4 @@ permissions: jobs: check-license: - permissions: - contents: write - pull-requests: write - uses: notaryproject/notation-core-go/.github/workflows/reusable-license-checker.yml@main \ No newline at end of file + uses: notaryproject/notation-core-go/.github/workflows/reusable-license-checker.yml@main diff --git a/.github/workflows/release-github.yml b/.github/workflows/release-github.yml index eaa77dc0e..29ede3f55 100644 --- a/.github/workflows/release-github.yml +++ b/.github/workflows/release-github.yml @@ -33,12 +33,12 @@ jobs: fail-fast: true steps: - name: Set up Go ${{ matrix.go-version }} - uses: actions/setup-go@0a12ed9d6a96ab950c8f026ed9f722fe0da7ef32 # v5.0.2 + uses: actions/setup-go@41dfa10bad2bb2ae585af6ee5bb4d7d973ad74ed # v5.1.0 with: go-version: ${{ matrix.go-version }} check-latest: true - name: Checkout - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2 with: fetch-depth: 0 - name: Set GoReleaser Previous Tag To Be Last Non Weekly Release @@ -46,7 +46,7 @@ jobs: pre_tag=`git tag --sort=-creatordate --list 'v*' | grep -v dev | head -2 | tail -1` echo "GORELEASER_PREVIOUS_TAG=$pre_tag" >> $GITHUB_ENV - name: Run GoReleaser - uses: goreleaser/goreleaser-action@286f3b13b1b49da4ac219696163fb8c1c93e1200 # v6.0.0 + uses: goreleaser/goreleaser-action@9ed2f89a662bf1735a48bc8557fd212fa902bebf # v6.1.0 with: distribution: goreleaser version: latest diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml index 7618d5ece..609938962 100644 --- a/.github/workflows/scorecard.yml +++ b/.github/workflows/scorecard.yml @@ -41,7 +41,7 @@ jobs: steps: - name: "Checkout code" - uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # tag=4.1.7 + uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # tag=4.2.2 with: persist-credentials: false @@ -54,13 +54,13 @@ jobs: publish_results: true - name: "Upload artifact" - uses: actions/upload-artifact@50769540e7f4bd5e21e526ee35c689e35e0d6874 # tag=v4.4.0 + uses: actions/upload-artifact@b4b15b8c7c6ac21ea08fcf65892d2ee8f75cf882 # tag=v4.4.3 with: name: SARIF file path: results.sarif retention-days: 5 - name: "Upload to code-scanning" - uses: github/codeql-action/upload-sarif@294a9d92911152fe08befb9ec03e240add280cb3 # v3.26.8 + uses: github/codeql-action/upload-sarif@aa578102511db1f4524ed59b8cc2bae4f6e88195 # v3.27.6 with: sarif_file: results.sarif diff --git a/.github/workflows/stale.yml b/.github/workflows/stale.yml index 3bdbf430e..ea4d822c6 100644 --- a/.github/workflows/stale.yml +++ b/.github/workflows/stale.yml @@ -16,11 +16,17 @@ on: schedule: - cron: "30 1 * * *" +permissions: + contents: read + jobs: stale: + permissions: + issues: write + pull-requests: write runs-on: ubuntu-latest steps: - - uses: actions/stale@v9 + - uses: actions/stale@28ca1036281a5e5922ead5184a1bbf96e5fc984e # v9.0.0 with: stale-issue-message: "This issue is stale because it has been opened for 60 days with no activity. Remove stale label or comment. Otherwise, it will be closed in 30 days." stale-pr-message: "This PR is stale because it has been opened for 45 days with no activity. Remove stale label or comment. Otherwise, it will be closed in 30 days." @@ -31,4 +37,3 @@ jobs: days-before-issue-close: 30 days-before-pr-close: 30 exempt-all-milestones: true - diff --git a/cmd/notation/internal/truststore/testdata/NotationTestRoot.pem b/cmd/notation/internal/truststore/testdata/NotationTestRoot.pem new file mode 100644 index 000000000..aa23820da --- /dev/null +++ b/cmd/notation/internal/truststore/testdata/NotationTestRoot.pem @@ -0,0 +1,27 @@ +-----BEGIN CERTIFICATE----- +MIIEizCCAvOgAwIBAgIBATANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzEL +MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEb +MBkGA1UEAxMSTm90YXRpb24gVGVzdCBSb290MCAXDTIwMDkwOTA3MDAwMFoYDzIx +MjIwOTA1MjAzODQ1WjBaMQswCQYDVQQGEwJVUzELMAkGA1UECBMCV0ExEDAOBgNV +BAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEbMBkGA1UEAxMSTm90YXRpb24g +VGVzdCBSb290MIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAxxAZ8VZe +gqBUctz3BkwhObZKnW+KsN5/N1/u2vPLmEzHDj6xgd8Hn0JoughDaxeQCV66NC2o +bqPnPp4+68G/qZnxkXVXdFyqVodu4FgPUjiqcJjft7bh45BVgLFpOqSqDQ3ko30B +7gdGfIIkoBj/8gz3tHnmIvl3MywtOhDeGnlLNzBY52wVmhPIdKOaW/7WkMrXKFCk +LkNICGnIpWuyBtC+7RfM8hG6eRW1KCm5xrkRmn5ptonjxix/JTGj4me/NMkwdVkz +6wcCSAJnqTgHi2oqk73qqNu0LHsEMFBF8IGqmVkn2MOHkFamPBokzQ6HXXfvR4nb +cWQZCUgRinPTVg9CF0B6XSCEMCSH5kveZxTQtAFRB6NosbzuU5jDmJgpbDfauev7 +Eg/6bZzphcugRkVuwulymzsake5Jbvs9Kyw3CNPYH2G3Kli1FNhfc46ugXHbIfXg +NQcou3xabcu+r6cFRqqK6NmV9ouMQRj8Ri95Gp2BUlpTEFhcvMb9d4nXAgMBAAGj +WjBYMA4GA1UdDwEB/wQEAwICBDATBgNVHSUEDDAKBggrBgEFBQcDAzASBgNVHRMB +Af8ECDAGAQH/AgEBMB0GA1UdDgQWBBS5FZjt9UsEPkcKrStrnjSpTq4kDTANBgkq +hkiG9w0BAQsFAAOCAYEAKtxfv12LzM85bxOMp5++pIDa6eMcBaurYbAM2yC9B6Lu +Hf0JGeFdNqt4Fw38Ajooj2vWMWBrARVEZRVqTC5+ZSN2meGBXBXlT4n8FdEdmv+0 +5iwVYdmDFp8FKeoOZZZF23u+r2OrazJo1ufWmoSI2P0lEfZQQFQElltWu3QH+OLO +WXJmB7KbLKyheelGK5XhtAYYapRdW4sKJ398ybpv5C1oALCcTwoSmvH8wW5J4/gj +mhKICYh2goMauf0lesdxj+0His7E8blOWrUmfOB5dp73XawLKcd/UxHN8zAPC08L +DL9NMcihn3ZHKi7/dtkiV2iSaDPD1ChSGdqfXIysYqOhYoktgAfBZ43CWnqQhgB8 +NezRKdOStYC3P2AGJW18irxxTRp2CO+gnXEcyhyr+cvyf0j8MkRSaHLXzjIrECu8 +BUitB6sKughdN13fs5t5SIiO6foeFdvIpZFFKO8s+4oTOSDCos2WFoC+8TZS6r58 +3OtFLmywl1HRgQkobGgw +-----END CERTIFICATE----- diff --git a/cmd/notation/internal/truststore/testdata/invalid.txt b/cmd/notation/internal/truststore/testdata/invalid.txt new file mode 100644 index 000000000..98eea0a15 --- /dev/null +++ b/cmd/notation/internal/truststore/testdata/invalid.txt @@ -0,0 +1 @@ +invalid test cert diff --git a/cmd/notation/internal/truststore/testdata/self-signed.crt b/cmd/notation/internal/truststore/testdata/self-signed.crt new file mode 100644 index 000000000..dd0094e90 --- /dev/null +++ b/cmd/notation/internal/truststore/testdata/self-signed.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/cmd/notation/internal/truststore/testdata/truststore/x509/ca/test/self-signed.crt b/cmd/notation/internal/truststore/testdata/truststore/x509/ca/test/self-signed.crt new file mode 100644 index 000000000..dd0094e90 --- /dev/null +++ b/cmd/notation/internal/truststore/testdata/truststore/x509/ca/test/self-signed.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/cmd/notation/internal/truststore/truststore.go b/cmd/notation/internal/truststore/truststore.go index 39edb0658..c2365a18f 100644 --- a/cmd/notation/internal/truststore/truststore.go +++ b/cmd/notation/internal/truststore/truststore.go @@ -194,7 +194,7 @@ func DeleteCert(storeType, namedStore, cert string, confirmed bool) error { return nil } -// CheckNonErrNotExistError returns nil when no err or err is fs.ErrNotExist +// CheckNonErrNotExistError returns nil when err is nil or err is fs.ErrNotExist func CheckNonErrNotExistError(err error) error { if err != nil && !errors.Is(err, fs.ErrNotExist) { return err diff --git a/cmd/notation/internal/truststore/truststore_test.go b/cmd/notation/internal/truststore/truststore_test.go index 2693fb4c9..b8aab3635 100644 --- a/cmd/notation/internal/truststore/truststore_test.go +++ b/cmd/notation/internal/truststore/truststore_test.go @@ -15,15 +15,107 @@ package truststore import ( "errors" + "os" "path/filepath" + "runtime" + "strings" "testing" + + "github.com/notaryproject/notation-go/dir" ) -func TestEmptyCertFile(t *testing.T) { - path := filepath.FromSlash("../../../../internal/testdata/Empty.txt") - expectedErr := errors.New("no valid certificate found in the empty file") - err := AddCert(path, "ca", "test", false) - if err == nil || err.Error() != "no valid certificate found in the file" { - t.Fatalf("expected err: %v, got: %v", expectedErr, err) - } +func TestAddCert(t *testing.T) { + defer func(oldDir string) { + dir.UserConfigDir = oldDir + }(dir.UserConfigDir) + + t.Run("empty store type", func(t *testing.T) { + expectedErrMsg := "store type cannot be empty" + err := AddCert("", "", "test", false) + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err) + } + }) + + t.Run("invalid store type", func(t *testing.T) { + expectedErrMsg := "unsupported store type: invalid" + err := AddCert("", "invalid", "test", false) + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err) + } + }) + + t.Run("invalid store name", func(t *testing.T) { + expectedErrMsg := "named store name needs to follow [a-zA-Z0-9_.-]+ format" + err := AddCert("", "ca", "test%", false) + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err) + } + }) + + t.Run("no valid certificate in file", func(t *testing.T) { + path := filepath.FromSlash("testdata/invalid.txt") + expectedErrMsg := "x509: malformed certificate" + err := AddCert(path, "ca", "test", false) + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err) + } + }) + + t.Run("cert already exists", func(t *testing.T) { + dir.UserConfigDir = "testdata" + path := filepath.FromSlash("testdata/self-signed.crt") + expectedErrMsg := "certificate already exists in the Trust Store" + err := AddCert(path, "ca", "test", false) + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err) + } + }) + + t.Run("empty file", func(t *testing.T) { + path := filepath.FromSlash("../../../../internal/testdata/Empty.txt") + expectedErr := errors.New("no valid certificate found in the empty file") + err := AddCert(path, "ca", "test", false) + if err == nil || err.Error() != "no valid certificate found in the file" { + t.Fatalf("expected err: %v, but got: %v", expectedErr, err) + } + }) + + t.Run("failed to add cert to store", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } + + dir.UserConfigDir = t.TempDir() + if err := os.Chmod(dir.UserConfigDir, 0000); err != nil { + t.Fatal(err) + } + defer os.Chmod(dir.UserConfigDir, 0700) + + path := filepath.FromSlash("testdata/NotationTestRoot.pem") + expectedErrMsg := "permission denied" + err := AddCert(path, "ca", "test", false) + if err == nil || !strings.Contains(err.Error(), expectedErrMsg) { + t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err) + } + }) +} + +func TestDeleteAllCerts(t *testing.T) { + defer func(oldDir string) { + dir.UserConfigDir = oldDir + }(dir.UserConfigDir) + + t.Run("store does not exist", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } + + dir.UserConfigDir = "testdata" + expectedErrMsg := `stat testdata/truststore/x509/tsa/test: no such file or directory` + err := DeleteAllCerts("tsa", "test", true) + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected err: %v, but got: %v", expectedErrMsg, err) + } + }) } diff --git a/cmd/notation/plugin/install.go b/cmd/notation/plugin/install.go index b7538fc16..d79924e10 100644 --- a/cmd/notation/plugin/install.go +++ b/cmd/notation/plugin/install.go @@ -132,7 +132,7 @@ func install(command *cobra.Command, opts *pluginInstallOpts) error { } pluginURL, err := url.Parse(opts.pluginSource) if err != nil { - return fmt.Errorf("failed to parse plugin download URL %s with error: %w", pluginURL, err) + return fmt.Errorf("failed to parse plugin download URL %s with error: %w", opts.pluginSource, err) } if pluginURL.Scheme != "https" { return fmt.Errorf("failed to download plugin from URL: only the HTTPS scheme is supported, but got %s", pluginURL.Scheme) diff --git a/cmd/notation/plugin/install_test.go b/cmd/notation/plugin/install_test.go new file mode 100644 index 000000000..6f583d7ed --- /dev/null +++ b/cmd/notation/plugin/install_test.go @@ -0,0 +1,96 @@ +// 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 plugin + +import ( + "context" + "os" + "path/filepath" + "runtime" + "strings" + "testing" + + notationplugin "github.com/notaryproject/notation/cmd/notation/internal/plugin" + "github.com/notaryproject/notation/internal/osutil" + "github.com/spf13/cobra" +) + +func TestInstall(t *testing.T) { + t.Run("invalid plugin source url", func(t *testing.T) { + opts := &pluginInstallOpts{ + pluginSourceType: notationplugin.PluginSourceTypeURL, + inputChecksum: "dummy", + pluginSource: "http://[::1]/%", + } + expectedErrMsg := `failed to parse plugin download URL http://[::1]/% with error: parse "http://[::1]/%": invalid URL escape "%"` + err := install(&cobra.Command{}, opts) + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected error %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("unknown plugin source type", func(t *testing.T) { + opts := &pluginInstallOpts{ + pluginSourceType: -1, + } + expectedErrMsg := `plugin installation failed: unknown plugin source type` + err := install(&cobra.Command{}, opts) + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected error %s, but got %s", expectedErrMsg, err) + } + }) +} + +func TestInstallPlugin(t *testing.T) { + ctx := context.Background() + t.Run("input path does not exist", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } + expectedErrMsg := `stat invalid: no such file or directory` + err := installPlugin(ctx, "invalid", "", false) + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected error %s, but got %s", expectedErrMsg, err) + } + }) + + t.Run("failed to get file type", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } + + tempDir := t.TempDir() + data := []byte("data") + filename := filepath.Join(tempDir, "a", "file.txt") + if err := osutil.WriteFile(filename, data); err != nil { + t.Fatal(err) + } + err := os.Chmod(tempDir, 0) + if err != nil { + t.Fatal(err) + } + defer func() { + err := os.Chmod(tempDir, 0700) + if err != nil { + t.Fatal(err) + } + }() + + expectedErrMsg := `permission denied` + err = installPlugin(ctx, filename, "", false) + if err == nil || !strings.Contains(err.Error(), expectedErrMsg) { + t.Fatalf("expected permission denied error, but got %s", err) + } + }) +} diff --git a/cmd/notation/sign.go b/cmd/notation/sign.go index 30b4e0a69..7e88cde5b 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 + tsaRevocationValidator, err := clirev.NewRevocationValidator(ctx, purpose.Timestamping) + if err != nil { + return notation.SignOptions{}, fmt.Errorf("failed to create timestamping revocation validator: %w", err) + } + signOpts.TSARevocationValidator = tsaRevocationValidator } return signOpts, nil } diff --git a/cmd/notation/verify.go b/cmd/notation/verify.go index 96b1ee123..d320db47b 100644 --- a/cmd/notation/verify.go +++ b/cmd/notation/verify.go @@ -18,27 +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" + clirev "github.com/notaryproject/notation/internal/revocation" ) type verifyOpts struct { @@ -233,32 +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 } - cacheRoot, err := dir.CacheFS().SysPath(dir.PathCRLCache) - if err != nil { - return nil, err - } - crlFetcher.Cache, err = crl.NewFileCache(cacheRoot) - if err != nil { - return nil, err - } - 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/cmd/notation/verify_test.go b/cmd/notation/verify_test.go index 23954e11f..98464f1cc 100644 --- a/cmd/notation/verify_test.go +++ b/cmd/notation/verify_test.go @@ -15,11 +15,14 @@ package main import ( "context" + "encoding/json" + "os" + "path/filepath" "reflect" - "runtime" "testing" "github.com/notaryproject/notation-go/dir" + "github.com/notaryproject/notation-go/verifier/trustpolicy" ) func TestVerifyCommand_BasicArgs(t *testing.T) { @@ -86,24 +89,48 @@ func TestVerifyCommand_MissingArgs(t *testing.T) { } func TestGetVerifier(t *testing.T) { - t.Run("non-existing trust policy", func(t *testing.T) { - dir.UserConfigDir = "/" - expectedErrMsg := "trust policy is not present. To create a trust policy, see: https://notaryproject.dev/docs/quickstart/#create-a-trust-policy" + defer func(oldConfiDir, oldCacheDir string) { + dir.UserConfigDir = oldConfiDir + dir.UserCacheDir = oldCacheDir + }(dir.UserConfigDir, dir.UserCacheDir) + + t.Run("success", func(t *testing.T) { + tempRoot := t.TempDir() + dir.UserConfigDir = tempRoot + path := filepath.Join(tempRoot, "trustpolicy.json") + policyJson, _ := json.Marshal(dummyOCIPolicyDocument()) + if err := os.WriteFile(path, policyJson, 0600); err != nil { + t.Fatalf("TestLoadOCIDocument write policy file failed. Error: %v", err) + } + t.Cleanup(func() { os.RemoveAll(tempRoot) }) + _, err := getVerifier(context.Background()) - if err == nil || err.Error() != expectedErrMsg { - t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + if err != nil { + t.Fatal(err) } }) - t.Run("failed to new crl file cache", func(t *testing.T) { - if runtime.GOOS == "windows" { - t.Skip("skipping test on Windows") - } - dir.UserCacheDir = "/cache" - expectedErrMsg := "failed to create crl file cache: mkdir /cache: permission denied" + t.Run("non-existing trust policy", func(t *testing.T) { + dir.UserConfigDir = "/" + expectedErrMsg := "trust policy is not present. To create a trust policy, see: https://notaryproject.dev/docs/quickstart/#create-a-trust-policy" _, err := getVerifier(context.Background()) if err == nil || err.Error() != expectedErrMsg { t.Fatalf("expected %s, but got %s", expectedErrMsg, err) } }) } + +func dummyOCIPolicyDocument() trustpolicy.Document { + return trustpolicy.Document{ + Version: "1.0", + TrustPolicies: []trustpolicy.TrustPolicy{ + { + Name: "test-statement-name", + RegistryScopes: []string{"registry.acme-rockets.io/software/net-monitor"}, + 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/go.mod b/go.mod index 7da3817e2..d25649623 100644 --- a/go.mod +++ b/go.mod @@ -3,16 +3,16 @@ module github.com/notaryproject/notation go 1.23 require ( - github.com/notaryproject/notation-core-go v1.2.0-rc.1 - github.com/notaryproject/notation-go v1.3.0-rc.1 - github.com/notaryproject/tspclient-go v0.2.0 + github.com/notaryproject/notation-core-go v1.2.0-rc.2 + github.com/notaryproject/notation-go v1.3.0-rc.2 + github.com/notaryproject/tspclient-go v1.0.0-rc.1 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/sirupsen/logrus v1.9.3 github.com/spf13/cobra v1.8.1 github.com/spf13/pflag v1.0.5 - golang.org/x/net v0.29.0 - golang.org/x/term v0.24.0 + golang.org/x/net v0.32.0 + golang.org/x/term v0.27.0 oras.land/oras-go/v2 v2.5.0 ) @@ -21,14 +21,14 @@ require ( github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-ldap/ldap/v3 v3.4.8 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.1 // indirect 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.27.0 // indirect - golang.org/x/mod v0.21.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/mod v0.22.0 // indirect golang.org/x/sync v0.6.0 // indirect - golang.org/x/sys v0.25.0 // indirect + golang.org/x/sys v0.28.0 // indirect ) diff --git a/go.sum b/go.sum index d21c731f2..50b5b3669 100644 --- a/go.sum +++ b/go.sum @@ -12,8 +12,8 @@ github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD 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= github.com/go-ldap/ldap/v3 v3.4.8/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= +github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= @@ -35,14 +35,14 @@ 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.3.0-rc.1 h1:pm9tdUy2tWYqlwyRDZyKXgLwAscDATPUYv0ul2RK/Iw= -github.com/notaryproject/notation-go v1.3.0-rc.1/go.mod h1:W4o45yolX4Q+3PKlcpGleLLXEKWHa3BshEqw/JX5c6I= +github.com/notaryproject/notation-core-go v1.2.0-rc.2 h1:0jOItalNwBNUhyuc5PPHQxO3jIZ5xRYq+IvRMQXNbuE= +github.com/notaryproject/notation-core-go v1.2.0-rc.2/go.mod h1:7aIcavfywFvBQoYyfVFJB501kt7Etqyubrt5mhJBG2c= +github.com/notaryproject/notation-go v1.3.0-rc.2 h1:uugL3kruAAWPMFoOhjcoPAhUnIqMF1pcc8nIlqOKpeU= +github.com/notaryproject/notation-go v1.3.0-rc.2/go.mod h1:l7C6xVLPy5cBb+6MpsM9iLyFrVYxgS6+QjBdrl/KSY8= 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 v1.0.0-rc.1 h1:KcHxlqg6Adt4kzGLw012i0YMLlwGwToiR129c6IQ7Ys= +github.com/notaryproject/tspclient-go v1.0.0-rc.1/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= @@ -75,12 +75,12 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y 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/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= 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= @@ -90,8 +90,8 @@ golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= -golang.org/x/net v0.29.0 h1:5ORfpBpCs4HzDYoodCDBbwHzdR5UrLBZ3sOnUJmFoHo= -golang.org/x/net v0.29.0/go.mod h1:gLkgy8jTGERgjzMic6DS9+SP0ajcu6Xu3Orq/SpETg0= +golang.org/x/net v0.32.0 h1:ZqPmj8Kzc+Y6e0+skZsuACbx+wzMgo5MQsJh9Qd6aYI= +golang.org/x/net v0.32.0/go.mod h1:CwU0IoeOlnQQWJ6ioyFrfRuomB8GKF6KbYXZVyeXNfs= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= @@ -107,16 +107,16 @@ golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/sys v0.25.0 h1:r+8e+loiHxRqhXVl6ML1nO3l1+oFoWbnlu2Ehimmi34= -golang.org/x/sys v0.25.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= -golang.org/x/term v0.24.0 h1:Mh5cbb+Zk2hqqXNO7S1iTjEphVL+jb8ZWaqh/g+JWkM= -golang.org/x/term v0.24.0/go.mod h1:lOBK/LVxemqiMij05LGJ0tzNr8xlmwBRJ81PX6wVLH8= +golang.org/x/term v0.27.0 h1:WP60Sv1nlK1T6SupCHbXzSaN0b9wUmsPoRS9b61A23Q= +golang.org/x/term v0.27.0/go.mod h1:iMsnZpn0cago0GOrHO2+Y7u7JPn5AylBrcoWkElMTSM= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= diff --git a/internal/revocation/crl/crl.go b/internal/revocation/crl/crl.go new file mode 100644 index 000000000..e5dfb489f --- /dev/null +++ b/internal/revocation/crl/crl.go @@ -0,0 +1,80 @@ +// 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 crl + +import ( + "context" + "errors" + "fmt" + "os" + "sync" + + corecrl "github.com/notaryproject/notation-core-go/revocation/crl" + "github.com/notaryproject/notation-go/log" +) + +// CacheWithLog implements corecrl.Cache with logging +type CacheWithLog struct { + corecrl.Cache + + //DiscardCacheError is set to true to enable logging the discard cache error + //warning + DiscardCacheError bool + + // logDiscardCrlCacheErrorOnce guarantees the discard cache error + // warning is logged only once + logDiscardCrlCacheErrorOnce sync.Once +} + +// Get retrieves the CRL bundle with the given url +func (c *CacheWithLog) Get(ctx context.Context, url string) (*corecrl.Bundle, error) { + if c.Cache == nil { + return nil, errors.New("cache cannot be nil") + } + logger := log.GetLogger(ctx) + + bundle, err := c.Cache.Get(ctx, url) + if err != nil && !errors.Is(err, corecrl.ErrCacheMiss) { + if c.DiscardCacheError { + c.logDiscardCrlCacheErrorOnce.Do(c.logDiscardCrlCacheError) + } + logger.Debug(err.Error()) + return nil, err + } + return bundle, err +} + +// Set stores the CRL bundle with the given url +func (c *CacheWithLog) Set(ctx context.Context, url string, bundle *corecrl.Bundle) error { + if c.Cache == nil { + return errors.New("cache cannot be nil") + } + logger := log.GetLogger(ctx) + + err := c.Cache.Set(ctx, url, bundle) + if err != nil { + if c.DiscardCacheError { + c.logDiscardCrlCacheErrorOnce.Do(c.logDiscardCrlCacheError) + } + logger.Debug(err.Error()) + return err + } + return nil +} + +// logDiscardCrlCacheError logs the warning when CRL cache error is +// discarded +func (c *CacheWithLog) logDiscardCrlCacheError() { + fmt.Fprintln(os.Stderr, "Warning: CRL cache error discarded. Enable debug log through '-d' for error details.") +} diff --git a/internal/revocation/crl/crl_test.go b/internal/revocation/crl/crl_test.go new file mode 100644 index 000000000..a81ba6c58 --- /dev/null +++ b/internal/revocation/crl/crl_test.go @@ -0,0 +1,135 @@ +// 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 crl + +import ( + "context" + "errors" + "os" + "sync" + "testing" + + corecrl "github.com/notaryproject/notation-core-go/revocation/crl" +) + +func TestGet(t *testing.T) { + cache := &CacheWithLog{} + expectedErrMsg := "cache cannot be nil" + _, err := cache.Get(context.Background(), "") + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected error %q, but got %q", expectedErrMsg, err) + } + + cache = &CacheWithLog{ + Cache: &dummyCache{}, + } + expectedErrMsg = "cache get failed" + _, err = cache.Get(context.Background(), "") + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected error %q, but got %q", expectedErrMsg, err) + } + + cache = &CacheWithLog{ + Cache: &dummyCache{ + cacheMiss: true, + }, + } + _, err = cache.Get(context.Background(), "") + if err == nil || !errors.Is(err, corecrl.ErrCacheMiss) { + t.Fatalf("expected error %q, but got %q", corecrl.ErrCacheMiss, err) + } +} + +func TestSet(t *testing.T) { + cache := &CacheWithLog{} + expectedErrMsg := "cache cannot be nil" + err := cache.Set(context.Background(), "", nil) + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected error %q, but got %q", expectedErrMsg, err) + } + + cache = &CacheWithLog{ + Cache: &dummyCache{}, + } + expectedErrMsg = "cache set failed" + err = cache.Set(context.Background(), "", nil) + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected error %q, but got %q", expectedErrMsg, err) + } + + cache = &CacheWithLog{ + Cache: &dummyCache{ + setSuccess: true, + }, + } + err = cache.Set(context.Background(), "", nil) + if err != nil { + t.Fatalf("expected nil error, but got %q", err) + } +} + +func TestLogDiscardErrorOnce(t *testing.T) { + cache := &CacheWithLog{ + Cache: &dummyCache{}, + DiscardCacheError: true, + } + oldStderr := os.Stderr + defer func() { + os.Stderr = oldStderr + }() + testFile, err := os.CreateTemp(t.TempDir(), "testNotation") + if err != nil { + t.Fatal(err) + } + defer testFile.Close() + os.Stderr = testFile + var wg sync.WaitGroup + for i := 0; i < 3; i++ { + wg.Add(1) + go func() { + defer wg.Done() + cache.Get(context.Background(), "") + cache.Set(context.Background(), "", nil) + }() + } + wg.Wait() + + b, err := os.ReadFile(testFile.Name()) + if err != nil { + t.Fatal(err) + } + expectedMsg := "Warning: CRL cache error discarded. Enable debug log through '-d' for error details.\n" + if string(b) != expectedMsg { + t.Fatalf("expected to get %q, but got %q", expectedMsg, string(b)) + } +} + +type dummyCache struct { + cacheMiss bool + setSuccess bool +} + +func (d *dummyCache) Get(ctx context.Context, url string) (*corecrl.Bundle, error) { + if d.cacheMiss { + return nil, corecrl.ErrCacheMiss + } + return nil, errors.New("cache get failed") +} + +func (d *dummyCache) Set(ctx context.Context, url string, bundle *corecrl.Bundle) error { + if d.setSuccess { + return nil + } + return errors.New("cache set failed") +} diff --git a/internal/revocation/revocation.go b/internal/revocation/revocation.go new file mode 100644 index 000000000..412d6f0e5 --- /dev/null +++ b/internal/revocation/revocation.go @@ -0,0 +1,54 @@ +// 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" + "github.com/notaryproject/notation/internal/httputil" + clicrl "github.com/notaryproject/notation/internal/revocation/crl" +) + +// NewRevocationValidator returns a revocation.Validator given the certificate +// purpose +func NewRevocationValidator(ctx context.Context, purpose purpose.Purpose) (revocation.Validator, error) { + // err is always nil + crlFetcher, _ := corecrl.NewHTTPFetcher(httputil.NewClient(ctx, &http.Client{Timeout: 5 * time.Second})) + crlFetcher.DiscardCacheError = true // discard crl cache error + cacheRoot, _ := dir.CacheFS().SysPath(dir.PathCRLCache) // err is always nil + 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: httputil.NewClient(ctx, &http.Client{Timeout: 2 * time.Second}), + CRLFetcher: crlFetcher, + CertChainPurpose: purpose, + }) +} diff --git a/internal/revocation/revocation_test.go b/internal/revocation/revocation_test.go new file mode 100644 index 000000000..eeb7ff54b --- /dev/null +++ b/internal/revocation/revocation_test.go @@ -0,0 +1,75 @@ +// 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" + "net/http" + "os" + "runtime" + "testing" + "time" + + 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/internal/httputil" +) + +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) + } + }) +} + +func TestNilError(t *testing.T) { + _, err := corecrl.NewHTTPFetcher(httputil.NewClient(context.Background(), &http.Client{Timeout: 5 * time.Second})) + if err != nil { + t.Fatal(err) + } + + _, err = dir.CacheFS().SysPath(dir.PathCRLCache) + if err != nil { + t.Fatal(err) + } +} diff --git a/internal/trace/context.go b/internal/trace/context.go index 8563d73ee..322696062 100644 --- a/internal/trace/context.go +++ b/internal/trace/context.go @@ -48,6 +48,7 @@ func WithLoggerLevel(ctx context.Context, level logrus.Level) context.Context { // create logger logger := logrus.New() + formatter.DisableQuote = true logger.SetFormatter(&formatter) logger.SetLevel(level) diff --git a/internal/trace/transport.go b/internal/trace/transport.go index 6d6f9546c..5c631c62b 100644 --- a/internal/trace/transport.go +++ b/internal/trace/transport.go @@ -31,13 +31,27 @@ package trace import ( "context" + "fmt" "net/http" "strings" + "sync/atomic" "github.com/notaryproject/notation-go/log" "github.com/sirupsen/logrus" ) +var ( + // requestCount records the number of logged request-response pairs and will + // be used as the unique id for the next pair. + requestCount uint64 + + // toScrub is a set of headers that should be scrubbed from the log. + toScrub = []string{ + "Authorization", + "Set-Cookie", + } +) + // Transport is an http.RoundTripper that keeps track of the in-flight // request and add hooks to report HTTP tracing events. type Transport struct { @@ -50,39 +64,43 @@ func NewTransport(base http.RoundTripper) *Transport { // RoundTrip calls base roundtrip while keeping track of the current request. func (t *Transport) RoundTrip(req *http.Request) (resp *http.Response, err error) { + id := atomic.AddUint64(&requestCount, 1) - 1 ctx := req.Context() e := log.GetLogger(ctx) - e.Debugf("> Request: %q %q", req.Method, req.URL) - e.Debugf("> Request headers:") - logHeader(req.Header, e) + // log the request + e.Debugf("Request #%d\n> Request: %q %q\n> Request headers:\n%s", + id, req.Method, req.URL, logHeader(req.Header)) + // log the response resp, err = t.RoundTripper.RoundTrip(req) if err != nil { e.Errorf("Error in getting response: %w", err) } else if resp == nil { e.Errorf("No response obtained for request %s %q", req.Method, req.URL) } else { - e.Debugf("< Response status: %q", resp.Status) - e.Debugf("< Response headers:") - logHeader(resp.Header, e) + e.Debugf("Response #%d\n< Response status: %q\n< Response headers:\n%s", + id, resp.Status, logHeader(resp.Header)) } return resp, err } // logHeader prints out the provided header keys and values, with auth header // scrubbed. -func logHeader(header http.Header, e log.Logger) { +func logHeader(header http.Header) string { if len(header) > 0 { + headers := []string{} for k, v := range header { - if strings.EqualFold(k, "Authorization") { - v = []string{"*****"} + for _, h := range toScrub { + if strings.EqualFold(k, h) { + v = []string{"*****"} + } } - e.Debugf(" %q: %q", k, strings.Join(v, ", ")) + headers = append(headers, fmt.Sprintf(" %q: %q", k, strings.Join(v, ", "))) } - } else { - e.Debugf(" Empty header") + return strings.Join(headers, "\n") } + return " Empty header" } // SetHTTPDebugLog sets up http debug log with logrus.Logger diff --git a/test/e2e/go.mod b/test/e2e/go.mod index 8eb559a31..24fcc881f 100644 --- a/test/e2e/go.mod +++ b/test/e2e/go.mod @@ -3,9 +3,10 @@ module github.com/notaryproject/notation/test/e2e go 1.23 require ( - github.com/notaryproject/notation-core-go v1.2.0-rc.1 - github.com/onsi/ginkgo/v2 v2.20.2 - github.com/onsi/gomega v1.34.1 + github.com/notaryproject/notation-core-go v1.2.0-rc.2 + github.com/notaryproject/notation-go v1.3.0-rc.2 + github.com/onsi/ginkgo/v2 v2.22.0 + github.com/onsi/gomega v1.36.1 github.com/opencontainers/image-spec v1.1.0 oras.land/oras-go/v2 v2.5.0 ) @@ -15,17 +16,17 @@ require ( github.com/go-logr/logr v1.4.2 // indirect github.com/go-task/slim-sprig/v3 v3.0.0 // indirect github.com/google/go-cmp v0.6.0 // indirect - github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 // indirect - github.com/notaryproject/tspclient-go v0.2.0 // indirect + github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db // indirect + github.com/notaryproject/tspclient-go v1.0.0-rc.1 // indirect github.com/opencontainers/go-digest 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/exp v0.0.0-20240719175910-8a7402abbf56 // indirect - golang.org/x/net v0.28.0 // indirect - golang.org/x/sync v0.8.0 // indirect - golang.org/x/sys v0.24.0 // indirect - golang.org/x/text v0.17.0 // indirect - golang.org/x/tools v0.24.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/net v0.30.0 // indirect + golang.org/x/sync v0.10.0 // indirect + golang.org/x/sys v0.28.0 // indirect + golang.org/x/text v0.21.0 // indirect + golang.org/x/tools v0.26.0 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect ) diff --git a/test/e2e/go.sum b/test/e2e/go.sum index 5b9cd34bb..a9febc544 100644 --- a/test/e2e/go.sum +++ b/test/e2e/go.sum @@ -8,16 +8,18 @@ github.com/go-task/slim-sprig/v3 v3.0.0 h1:sUs3vkvUymDpBKi3qH1YSqBQk9+9D/8M2mN1v github.com/go-task/slim-sprig/v3 v3.0.0/go.mod h1:W848ghGpv3Qj3dhTPRyJypKRiqCdHZiAzKg9hl15HA8= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= -github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5 h1:5iH8iuqE5apketRbSFBy+X1V0o+l+8NF1avt4HWl7cA= -github.com/google/pprof v0.0.0-20240827171923-fa2c70bbbfe5/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= -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/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/onsi/ginkgo/v2 v2.20.2 h1:7NVCeyIWROIAheY21RLS+3j2bb52W0W82tkberYytp4= -github.com/onsi/ginkgo/v2 v2.20.2/go.mod h1:K9gyxPIlb+aIvnZ8bd9Ak+YP18w3APlR+5coaZoE2ag= -github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= -github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db h1:097atOisP2aRj7vFgYQBbFN4U4JNXUNYpxael3UzMyo= +github.com/google/pprof v0.0.0-20241029153458-d1b30febd7db/go.mod h1:vavhavw2zAxS5dIdcRluK6cSGGPlZynqzFM8NdvU144= +github.com/notaryproject/notation-core-go v1.2.0-rc.2 h1:0jOItalNwBNUhyuc5PPHQxO3jIZ5xRYq+IvRMQXNbuE= +github.com/notaryproject/notation-core-go v1.2.0-rc.2/go.mod h1:7aIcavfywFvBQoYyfVFJB501kt7Etqyubrt5mhJBG2c= +github.com/notaryproject/notation-go v1.3.0-rc.2 h1:uugL3kruAAWPMFoOhjcoPAhUnIqMF1pcc8nIlqOKpeU= +github.com/notaryproject/notation-go v1.3.0-rc.2/go.mod h1:l7C6xVLPy5cBb+6MpsM9iLyFrVYxgS6+QjBdrl/KSY8= +github.com/notaryproject/tspclient-go v1.0.0-rc.1 h1:KcHxlqg6Adt4kzGLw012i0YMLlwGwToiR129c6IQ7Ys= +github.com/notaryproject/tspclient-go v1.0.0-rc.1/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/onsi/ginkgo/v2 v2.22.0 h1:Yed107/8DjTr0lKCNt7Dn8yQ6ybuDRQoMGrNFKzMfHg= +github.com/onsi/ginkgo/v2 v2.22.0/go.mod h1:7Du3c42kxCUegi0IImZ1wUQzMBVecgIHjR1C+NkhLQo= +github.com/onsi/gomega v1.36.1 h1:bJDPBO7ibjxcbHMgSCoo4Yj18UWbKDlLwX1x9sybDcw= +github.com/onsi/gomega v1.36.1/go.mod h1:PvZbdDc8J6XJEpDK4HCuRBm8a6Fzp9/DmhC9C7yFlog= 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= @@ -26,26 +28,24 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -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= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56 h1:2dVuKD2vS7b0QIHQbpyTISPd0LeHDbnYEryqj5Q1ug8= -golang.org/x/exp v0.0.0-20240719175910-8a7402abbf56/go.mod h1:M4RDyNAINzryxdtnbRXRL/OHtkFuWGRjvuhBJpk2IlY= -golang.org/x/net v0.28.0 h1:a9JDOJc5GMUJ0+UDqmLT86WiEy7iWyIhz8gz8E4e5hE= -golang.org/x/net v0.28.0/go.mod h1:yqtgsTWOOnlGLG9GFRrK3++bGOUEkNBoHZc8MEDWPNg= -golang.org/x/sync v0.8.0 h1:3NFvSEYkUoMifnESzZl15y791HH1qU2xm6eCJU5ZPXQ= -golang.org/x/sync v0.8.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= -golang.org/x/sys v0.24.0 h1:Twjiwq9dn6R1fQcyiK+wQyHWfaz/BJB+YIpzU/Cv3Xg= -golang.org/x/sys v0.24.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= -golang.org/x/text v0.17.0 h1:XtiM5bkSOt+ewxlOE/aE/AKEHibwj/6gvWMl9Rsh0Qc= -golang.org/x/text v0.17.0/go.mod h1:BuEKDfySbSR4drPmRPG/7iBdf8hvFMuRexcpahXilzY= -golang.org/x/tools v0.24.0 h1:J1shsA93PJUEVaUSaay7UXAyE8aimq3GW0pjlolpa24= -golang.org/x/tools v0.24.0/go.mod h1:YhNqVBIfWHdzvTLs0d8LCuMhkKUgSUKldakyV7W/WDQ= -google.golang.org/protobuf v1.34.1 h1:9ddQBjfCyZPOHPUiPxpYESBLc+T8P3E+Vo4IbKZgFWg= -google.golang.org/protobuf v1.34.1/go.mod h1:c6P6GXX6sHbq/GpV6MGZEdwhWPcYBgnhAHhKbcUYpos= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= +golang.org/x/net v0.30.0 h1:AcW1SDZMkb8IpzCdQUaIq2sP4sZ4zw+55h6ynffypl4= +golang.org/x/net v0.30.0/go.mod h1:2wGyMJ5iFasEhkwi13ChkO/t1ECNC4X4eBKkVFyYFlU= +golang.org/x/sync v0.10.0 h1:3NQrjDixjgGwUOCaF8w2+VYHv0Ve/vGYSbdkTa98gmQ= +golang.org/x/sync v0.10.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk= +golang.org/x/sys v0.28.0 h1:Fksou7UEQUWlKvIdsqzJmUmCX3cZuD2+P3XyyzwMhlA= +golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= +golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= +golang.org/x/tools v0.26.0 h1:v/60pFQmzmT9ExmjDv2gGIfi3OqfKoEP6I5+umXlbnQ= +golang.org/x/tools v0.26.0/go.mod h1:TPVVj70c7JJ3WCazhD8OdXcZg/og+b9+tH/KxylGwH0= +google.golang.org/protobuf v1.35.1 h1:m3LfL6/Ca+fqnjnlqQXNpFPABW1UD7mjh8KO2mKFytA= +google.golang.org/protobuf v1.35.1/go.mod h1:9fA7Ob0pmnwhb644+1+CVWFRbNajQ6iRojtC/QF5bRE= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= diff --git a/test/e2e/internal/notation/host.go b/test/e2e/internal/notation/host.go index 168015a2b..0ad17854f 100644 --- a/test/e2e/internal/notation/host.go +++ b/test/e2e/internal/notation/host.go @@ -123,7 +123,7 @@ func Opts(options ...utils.HostOption) []utils.HostOption { func BaseOptions() []utils.HostOption { return Opts( AuthOption("", ""), - AddKeyOption("e2e.key", "e2e.crt"), + AddKeyOption(filepath.Join(NotationE2ELocalKeysDir, "e2e.key"), filepath.Join(NotationE2ELocalKeysDir, "e2e.crt")), AddTrustStoreOption("e2e", filepath.Join(NotationE2ELocalKeysDir, "e2e.crt")), AddTrustPolicyOption("trustpolicy.json"), ) @@ -141,7 +141,7 @@ func TimestampOptions(verifyTimestamp string) []utils.HostOption { return Opts( AuthOption("", ""), - AddKeyOption("e2e.key", "e2e.crt"), + AddKeyOption(filepath.Join(NotationE2ELocalKeysDir, "e2e.key"), filepath.Join(NotationE2ELocalKeysDir, "e2e.crt")), AddTrustStoreOption("e2e", filepath.Join(NotationE2ELocalKeysDir, "e2e.crt")), AddTimestampTrustStoreOption("e2e", filepath.Join(NotationE2EConfigPath, "timestamp", "globalsignTSARoot.cer")), AddTimestampTrustStoreOption("e2e", filepath.Join(NotationE2EConfigPath, "timestamp", "DigiCertTSARootSHA384.cer")), @@ -149,10 +149,19 @@ func TimestampOptions(verifyTimestamp string) []utils.HostOption { ) } +func CRLOptions() []utils.HostOption { + return Opts( + AuthOption("", ""), + AddKeyOption(filepath.Join(NotationE2EConfigPath, "crl", "leaf.key"), filepath.Join(NotationE2EConfigPath, "crl", "certchain_with_crl.pem")), + AddTrustStoreOption("e2e", filepath.Join(NotationE2EConfigPath, "crl", "root.crt")), + AddTrustPolicyOption("trustpolicy.json"), + ) +} + func BaseOptionsWithExperimental() []utils.HostOption { return Opts( AuthOption("", ""), - AddKeyOption("e2e.key", "e2e.crt"), + AddKeyOption(filepath.Join(NotationE2ELocalKeysDir, "e2e.key"), filepath.Join(NotationE2ELocalKeysDir, "e2e.crt")), AddTrustStoreOption("e2e", filepath.Join(NotationE2ELocalKeysDir, "e2e.crt")), AddTrustPolicyOption("trustpolicy.json"), EnableExperimental(), @@ -163,7 +172,7 @@ func BaseOptionsWithExperimental() []utils.HostOption { // testing environment. func TestLoginOptions() []utils.HostOption { return Opts( - AddKeyOption("e2e.key", "e2e.crt"), + AddKeyOption(filepath.Join(NotationE2ELocalKeysDir, "e2e.key"), filepath.Join(NotationE2ELocalKeysDir, "e2e.crt")), AddTrustStoreOption("e2e", filepath.Join(NotationE2ELocalKeysDir, "e2e.crt")), AddTrustPolicyOption("trustpolicy.json"), AddConfigJsonOption("pass_credential_helper_config.json"), @@ -193,9 +202,9 @@ func AuthOption(username, password string) utils.HostOption { // AddKeyOption adds the test signingkeys.json, key and cert files to // the notation directory. -func AddKeyOption(keyName, certName string) utils.HostOption { +func AddKeyOption(keyPath, certPath string) utils.HostOption { return func(vhost *utils.VirtualHost) error { - return AddKeyPairs(vhost.AbsolutePath(NotationDirName), keyName, certName) + return AddKeyPairs(vhost.AbsolutePath(NotationDirName), keyPath, certPath) } } diff --git a/test/e2e/internal/notation/key.go b/test/e2e/internal/notation/key.go index d05003039..fd11a3852 100644 --- a/test/e2e/internal/notation/key.go +++ b/test/e2e/internal/notation/key.go @@ -53,35 +53,37 @@ type SigningKeys struct { // AddKeyPairs creates the signingkeys.json file and the localkeys directory // with e2e.key and e2e.crt -func AddKeyPairs(dir, keyName, certName string) error { +func AddKeyPairs(destNotationConfigDir, srcKeyPath, srcCertPath string) error { + keyName := filepath.Base(srcKeyPath) + certName := filepath.Base(srcCertPath) // create signingkeys.json files if err := saveJSON( - generateSigningKeys(dir), - filepath.Join(dir, SigningKeysFileName)); err != nil { + generateSigningKeys(destNotationConfigDir, keyName, certName), + filepath.Join(destNotationConfigDir, SigningKeysFileName)); err != nil { return err } // create localkeys directory - localKeysDir := filepath.Join(dir, LocalKeysDirName) + localKeysDir := filepath.Join(destNotationConfigDir, LocalKeysDirName) os.MkdirAll(localKeysDir, 0700) // copy key and cert files - if err := copyFile(filepath.Join(NotationE2ELocalKeysDir, keyName), filepath.Join(localKeysDir, "e2e.key")); err != nil { + if err := copyFile(srcKeyPath, filepath.Join(localKeysDir, keyName)); err != nil { return err } - return copyFile(filepath.Join(NotationE2ELocalKeysDir, certName), filepath.Join(localKeysDir, "e2e.crt")) + return copyFile(srcCertPath, filepath.Join(localKeysDir, certName)) } // generateSigningKeys generates the signingkeys.json for notation. -func generateSigningKeys(dir string) *SigningKeys { +func generateSigningKeys(dir, keyName, certName string) *SigningKeys { return &SigningKeys{ Default: "e2e", Keys: []KeySuite{ { Name: "e2e", X509KeyPair: &X509KeyPair{ - KeyPath: filepath.Join(dir, "localkeys", "e2e.key"), - CertificatePath: filepath.Join(dir, "localkeys", "e2e.crt"), + KeyPath: filepath.Join(dir, "localkeys", keyName), + CertificatePath: filepath.Join(dir, "localkeys", certName), }, }, }, diff --git a/test/e2e/internal/utils/crl.go b/test/e2e/internal/utils/crl.go new file mode 100644 index 000000000..36bc8d0f8 --- /dev/null +++ b/test/e2e/internal/utils/crl.go @@ -0,0 +1,79 @@ +// 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 utils + +import ( + "fmt" + "net/http" +) + +// LeafCRLRevoke sends http post request to http://localhost:10086/leaf/revoke +func LeafCRLRevoke() error { + url := "http://localhost:10086/leaf/revoke" + resp, err := http.Post(url, "application/json", nil) + if err != nil { + return err + } + defer resp.Body.Close() + fmt.Printf("CRL of leaf certificate revoked with status code: %d\n", resp.StatusCode) + return nil +} + +// LeafCRLUnrevoke sends http post request to http://localhost:10086/leaf/unrevoke +func LeafCRLUnrevoke() error { + url := "http://localhost:10086/leaf/unrevoke" + resp, err := http.Post(url, "application/json", nil) + if err != nil { + return err + } + defer resp.Body.Close() + fmt.Printf("CRL of leaf certificate unrevoked with status code: %d\n", resp.StatusCode) + return nil +} + +// LeafCRLExpired sends http post request to http://localhost:10086/leaf/expired +func LeafCRLExpired() error { + url := "http://localhost:10086/leaf/expired" + resp, err := http.Post(url, "application/json", nil) + if err != nil { + return err + } + defer resp.Body.Close() + fmt.Printf("CRL of leaf certificate expired with status code: %d\n", resp.StatusCode) + return nil +} + +// IntermediateCRLRevoke sends http post request to http://localhost:10086/intermediate/revoke +func IntermediateCRLRevoke() error { + url := "http://localhost:10086/intermediate/revoke" + resp, err := http.Post(url, "application/json", nil) + if err != nil { + return nil + } + defer resp.Body.Close() + fmt.Printf("CRL of intermediate certificate revoked with status code: %d\n", resp.StatusCode) + return nil +} + +// IntermediateCRLUnrevoke sends http post request to http://localhost:10086/intermediate/unrevoke +func IntermediateCRLUnrevoke() error { + url := "http://localhost:10086/intermediate/unrevoke" + resp, err := http.Post(url, "application/json", nil) + if err != nil { + return nil + } + defer resp.Body.Close() + fmt.Printf("CRL of intermediate certificate unrevoked with status code: %d\n", resp.StatusCode) + return nil +} diff --git a/test/e2e/internal/utils/host.go b/test/e2e/internal/utils/host.go index f5a336856..605032767 100644 --- a/test/e2e/internal/utils/host.go +++ b/test/e2e/internal/utils/host.go @@ -38,7 +38,7 @@ func NewVirtualHost(binPath string, options ...HostOption) (*VirtualHost, error) vhost.userDir = ginkgo.GinkgoT().TempDir() // set user dir environment variables - vhost.UpdateEnv(UserConfigEnv(vhost.userDir)) + vhost.UpdateEnv(UserEnv(vhost.userDir)) // set options vhost.SetOption(options...) @@ -77,11 +77,13 @@ func (h *VirtualHost) SetOption(options ...HostOption) { // HostOption is a function to set the host configuration. type HostOption func(vhost *VirtualHost) error -// UserConfigEnv creates environment variable for changing -// user config dir (By setting $XDG_CONFIG_HOME). -func UserConfigEnv(dir string) map[string]string { +// UserEnv creates environment variable for changing +// user config dir by setting $XDG_CONFIG_HOME and user cache dir by +// setting $NOTATION_CACHE. +func UserEnv(dir string) map[string]string { // create and set user dir for linux return map[string]string{ "XDG_CONFIG_HOME": dir, + "NOTATION_CACHE": filepath.Join(dir, ".cache"), } } diff --git a/test/e2e/plugin/go.mod b/test/e2e/plugin/go.mod index 7524d77b7..2a1600a44 100644 --- a/test/e2e/plugin/go.mod +++ b/test/e2e/plugin/go.mod @@ -4,10 +4,10 @@ go 1.23 require ( github.com/golang-jwt/jwt v3.2.2+incompatible - github.com/notaryproject/notation-core-go v1.2.0-rc.1 - github.com/notaryproject/notation-go v1.3.0-rc.1 + github.com/notaryproject/notation-core-go v1.2.0-rc.2 + github.com/notaryproject/notation-go v1.3.0-rc.2 github.com/notaryproject/notation-plugin-framework-go v1.0.0 - github.com/spf13/cobra v1.7.0 + github.com/spf13/cobra v1.8.1 ) require ( @@ -15,17 +15,17 @@ require ( github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect github.com/go-ldap/ldap/v3 v3.4.8 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect - github.com/notaryproject/tspclient-go v0.2.0 // indirect + github.com/notaryproject/tspclient-go v1.0.0-rc.1 // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/opencontainers/image-spec v1.1.0 // indirect github.com/spf13/pflag v1.0.5 // 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.27.0 // indirect - golang.org/x/mod v0.21.0 // indirect + golang.org/x/crypto v0.31.0 // indirect + golang.org/x/mod v0.22.0 // indirect golang.org/x/sync v0.6.0 // indirect oras.land/oras-go/v2 v2.5.0 // indirect ) diff --git a/test/e2e/plugin/go.sum b/test/e2e/plugin/go.sum index e9735eacc..856583b69 100644 --- a/test/e2e/plugin/go.sum +++ b/test/e2e/plugin/go.sum @@ -2,7 +2,7 @@ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 h1:mFRzDkZVAjdal+ github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358/go.mod h1:chxPXzSsl7ZWRAuOIE23GDNzjWuZquvFlgA8xmpunjU= 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.2/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= +github.com/cpuguy83/go-md2man/v2 v2.0.4/go.mod h1:tgQtvFlXSQOSOSIRvRPT7W67SCa46tRHOmNcaadrF8o= 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= @@ -14,8 +14,8 @@ github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ github.com/go-ldap/ldap/v3 v3.4.8/go.mod h1:qS3Sjlu76eHfHGpUdWkAXQTw4beih+cHsco2jXlIXrk= github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY= github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I= -github.com/golang-jwt/jwt/v4 v4.5.0 h1:7cYmW1XlMY7h7ii7UhUyChSgS5wUJEnm9uZVTGqOWzg= -github.com/golang-jwt/jwt/v4 v4.5.0/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= +github.com/golang-jwt/jwt/v4 v4.5.1 h1:JdqV9zKUdtaa9gdPlywC3aeoEsR681PlKC+4F5gQgeo= +github.com/golang-jwt/jwt/v4 v4.5.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/securecookie v1.1.1/go.mod h1:ra0sb63/xPlUeL+yeDciTfxMRAA+MP+HVt/4epWDjd4= @@ -37,14 +37,14 @@ 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.3.0-rc.1 h1:pm9tdUy2tWYqlwyRDZyKXgLwAscDATPUYv0ul2RK/Iw= -github.com/notaryproject/notation-go v1.3.0-rc.1/go.mod h1:W4o45yolX4Q+3PKlcpGleLLXEKWHa3BshEqw/JX5c6I= +github.com/notaryproject/notation-core-go v1.2.0-rc.2 h1:0jOItalNwBNUhyuc5PPHQxO3jIZ5xRYq+IvRMQXNbuE= +github.com/notaryproject/notation-core-go v1.2.0-rc.2/go.mod h1:7aIcavfywFvBQoYyfVFJB501kt7Etqyubrt5mhJBG2c= +github.com/notaryproject/notation-go v1.3.0-rc.2 h1:uugL3kruAAWPMFoOhjcoPAhUnIqMF1pcc8nIlqOKpeU= +github.com/notaryproject/notation-go v1.3.0-rc.2/go.mod h1:l7C6xVLPy5cBb+6MpsM9iLyFrVYxgS6+QjBdrl/KSY8= 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 v1.0.0-rc.1 h1:KcHxlqg6Adt4kzGLw012i0YMLlwGwToiR129c6IQ7Ys= +github.com/notaryproject/tspclient-go v1.0.0-rc.1/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= @@ -52,8 +52,8 @@ github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2sz github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= -github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I= -github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0= +github.com/spf13/cobra v1.8.1 h1:e5/vxKd/rZsfSJMUX1agtjeTDf+qv1/JdBF8gg5k9ZM= +github.com/spf13/cobra v1.8.1/go.mod h1:wHxEcudfqmLYa8iTfL+OuZPbBZkmvliBWKIezN3kD9Y= github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA= github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= @@ -64,8 +64,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= @@ -74,12 +74,12 @@ golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5y 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/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= -golang.org/x/crypto v0.27.0 h1:GXm2NjJrPaiv/h1tb2UH8QfgC/hOf/+z0p6PT8o1w7A= -golang.org/x/crypto v0.27.0/go.mod h1:1Xngt8kV6Dvbssa53Ziq6Eqn0HqbZi5Z6R0ZpwQzt70= +golang.org/x/crypto v0.31.0 h1:ihbySMvVjLAeSH1IbfcRTkD/iNscyz8rGzjF/E5hV6U= +golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk= 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/test/e2e/run.sh b/test/e2e/run.sh index 1d3559788..4a8e28f05 100755 --- a/test/e2e/run.sh +++ b/test/e2e/run.sh @@ -69,7 +69,7 @@ if [ ! -f "$NOTATION_E2E_OLD_BINARY_PATH" ]; then fi # install dependency -go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo@v2.11.0 +go install -mod=mod github.com/onsi/ginkgo/v2/ginkgo@v2.21.0 # build e2e plugin and tar.gz PLUGIN_NAME=notation-e2e-plugin @@ -95,9 +95,16 @@ esac setup_registry +# run the CRL server in the background +python3 ./scripts/crl_server.py & +CRL_SERVER_PID=$! + # defer cleanup registry function cleanup { + echo "Cleaning up..." cleanup_registry + echo "Stopping CRL server..." + kill $CRL_SERVER_PID } trap cleanup EXIT @@ -111,4 +118,4 @@ export NOTATION_E2E_PLUGIN_TAR_GZ_PATH=$CWD/plugin/bin/$PLUGIN_NAME.tar.gz export NOTATION_E2E_MALICIOUS_PLUGIN_ARCHIVE_PATH=$CWD/testdata/malicious-plugin # run tests -ginkgo -r -p -v +ginkgo -r -p -v \ No newline at end of file diff --git a/test/e2e/scripts/crl_server.py b/test/e2e/scripts/crl_server.py new file mode 100644 index 000000000..dea91d699 --- /dev/null +++ b/test/e2e/scripts/crl_server.py @@ -0,0 +1,81 @@ +# 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. + +import http.server +import socketserver +import os + +PORT = 10086 +DATA_DIR = './testdata/config/crl' +leaf_crl = 'leaf.crl' +intermediate_crl = 'intermediate.crl' + + +class CRLRequestHandler(http.server.SimpleHTTPRequestHandler): + def do_GET(self): + global leaf_crl + global intermediate_crl + if self.path == '/leaf.crl': + file_path = os.path.join(DATA_DIR, leaf_crl) + self.crl_response(file_path) + elif self.path == '/intermediate.crl': + file_path = os.path.join(DATA_DIR, intermediate_crl) + self.crl_response(file_path) + else: + self.send_error(404, 'Not Found') + + def crl_response(self, file_path): + if os.path.exists(file_path): + self.send_response(200) + self.send_header('Content-Type', 'application/pkix-crl') + self.end_headers() + with open(file_path, 'rb') as f: + self.wfile.write(f.read()) + else: + self.send_error(404, 'File Not Found') + + def do_POST(self): + global leaf_crl + global intermediate_crl + if self.path == '/leaf/revoke': + leaf_crl = 'leaf_revoked.crl' + self.post_response() + elif self.path == '/leaf/unrevoke': + leaf_crl = 'leaf.crl' + self.post_response() + elif self.path == '/leaf/expired': + leaf_crl = 'leaf_expired.crl' + self.post_response() + elif self.path == '/intermediate/revoke': + intermediate_crl = 'intermediate_revoked.crl' + self.post_response() + elif self.path == '/intermediate/unrevoke': + intermediate_crl = 'intermediate.crl' + self.post_response() + else: + self.send_error(404, 'Not Found') + + def post_response(self): + self.send_response(201) + self.end_headers() + self.wfile.write(b'ok') + +class ReusableTCPServer(socketserver.TCPServer): + allow_reuse_address = True + +with ReusableTCPServer(('', PORT), CRLRequestHandler) as httpd: + print(f"Serving at port {PORT}") + try: + httpd.serve_forever() + finally: + httpd.server_close() \ No newline at end of file diff --git a/test/e2e/scripts/gen_crl_testing_certs.sh b/test/e2e/scripts/gen_crl_testing_certs.sh new file mode 100755 index 000000000..59d3a1457 --- /dev/null +++ b/test/e2e/scripts/gen_crl_testing_certs.sh @@ -0,0 +1,231 @@ +#!/bin/bash -ex +# 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. + +# This file include the script to generate testing certificates for CRL testing. +# The generated files are: +# - certchain_with_crl.pem: the fullchain file that includes the leaf +# certificate with CRL, intermediate certificate with invalid OCSP and valid +# CRL, and the root certificate. +# - leaf.crl: the CRL file that includes the revoked leaf certificate. +# - leaf.key: the private key of the leaf certificate. +# - leaf_revoked.crl: the CRL file that includes the revoked leaf certificate. +# - intermediate.crl: the CRL file that includes the intermediate certificate. +# - intermediate_revoked.crl: the CRL file that includes the revoked intermediate +# - root.crt: the root certificate. +# +# Note: The script will not run in the pipeline, but we need to keep it for +# future maintenance because generating those test certificates with CRL is not +# easy. + +# Create root CA configuration file +cat > root.cnf < demoCA/serial +echo '1002' > demoCA/crlnumber + +# Generate root private key +openssl genrsa -out root.key 2048 + +# Generate self-signed root certificate with extensions +openssl req -x509 -new -key root.key -sha256 -days 36500 -out root.crt \ + -config root.cnf -extensions v3_ca + +# Update intermediate.cnf to include [ca] and [CA_default] sections +cat > intermediate.cnf < intermediateCA/serial +echo '1000' > intermediateCA/crlnumber + +# Generate intermediate private key +openssl genrsa -out intermediate.key 2048 + +# Generate intermediate CSR +openssl req -new -key intermediate.key -out intermediate.csr -config intermediate.cnf + +# Sign intermediate certificate with root CA +openssl ca -config root.cnf -in intermediate.csr -out intermediate.crt -batch -extensions v3_intermediate_ca -extfile intermediate.cnf -notext + +# Update leaf.cnf to remove OCSP server +cat > leaf.cnf < certchain_with_crl.pem + +rm -rf leaf.csr leaf.crt leaf.cnf root.srl root.cnf root.key root.crl demoCA intermediate.csr intermediate.cnf intermediate.key intermediate.crt intermediateCA diff --git a/test/e2e/suite/command/verify.go b/test/e2e/suite/command/verify.go index 239b363b2..9ab8d29d0 100644 --- a/test/e2e/suite/command/verify.go +++ b/test/e2e/suite/command/verify.go @@ -229,7 +229,7 @@ var _ = Describe("notation verify", func() { notation.Exec("sign", "--timestamp-url", "http://timestamp.digicert.com", "--timestamp-root-cert", filepath.Join(NotationE2EConfigPath, "timestamp", "DigiCertTSARootSHA384.cer"), artifact.ReferenceWithDigest()). MatchKeyWords(SignSuccessfully) - notation.Exec("verify", artifact.ReferenceWithDigest(), "-v"). + notation.Exec("verify", artifact.ReferenceWithDigest(), "-d"). MatchKeyWords(VerifySuccessfully). MatchErrKeyWords("Timestamp verification disabled") }) @@ -240,7 +240,7 @@ var _ = Describe("notation verify", func() { notation.Exec("sign", "--timestamp-url", "http://timestamp.digicert.com", "--timestamp-root-cert", filepath.Join(NotationE2EConfigPath, "timestamp", "DigiCertTSARootSHA384.cer"), artifact.ReferenceWithDigest()). MatchKeyWords(SignSuccessfully) - notation.Exec("verify", artifact.ReferenceWithDigest(), "-v"). + notation.Exec("verify", artifact.ReferenceWithDigest(), "-d"). MatchKeyWords(VerifySuccessfully). MatchErrKeyWords("Performing timestamp verification...") }) @@ -251,9 +251,9 @@ var _ = Describe("notation verify", func() { notation.Exec("sign", "--timestamp-url", "http://timestamp.digicert.com", "--timestamp-root-cert", filepath.Join(NotationE2EConfigPath, "timestamp", "DigiCertTSARootSHA384.cer"), artifact.ReferenceWithDigest()). MatchKeyWords(SignSuccessfully) - notation.Exec("verify", artifact.ReferenceWithDigest(), "-v"). + notation.Exec("verify", artifact.ReferenceWithDigest(), "-d"). MatchKeyWords(VerifySuccessfully). - MatchErrKeyWords("Timestamp verification disabled: verifyTimestamp is set to \\\"afterCertExpiry\\\" and signing cert chain unexpired") + MatchErrKeyWords("Timestamp verification disabled: verifyTimestamp is set to \"afterCertExpiry\" and signing cert chain unexpired") }) }) }) diff --git a/test/e2e/suite/plugin/install.go b/test/e2e/suite/plugin/install.go index 363801d44..746babf6a 100644 --- a/test/e2e/suite/plugin/install.go +++ b/test/e2e/suite/plugin/install.go @@ -154,8 +154,8 @@ var _ = Describe("notation plugin install", func() { It("with invalid plugin URL", func() { Host(nil, func(notation *utils.ExecOpts, _ *Artifact, vhost *utils.VirtualHost) { - notation.ExpectFailure().Exec("plugin", "install", "--url", "https://invalid", "--sha256sum", "abcd"). - MatchErrKeyWords("failed to download plugin from URL https://invalid") + notation.ExpectFailure().Exec("plugin", "install", "--url", "https://invalid.test", "--sha256sum", "abcd"). + MatchErrKeyWords("failed to download plugin from URL https://invalid.test") }) }) }) diff --git a/test/e2e/suite/plugin/verify.go b/test/e2e/suite/plugin/verify.go index 51b76f7a7..520d5cf0b 100644 --- a/test/e2e/suite/plugin/verify.go +++ b/test/e2e/suite/plugin/verify.go @@ -46,7 +46,7 @@ var _ = Describe("notation plugin verify", func() { MatchErrKeyWords( "Plugin verify-signature request", "Plugin verify-signature response", - `{\"verificationResults\":{\"SIGNATURE_VERIFIER.REVOCATION_CHECK\":{\"success\":true},\"SIGNATURE_VERIFIER.TRUSTED_IDENTITY\":{\"success\":true}},\"processedAttributes\":null}`). + `{"verificationResults":{"SIGNATURE_VERIFIER.REVOCATION_CHECK":{"success":true},"SIGNATURE_VERIFIER.TRUSTED_IDENTITY":{"success":true}},"processedAttributes":null}`). MatchKeyWords(VerifySuccessfully) }) }) @@ -77,7 +77,7 @@ var _ = Describe("notation plugin verify", func() { MatchErrKeyWords( "Plugin verify-signature request", "Plugin verify-signature response", - `revocation check by verification plugin \"e2e-plugin\" failed with reason \"revocation check failed\"`, + `revocation check by verification plugin "e2e-plugin" failed with reason "revocation check failed"`, VerifyFailed) }) }) @@ -108,7 +108,7 @@ var _ = Describe("notation plugin verify", func() { MatchErrKeyWords( "Plugin verify-signature request", "Plugin verify-signature response", - `trusted identify verification by plugin \"e2e-plugin\" failed with reason \"trusted identity check failed\"`, + `trusted identify verification by plugin "e2e-plugin" failed with reason "trusted identity check failed"`, VerifyFailed) }) }) @@ -138,7 +138,7 @@ var _ = Describe("notation plugin verify", func() { MatchErrKeyWords( "Plugin verify-signature request", "Plugin verify-signature response", - `{\"verificationResults\":{\"SIGNATURE_VERIFIER.REVOCATION_CHECK\":{\"success\":true},\"SIGNATURE_VERIFIER.TRUSTED_IDENTITY\":{\"success\":true}},\"processedAttributes\":null}`). + `{"verificationResults":{"SIGNATURE_VERIFIER.REVOCATION_CHECK":{"success":true},"SIGNATURE_VERIFIER.TRUSTED_IDENTITY":{"success":true}},"processedAttributes":null}`). MatchKeyWords(VerifySuccessfully) }) }) @@ -197,7 +197,7 @@ var _ = Describe("notation plugin verify", func() { MatchErrKeyWords( "Plugin verify-signature request", "Plugin verify-signature response", - `{\"verificationResults\":{\"SIGNATURE_VERIFIER.REVOCATION_CHECK\":{\"success\":true},\"SIGNATURE_VERIFIER.TRUSTED_IDENTITY\":{\"success\":true}},\"processedAttributes\":null}`). + `{"verificationResults":{"SIGNATURE_VERIFIER.REVOCATION_CHECK":{"success":true},"SIGNATURE_VERIFIER.TRUSTED_IDENTITY":{"success":true}},"processedAttributes":null}`). MatchKeyWords(VerifySuccessfully) }) }) diff --git a/test/e2e/suite/scenario/crl.go b/test/e2e/suite/scenario/crl.go new file mode 100644 index 000000000..0c09850ba --- /dev/null +++ b/test/e2e/suite/scenario/crl.go @@ -0,0 +1,315 @@ +// 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 scenario_test + +import ( + "context" + "net/http" + "os" + + crlcore "github.com/notaryproject/notation-core-go/revocation/crl" + "github.com/notaryproject/notation-go/verifier/crl" + . "github.com/notaryproject/notation/test/e2e/internal/notation" + "github.com/notaryproject/notation/test/e2e/internal/utils" + . "github.com/notaryproject/notation/test/e2e/suite/common" + . "github.com/onsi/ginkgo/v2" +) + +var _ = Describe("notation CRL revocation check", Serial, func() { + It("successfully completed with cache", func() { + Host(CRLOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("sign", artifact.ReferenceWithDigest()). + MatchKeyWords(SignSuccessfully) + + utils.LeafCRLUnrevoke() + utils.IntermediateCRLUnrevoke() + + // verify without cache + notation.Exec("verify", artifact.ReferenceWithDigest(), "-d"). + MatchKeyWords( + VerifySuccessfully, + ). + MatchErrKeyWords( + "CRL file cache miss", + "Retrieving crl bundle from file cache with key", + "Storing crl bundle to file cache with key", + "OCSP check failed with unknown error and fallback to CRL check for certificate #2", + ). + NoMatchErrKeyWords( + "is revoked", + ) + + // verify with cache + notation.Exec("verify", artifact.ReferenceWithDigest(), "-d"). + MatchKeyWords( + VerifySuccessfully, + ). + MatchErrKeyWords( + "Retrieving crl bundle from file cache with key", + "OCSP check failed with unknown error and fallback to CRL check for certificate #2", + ). + NoMatchErrKeyWords( + "CRL file cache miss", + "Storing crl bundle to file cache with key", + "is revoked", + ) + }) + }) + + It("failed with revoked leaf certificate", func() { + Host(CRLOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("sign", artifact.ReferenceWithDigest()). + MatchKeyWords(SignSuccessfully) + + utils.LeafCRLRevoke() + utils.IntermediateCRLUnrevoke() + + // verify without cache + notation.ExpectFailure().Exec("verify", artifact.ReferenceWithDigest(), "-d"). + MatchErrKeyWords( + VerifyFailed, + "CRL file cache miss", + "Retrieving crl bundle from file cache with key", + "Storing crl bundle to file cache with key", + "is revoked", + "OCSP check failed with unknown error and fallback to CRL check for certificate #2", + ) + + // verify with cache + notation.ExpectFailure().Exec("verify", artifact.ReferenceWithDigest(), "-d"). + MatchErrKeyWords( + VerifyFailed, + "Retrieving crl bundle from file cache with key", + "is revoked", + "OCSP check failed with unknown error and fallback to CRL check for certificate #2", + ). + NoMatchErrKeyWords( + "CRL file cache miss", + "Storing crl bundle to file cache with key", + ) + }) + }) + + It("failed with revoked intermediate certificate", func() { + Host(CRLOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("sign", artifact.ReferenceWithDigest()). + MatchKeyWords(SignSuccessfully) + + utils.LeafCRLUnrevoke() + utils.IntermediateCRLRevoke() + + // verify without cache + notation.ExpectFailure().Exec("verify", artifact.ReferenceWithDigest(), "-d"). + MatchErrKeyWords( + VerifyFailed, + "CRL file cache miss", + "Retrieving crl bundle from file cache with key", + "Storing crl bundle to file cache with key", + "is revoked", + "OCSP check failed with unknown error and fallback to CRL check for certificate #2", + ) + + // verify with cache + notation.ExpectFailure().Exec("verify", artifact.ReferenceWithDigest(), "-d"). + MatchErrKeyWords( + VerifyFailed, + "Retrieving crl bundle from file cache with key", + "is revoked", + "OCSP check failed with unknown error and fallback to CRL check for certificate #2", + ). + NoMatchErrKeyWords( + "CRL file cache miss", + "Storing crl bundle to file cache with key", + ) + }) + }) + + It("successfully completed with cache creation error in warning message", func() { + Host(CRLOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("sign", artifact.ReferenceWithDigest()). + MatchKeyWords(SignSuccessfully) + + utils.LeafCRLUnrevoke() + utils.IntermediateCRLUnrevoke() + + if err := os.MkdirAll(vhost.AbsolutePath(".cache"), 0500); err != nil { + Fail(err.Error()) + } + defer os.Chmod(vhost.AbsolutePath(".cache"), 0700) + + // verify without cache + notation.Exec("verify", artifact.ReferenceWithDigest(), "-d"). + MatchKeyWords( + VerifySuccessfully, + ). + MatchErrKeyWords( + "Warning: failed to create crl file cache", + "OCSP check failed with unknown error and fallback to CRL check for certificate #2", + `"GET" "http://localhost:10086/intermediate.crl"`, + `"GET" "http://localhost:10086/leaf.crl"`, + ). + NoMatchErrKeyWords( + "is revoked", + ) + }) + }) + + It("failed with revoked leaf certificate and cache creation error in warning message", func() { + Host(CRLOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("sign", artifact.ReferenceWithDigest()). + MatchKeyWords(SignSuccessfully) + + utils.LeafCRLRevoke() + utils.IntermediateCRLUnrevoke() + + if err := os.MkdirAll(vhost.AbsolutePath(".cache"), 0500); err != nil { + Fail(err.Error()) + } + defer os.Chmod(vhost.AbsolutePath(".cache"), 0700) + + // verify without cache + notation.ExpectFailure().Exec("verify", artifact.ReferenceWithDigest(), "-d"). + MatchErrKeyWords( + VerifyFailed, + "Warning: failed to create crl file cache", + "OCSP check failed with unknown error and fallback to CRL check for certificate #2", + `"GET" "http://localhost:10086/intermediate.crl"`, + `"GET" "http://localhost:10086/leaf.crl"`, + "is revoked", + ) + }) + }) + + It("successfully completed with cache get and set error in debug log", func() { + Host(CRLOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + notation.Exec("sign", artifact.ReferenceWithDigest()). + MatchKeyWords(SignSuccessfully) + + utils.LeafCRLUnrevoke() + utils.IntermediateCRLUnrevoke() + + // verify without cache + notation.Exec("verify", artifact.ReferenceWithDigest(), "-d"). + MatchKeyWords( + VerifySuccessfully, + ). + MatchErrKeyWords( + "CRL file cache miss", + "Retrieving crl bundle from file cache with key", + "Storing crl bundle to file cache with key", + "OCSP check failed with unknown error and fallback to CRL check for certificate #2", + ). + NoMatchErrKeyWords( + "is revoked", + ) + + utils.LeafCRLRevoke() + if err := os.Chmod(vhost.AbsolutePath(".cache", "crl"), 0000); err != nil { + Fail(err.Error()) + } + defer os.Chmod(vhost.AbsolutePath(".cache", "crl"), 0700) + + // verify with cache error + notation.ExpectFailure().Exec("verify", artifact.ReferenceWithDigest(), "-d"). + MatchErrKeyWords( + VerifyFailed, + "failed to get crl bundle from file cache with key", + "failed to store crl bundle in file cache", + "/.cache/crl/eaf8bbfe35f6c2c8b136081de9a994f9515752b2e30b9a6889ae3128ea97656c: permission denied", + "OCSP check failed with unknown error and fallback to CRL check for certificate #2", + `"GET" "http://localhost:10086/intermediate.crl"`, + `"GET" "http://localhost:10086/leaf.crl"`, + "is revoked", + ) + }) + }) + + It("succesfully completed with the crl in the cache expired and a roundtrip", func() { + Host(CRLOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + ctx := context.Background() + notation.Exec("sign", artifact.ReferenceWithDigest()). + MatchKeyWords(SignSuccessfully) + + utils.LeafCRLExpired() + // write expired CRL cache + fetcher, err := crlcore.NewHTTPFetcher(http.DefaultClient) + if err != nil { + Fail(err.Error()) + } + fetcher.Cache, err = crl.NewFileCache(vhost.AbsolutePath(".cache", "crl")) + if err != nil { + Fail(err.Error()) + } + _, err = fetcher.Fetch(ctx, "http://localhost:10086/leaf.crl") + if err != nil { + Fail(err.Error()) + } + + utils.LeafCRLUnrevoke() + utils.IntermediateCRLUnrevoke() + // verify without cache + notation.Exec("verify", artifact.ReferenceWithDigest(), "-d"). + MatchKeyWords( + VerifySuccessfully, + ). + MatchErrKeyWords( + "CRL bundle retrieved from file cache has expired at 2023-12-25", + `"GET" "http://localhost:10086/leaf.crl"`, + "Retrieving crl bundle from file cache with key", + "Storing crl bundle to file cache with key", + "OCSP check failed with unknown error and fallback to CRL check for certificate #2", + ). + NoMatchErrKeyWords( + "is revoked", + ) + }) + }) + + It("failed with crl in the cache expired and a roundtrip to download a revoked crl", func() { + Host(CRLOptions(), func(notation *utils.ExecOpts, artifact *Artifact, vhost *utils.VirtualHost) { + ctx := context.Background() + notation.Exec("sign", artifact.ReferenceWithDigest()). + MatchKeyWords(SignSuccessfully) + + utils.LeafCRLExpired() + // write expired CRL cache + fetcher, err := crlcore.NewHTTPFetcher(http.DefaultClient) + if err != nil { + Fail(err.Error()) + } + fetcher.Cache, err = crl.NewFileCache(vhost.AbsolutePath(".cache", "crl")) + if err != nil { + Fail(err.Error()) + } + _, err = fetcher.Fetch(ctx, "http://localhost:10086/leaf.crl") + if err != nil { + Fail(err.Error()) + } + + utils.LeafCRLRevoke() + utils.IntermediateCRLUnrevoke() + // verify without cache + notation.ExpectFailure().Exec("verify", artifact.ReferenceWithDigest(), "-d"). + MatchErrKeyWords( + VerifyFailed, + "CRL bundle retrieved from file cache has expired at 2023-12-25", + `"GET" "http://localhost:10086/leaf.crl"`, + "Retrieving crl bundle from file cache with key", + "Storing crl bundle to file cache with key", + "OCSP check failed with unknown error and fallback to CRL check for certificate #2", + "is revoked", + ) + }) + }) +}) diff --git a/test/e2e/suite/trustpolicy/trust_store.go b/test/e2e/suite/trustpolicy/trust_store.go index 736917493..d01a2fae0 100644 --- a/test/e2e/suite/trustpolicy/trust_store.go +++ b/test/e2e/suite/trustpolicy/trust_store.go @@ -70,7 +70,7 @@ var _ = Describe("notation trust policy trust store test", func() { It("multiple trust stores", func() { Host(nil, func(notation *utils.ExecOpts, artifact1 *Artifact, vhost *utils.VirtualHost) { // artifact1 signed with new_e2e.crt - OldNotation(AuthOption("", ""), AddKeyOption("e2e.key", "new_e2e.crt")). + OldNotation(AuthOption("", ""), AddKeyOption(filepath.Join(NotationE2ELocalKeysDir, "e2e.key"), filepath.Join(NotationE2ELocalKeysDir, "new_e2e.crt"))). Exec("sign", artifact1.ReferenceWithDigest(), "-v"). MatchKeyWords(SignSuccessfully) diff --git a/test/e2e/suite/trustpolicy/trusted_identity.go b/test/e2e/suite/trustpolicy/trusted_identity.go index 80ca06214..e37637340 100644 --- a/test/e2e/suite/trustpolicy/trusted_identity.go +++ b/test/e2e/suite/trustpolicy/trusted_identity.go @@ -77,7 +77,7 @@ var _ = Describe("notation trust policy trusted identity test", func() { It("with multiple trusted identity", func() { Host(nil, func(notation *utils.ExecOpts, artifact1 *Artifact, vhost *utils.VirtualHost) { // artifact1 signed with new_e2e.crt - OldNotation(AuthOption("", ""), AddKeyOption("e2e.key", "new_e2e.crt")). + OldNotation(AuthOption("", ""), AddKeyOption(filepath.Join(NotationE2ELocalKeysDir, "e2e.key"), filepath.Join(NotationE2ELocalKeysDir, "new_e2e.crt"))). Exec("sign", artifact1.ReferenceWithDigest(), "-v"). MatchKeyWords(SignSuccessfully) diff --git a/test/e2e/testdata/config/crl/certchain_with_crl.pem b/test/e2e/testdata/config/crl/certchain_with_crl.pem new file mode 100644 index 000000000..e9acff468 --- /dev/null +++ b/test/e2e/testdata/config/crl/certchain_with_crl.pem @@ -0,0 +1,76 @@ +-----BEGIN CERTIFICATE----- +MIID6DCCAtCgAwIBAgICEAAwDQYJKoZIhvcNAQELBQAwbjELMAkGA1UEBhMCVVMx +DjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5MRUwEwYDVQQKDAxPcmdhbml6 +YXRpb24xEDAOBgNVBAsMB09yZ1VuaXQxFzAVBgNVBAMMDkludGVybWVkaWF0ZUNB +MCAXDTI0MTExMTA1MzA1MVoYDzIxMjQxMDE4MDUzMDUxWjBoMQswCQYDVQQGEwJV +UzEOMAwGA1UECAwFU3RhdGUxDTALBgNVBAcMBENpdHkxFTATBgNVBAoMDE9yZ2Fu +aXphdGlvbjEQMA4GA1UECwwHT3JnVW5pdDERMA8GA1UEAwwITGVhZkNlcnQwggEi +MA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDJEFmIvqnUe3iwJ7HFrgCAbnEf +dGG/8yRuPWxTDkeHYQl8pMag5ZeytvTJalO8gba3oK6QRxPYhlzM8i7Ik/R6FXf6 +ZhTGzO8rIRe4Sc5ibO5TJeyfxciwtWnK6RtQwDZu4fb4tNmqUg6ZqqPnq1K8ieZf +ROVWs9zglJj37SoLY+Caxj2VOm8/aB/2mF46kqGUCb56RRk1q87x8U8wOSNW6ono +XVu6zBqLNwx2RcqKdKApYtaitwKz9cuWPTDrUe4OfCWDSYiB48YY0jDcV27ed+K8 +VKy6jgUAsKkzPIf3RbEBuMD2mUybC0o0D9t0h/R7h0f8zXgkxkP4KXwmPRPvAgMB +AAGjgZMwgZAwDAYDVR0TAQH/BAIwADAOBgNVHQ8BAf8EBAMCB4AwMAYDVR0fBCkw +JzAloCOgIYYfaHR0cDovL2xvY2FsaG9zdDoxMDA4Ni9sZWFmLmNybDAdBgNVHQ4E +FgQU/kBZC5X59h9/r/npEe2JYotqXbYwHwYDVR0jBBgwFoAUbCnIbIecdpvXQrcQ +okSpumRjw+IwDQYJKoZIhvcNAQELBQADggEBAMlLKGXxQ9ENqG2+h83toBJvOmPs +iEOLIcgaIvbvrnIPjZNDDiLar5hX1LPhnj5yvjy7XzHGfmFJg2lP1wYpqfCXdX/4 +P0Yfl1iy6ELf2z+QzKSd0njnc3kIrb7S1yLmrtkFY75vBxnJlUUA7q05Qy95jcDZ +fIuH8kFKaLVoXbbkonSzz01tW7PNsYqrZXmXfacrLLH66B3rscJFsu0oruy25Opj ++yS+ySlp1aEdWURI6WBd/8P6wEvbqZP+wXJVsEEp21mX050J1ycmDOPExcYetUSN +rglPBogxoOZqU3IGx7SVq5ze8l1hepKULMjACqHgu9klGos64E4f+LMGcFs= +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIEszCCA5ugAwIBAgICEAIwDQYJKoZIhvcNAQELBQAwZjELMAkGA1UEBhMCVVMx +DjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5MRUwEwYDVQQKDAxPcmdhbml6 +YXRpb24xEDAOBgNVBAsMB09yZ1VuaXQxDzANBgNVBAMMBlJvb3RDQTAgFw0yNDEx +MTEwNTMwNTFaGA8yMTI0MTAxODA1MzA1MVowbjELMAkGA1UEBhMCVVMxDjAMBgNV +BAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5MRUwEwYDVQQKDAxPcmdhbml6YXRpb24x +EDAOBgNVBAsMB09yZ1VuaXQxFzAVBgNVBAMMDkludGVybWVkaWF0ZUNBMIIBIjAN +BgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2O2N81+L0bel+CkBWeBBMh8Z/BRs +NBAsHlake1UlnJ12z0slRaSQfBK0cAHeRDAqBO/VkTF7bwsRR/Ypu8FAc64ayTUq +wWjNq5MU0HW80CmjyrYeXIC/BfzIOZC50IoGbQKrfbeJyP5qDWc41mOeZdyJbXtA +si17Ilwj/Q+seA58HSyZU1Iop4NDktsQpOr+XE9IWauu8xGy+ScQ92/3p4tNXYGI +7mZ1d/gD0KXs9sQ2klhmaH5OvubCQUGi7OX/yQWtJOmLUW7t7Ha4gmQYSG8jxOeT +vlt9Gv0OdiSA/ZvGn7qJfZ9NrjVQtw5j3sAxepNmoe3oh8lMZ/0ACevtcwIDAQAB +o4IBXzCCAVswEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwHQYD +VR0OBBYEFGwpyGyHnHab10K3EKJEqbpkY8PiMIGjBgNVHSMEgZswgZiAFKytgq/A +6Ar+6PeejGL+3SunIW8QoWqkaDBmMQswCQYDVQQGEwJVUzEOMAwGA1UECAwFU3Rh +dGUxDTALBgNVBAcMBENpdHkxFTATBgNVBAoMDE9yZ2FuaXphdGlvbjEQMA4GA1UE +CwwHT3JnVW5pdDEPMA0GA1UEAwwGUm9vdENBghQzVmwrGMBu11fJ0xRPTvXlgfJL +MzA4BgNVHR8EMTAvMC2gK6AphidodHRwOi8vbG9jYWxob3N0OjEwMDg2L2ludGVy +bWVkaWF0ZS5jcmwwNgYIKwYBBQUHAQEEKjAoMCYGCCsGAQUFBzABhhpodHRwOi8v +bG9jYWxob3N0LnRlc3Qvb2NzcDANBgkqhkiG9w0BAQsFAAOCAQEAHu/rr14Eo/GT +Hhcj10SL4wjXkKAMsXva6oUrD/z8nqRiFDy9pIavvQwdfeAVris9QcV+Z48Vl28w +OLH8AMahfNsQhjKxLB2ME1lJ3F6kMbnd4za4ZeeXykd5eswGD0PKnJb5aRYSHc5+ +OtS072Nt9qiyKtU++s0GAStx+0KnQ3r/3uTGpFgZNH+UKI5GxehW3v0iBlB/bZIP +YRCnhY82aDnR7ZEVXARyXDFX7obw4IBS3IqjnKndYtKwQOPKUzDTVPUhs7e9oetI +Y1YlZH3FJ9lBV+MxEEsmEu+TPhy+qRaqr0QHz/7tebdsMEB+v2ile7Y704AJVGnh +6g0n6AsHBQ== +-----END CERTIFICATE----- +-----BEGIN CERTIFICATE----- +MIIERjCCAy6gAwIBAgIUM1ZsKxjAbtdXydMUT0715YHySzMwDQYJKoZIhvcNAQEL +BQAwZjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5 +MRUwEwYDVQQKDAxPcmdhbml6YXRpb24xEDAOBgNVBAsMB09yZ1VuaXQxDzANBgNV +BAMMBlJvb3RDQTAgFw0yNDExMTEwNTMwNTFaGA8yMTI0MTAxODA1MzA1MVowZjEL +MAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5MRUwEwYD +VQQKDAxPcmdhbml6YXRpb24xEDAOBgNVBAsMB09yZ1VuaXQxDzANBgNVBAMMBlJv +b3RDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ46Go+Lo6yva6ZY +5N8UCkSt1nxnSfvwmSd358owqi6jO+hwv0jvrxSjzQyfke+tlfm3U/DLisyFOxny +RAYbhuM8PN5Fp3W5/og7nl5grhBQC3sps26QPVO7IvZBgfbkRCnC/LMdx4eeiUGZ +wc254KAh4/qYHMK+iqkAYg8DqLiWEhi1knYjNEWHCbeCnpj2vC+VhFNeTamR8bPd +U03xrZV9v/gZc3F+Ivwlxwb0QxDbXrYPc/5lixkQMYKQt8jzDl14TWeDbU589P31 +E3Y0CJSSDKczHXhh/cpN4lEGKircQynOdEEKf2z7FhvNVPH3tRh4ISmtl1lKrDk8 +drLBhKECAwEAAaOB6TCB5jAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUrK2Cr8DoCv7o956MYv7dK6chbxAwgaMGA1UdIwSBmzCBmIAU +rK2Cr8DoCv7o956MYv7dK6chbxChaqRoMGYxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI +DAVTdGF0ZTENMAsGA1UEBwwEQ2l0eTEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRAw +DgYDVQQLDAdPcmdVbml0MQ8wDQYDVQQDDAZSb290Q0GCFDNWbCsYwG7XV8nTFE9O +9eWB8kszMA0GCSqGSIb3DQEBCwUAA4IBAQArRoUqzUCjNaZWwtz8hhJYpKxrXK/M +MFsfj4FF6F9UgEZh+j9lAhQ1K9IoDKFKzcur3fO6dAPoWJm0P1vthCLMtFgeP7mm +d1H4BdtIiqWYTPtee8JgG2Mw8QdWaafb6WAdCOlAM01CWgR7aeL1cYDrarQLLXQ0 +KmbqNt4sPyv5orf/FjgHN8tUH2IKJo1NTrICmdP63Bal5kehh6lQYKytpmkqwcpA +HcagiCEvx5xWsZ/Mgnln8K8cg5xdV54bPssvxVPPKmLg/YzsqohjEiwsYoRBt4em +8Ul9fbaLugkoXtk7eCLpg7BJhhOOUZkiYjnmxZbkmVl7U79iFKrz73c5 +-----END CERTIFICATE----- diff --git a/test/e2e/testdata/config/crl/intermediate.crl b/test/e2e/testdata/config/crl/intermediate.crl new file mode 100644 index 000000000..9f71b046c Binary files /dev/null and b/test/e2e/testdata/config/crl/intermediate.crl differ diff --git a/test/e2e/testdata/config/crl/intermediate_revoked.crl b/test/e2e/testdata/config/crl/intermediate_revoked.crl new file mode 100644 index 000000000..b0bd1b6e5 Binary files /dev/null and b/test/e2e/testdata/config/crl/intermediate_revoked.crl differ diff --git a/test/e2e/testdata/config/crl/leaf.crl b/test/e2e/testdata/config/crl/leaf.crl new file mode 100644 index 000000000..4bff05c64 Binary files /dev/null and b/test/e2e/testdata/config/crl/leaf.crl differ diff --git a/test/e2e/testdata/config/crl/leaf.key b/test/e2e/testdata/config/crl/leaf.key new file mode 100644 index 000000000..f986032f6 --- /dev/null +++ b/test/e2e/testdata/config/crl/leaf.key @@ -0,0 +1,28 @@ +-----BEGIN PRIVATE KEY----- +MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDJEFmIvqnUe3iw +J7HFrgCAbnEfdGG/8yRuPWxTDkeHYQl8pMag5ZeytvTJalO8gba3oK6QRxPYhlzM +8i7Ik/R6FXf6ZhTGzO8rIRe4Sc5ibO5TJeyfxciwtWnK6RtQwDZu4fb4tNmqUg6Z +qqPnq1K8ieZfROVWs9zglJj37SoLY+Caxj2VOm8/aB/2mF46kqGUCb56RRk1q87x +8U8wOSNW6onoXVu6zBqLNwx2RcqKdKApYtaitwKz9cuWPTDrUe4OfCWDSYiB48YY +0jDcV27ed+K8VKy6jgUAsKkzPIf3RbEBuMD2mUybC0o0D9t0h/R7h0f8zXgkxkP4 +KXwmPRPvAgMBAAECggEAG511wUzNPuRNzAVKVX1pDzqxVHcjx9J+we9eFeg5AHSI +8jLKydAkLi+9CNQ5jQNUflMA4XW0WZcBXvAHvJUUTReZbhhK0+UowjKI3fmxHB6c +UGo93icy7GZLkfVt7YDWLmjgXAIG1ULw7hUcREDpG6u7ACxnwqlFyx34W9uZ3Iy3 +AICABJISJdxs7SGceFgmDUQluCQGeSA7Ma7ye3wEb9TqGcCwJyA/Ny2D3y9lztjB +CE/obwKVbWLAMRwHo/K/bhNR1A/HjfZVcWfA4TPlmpTTtnJjN/wipzLPBDqA77YW +YbASsCRD7rroQDfB0/kAQKq463/ckGQafaugx/zsWQKBgQDtRAOlWh4Dji4Py8Qf +DBvEcYfR41xYlJ9tV1LN4mWip8fujYRK2nExglpb0s7VqqNEhb0YhK8soMnR7DYE +Whd7wGfkCw0RJRbkQcKs0ZgHJSQDH6C8QPLjFx8sJ8y1gdgF5KapF1SZ22dEiA4F +zRB6u2M2Mhq+O0WSRuU8qj271wKBgQDY8JFUeAJ3jdSH7MtC6cps+yinXucCdKa5 +ktw8XF5wIZNWpZAkSuDKSZ14Mmet5yTvP+hKsVzbXtfDw3Ay3he23dD8khEa4p87 +k/3hED9yO8ERcl7myjJwKFo1LbZLKiZXUbrjT/APqPHeqqWChSEdElI4vWYZq3Ho +hLhh6JolqQKBgQC5ehHfkTMlVGBtuLz4CF8skhO64CGwnX6D21+/0tvg64g/1CE2 +4szaByzb21AVd+9qAaJxKEhIeulKUX1oqYTyGNceTgVJAdWDWmT09GQEMeSVDIR6 +pcs5+zlDK1m8CmT1NmmShcp8/CceS72qi0P2rcZA96owS+V3FDTf17WqwQKBgQCU +mCNTsmguL8311LJdgPoQr/BmxFCDlBdnYTrNdY+SSs07OmiDE27p4IamABCYQ40+ ++41HLDmoYUx1YPcHQK0JquItPnfM7JGZI4Nwl8p9moRiSO7MMo9d16YCau9EiPh+ +MxNKBEUw1M3ncQexYTMPUK9VAhZfWtnJJK+PEN4VEQKBgQCqF68DEkLQPwZaf9WE +zMprwZZ6bUhQmwp1TqKgW7OcgHCDzbMnYGRMgChtg6hZkFyyQN9aFj0ki66XI449 +DSH8fb4mIkdL1pP4FkHClKyTYE6SbMYWhFEJrUdrZ4QwktUm/e68w/op2B7v2fup +q9wlKAeblH73bGWHEs6+QfMVLA== +-----END PRIVATE KEY----- diff --git a/test/e2e/testdata/config/crl/leaf_expired.crl b/test/e2e/testdata/config/crl/leaf_expired.crl new file mode 100644 index 000000000..8e526887d Binary files /dev/null and b/test/e2e/testdata/config/crl/leaf_expired.crl differ diff --git a/test/e2e/testdata/config/crl/leaf_revoked.crl b/test/e2e/testdata/config/crl/leaf_revoked.crl new file mode 100644 index 000000000..a7ee7ff48 Binary files /dev/null and b/test/e2e/testdata/config/crl/leaf_revoked.crl differ diff --git a/test/e2e/testdata/config/crl/root.crt b/test/e2e/testdata/config/crl/root.crt new file mode 100644 index 000000000..a3008bfff --- /dev/null +++ b/test/e2e/testdata/config/crl/root.crt @@ -0,0 +1,25 @@ +-----BEGIN CERTIFICATE----- +MIIERjCCAy6gAwIBAgIUM1ZsKxjAbtdXydMUT0715YHySzMwDQYJKoZIhvcNAQEL +BQAwZjELMAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5 +MRUwEwYDVQQKDAxPcmdhbml6YXRpb24xEDAOBgNVBAsMB09yZ1VuaXQxDzANBgNV +BAMMBlJvb3RDQTAgFw0yNDExMTEwNTMwNTFaGA8yMTI0MTAxODA1MzA1MVowZjEL +MAkGA1UEBhMCVVMxDjAMBgNVBAgMBVN0YXRlMQ0wCwYDVQQHDARDaXR5MRUwEwYD +VQQKDAxPcmdhbml6YXRpb24xEDAOBgNVBAsMB09yZ1VuaXQxDzANBgNVBAMMBlJv +b3RDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJ46Go+Lo6yva6ZY +5N8UCkSt1nxnSfvwmSd358owqi6jO+hwv0jvrxSjzQyfke+tlfm3U/DLisyFOxny +RAYbhuM8PN5Fp3W5/og7nl5grhBQC3sps26QPVO7IvZBgfbkRCnC/LMdx4eeiUGZ +wc254KAh4/qYHMK+iqkAYg8DqLiWEhi1knYjNEWHCbeCnpj2vC+VhFNeTamR8bPd +U03xrZV9v/gZc3F+Ivwlxwb0QxDbXrYPc/5lixkQMYKQt8jzDl14TWeDbU589P31 +E3Y0CJSSDKczHXhh/cpN4lEGKircQynOdEEKf2z7FhvNVPH3tRh4ISmtl1lKrDk8 +drLBhKECAwEAAaOB6TCB5jAPBgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIB +BjAdBgNVHQ4EFgQUrK2Cr8DoCv7o956MYv7dK6chbxAwgaMGA1UdIwSBmzCBmIAU +rK2Cr8DoCv7o956MYv7dK6chbxChaqRoMGYxCzAJBgNVBAYTAlVTMQ4wDAYDVQQI +DAVTdGF0ZTENMAsGA1UEBwwEQ2l0eTEVMBMGA1UECgwMT3JnYW5pemF0aW9uMRAw +DgYDVQQLDAdPcmdVbml0MQ8wDQYDVQQDDAZSb290Q0GCFDNWbCsYwG7XV8nTFE9O +9eWB8kszMA0GCSqGSIb3DQEBCwUAA4IBAQArRoUqzUCjNaZWwtz8hhJYpKxrXK/M +MFsfj4FF6F9UgEZh+j9lAhQ1K9IoDKFKzcur3fO6dAPoWJm0P1vthCLMtFgeP7mm +d1H4BdtIiqWYTPtee8JgG2Mw8QdWaafb6WAdCOlAM01CWgR7aeL1cYDrarQLLXQ0 +KmbqNt4sPyv5orf/FjgHN8tUH2IKJo1NTrICmdP63Bal5kehh6lQYKytpmkqwcpA +HcagiCEvx5xWsZ/Mgnln8K8cg5xdV54bPssvxVPPKmLg/YzsqohjEiwsYoRBt4em +8Ul9fbaLugkoXtk7eCLpg7BJhhOOUZkiYjnmxZbkmVl7U79iFKrz73c5 +-----END CERTIFICATE-----