From b95c1d54d503d5776fa34e63dd4a9a1a4f397240 Mon Sep 17 00:00:00 2001 From: AdamKorcz <44787359+AdamKorcz@users.noreply.github.com> Date: Sun, 29 Sep 2024 22:11:20 +0100 Subject: [PATCH 01/15] test: add fuzz test (#459) Adds a fuzz test from cncf-fuzzing: https://github.com/cncf/cncf-fuzzing/blob/main/projects/notary/fuzz_pkix_test.go Signed-off-by: Adam Korczynski Signed-off-by: Patrick Zheng --- internal/pkix/fuzz_test.go | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 internal/pkix/fuzz_test.go diff --git a/internal/pkix/fuzz_test.go b/internal/pkix/fuzz_test.go new file mode 100644 index 00000000..2f6a6cc3 --- /dev/null +++ b/internal/pkix/fuzz_test.go @@ -0,0 +1,24 @@ +// 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 pkix + +import ( + "testing" +) + +func FuzzParseDistinguishedName(f *testing.F) { + f.Fuzz(func(t *testing.T, name string) { + _, _ = ParseDistinguishedName(name) + }) +} From 29912acbfea764a212720e40b599c63519073ee3 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 1 Oct 2024 05:48:38 +0000 Subject: [PATCH 02/15] build(deps): bump github.com/veraison/go-cose from 1.1.0 to 1.3.0 (#467) Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a3c819e6..3ebdab9c 100644 --- a/go.mod +++ b/go.mod @@ -9,7 +9,7 @@ require ( github.com/notaryproject/tspclient-go v0.2.0 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 - github.com/veraison/go-cose v1.1.0 + github.com/veraison/go-cose v1.3.0 golang.org/x/crypto v0.27.0 golang.org/x/mod v0.21.0 oras.land/oras-go/v2 v2.5.0 diff --git a/go.sum b/go.sum index 87b2a338..af608f87 100644 --- a/go.sum +++ b/go.sum @@ -52,8 +52,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= From 3c3302258ad510fbca2f8a73731569d91f07d196 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Wed, 23 Oct 2024 02:59:09 +0000 Subject: [PATCH 03/15] fix: OS error when setting CRL cache leads to denial of signature verification Signed-off-by: Junjie Gao Signed-off-by: Patrick Zheng --- internal/file/file.go | 11 +++++++++-- internal/file/file_test.go | 14 +++++++------- verifier/crl/crl.go | 2 +- 3 files changed, 17 insertions(+), 10 deletions(-) diff --git a/internal/file/file.go b/internal/file/file.go index c6e95849..464db1cc 100644 --- a/internal/file/file.go +++ b/internal/file/file.go @@ -119,8 +119,15 @@ func TrimFileExtension(fileName string) string { // WriteFile writes content to a temporary file and moves it to path. // If path already exists and is a file, WriteFile overwrites it. -func WriteFile(path string, content []byte) (writeErr error) { - tempFile, err := os.CreateTemp("", tempFileNamePrefix) +// +// Parameters: +// - tempDir is the directory to create the temporary file. It should be +// in the same mount point as path. If tempDir is empty, the default +// directory for temporary files is used. +// - path is the destination file path. +// - content is the content to write. +func WriteFile(tempDir, path string, content []byte) (writeErr error) { + tempFile, err := os.CreateTemp(tempDir, tempFileNamePrefix) if err != nil { return fmt.Errorf("failed to create temp file: %w", err) } diff --git a/internal/file/file_test.go b/internal/file/file_test.go index 306a0a5b..aeeea399 100644 --- a/internal/file/file_test.go +++ b/internal/file/file_test.go @@ -30,7 +30,7 @@ func TestCopyToDir(t *testing.T) { if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil { t.Fatal(err) } - if err := WriteFile(filename, data); err != nil { + if err := WriteFile(tempDir, filename, data); err != nil { t.Fatal(err) } @@ -52,7 +52,7 @@ func TestCopyToDir(t *testing.T) { if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil { t.Fatal(err) } - if err := WriteFile(filename, data); err != nil { + if err := WriteFile(tempDir, filename, data); err != nil { t.Fatal(err) } @@ -87,7 +87,7 @@ func TestCopyToDir(t *testing.T) { if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil { t.Fatal(err) } - if err := WriteFile(filename, data); err != nil { + if err := WriteFile(tempDir, filename, data); err != nil { t.Fatal(err) } // forbid reading @@ -113,7 +113,7 @@ func TestCopyToDir(t *testing.T) { if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil { t.Fatal(err) } - if err := WriteFile(filename, data); err != nil { + if err := WriteFile(tempDir, filename, data); err != nil { t.Fatal(err) } // forbid dest directory operation @@ -139,7 +139,7 @@ func TestCopyToDir(t *testing.T) { if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil { t.Fatal(err) } - if err := WriteFile(filename, data); err != nil { + if err := WriteFile(tempDir, filename, data); err != nil { t.Fatal(err) } // forbid writing to destTempDir @@ -159,7 +159,7 @@ func TestCopyToDir(t *testing.T) { if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil { t.Fatal(err) } - if err := WriteFile(filename, data); err != nil { + if err := WriteFile(tempDir, filename, data); err != nil { t.Fatal(err) } @@ -192,7 +192,7 @@ func TestWriteFile(t *testing.T) { if err != nil { t.Fatal(err) } - err = WriteFile(filepath.Join(tempDir, "testFile"), content) + err = WriteFile(tempDir, filepath.Join(tempDir, "testFile"), content) if err == nil || !strings.Contains(err.Error(), "permission denied") { t.Fatalf("expected permission denied error, but got %s", err) } diff --git a/verifier/crl/crl.go b/verifier/crl/crl.go index 9ebd16db..170d80f3 100644 --- a/verifier/crl/crl.go +++ b/verifier/crl/crl.go @@ -144,7 +144,7 @@ func (c *FileCache) Set(ctx context.Context, url string, bundle *corecrl.Bundle) if err != nil { return fmt.Errorf("failed to store crl bundle in file cache: %w", err) } - if err := file.WriteFile(filepath.Join(c.root, c.fileName(url)), contentBytes); err != nil { + if err := file.WriteFile(c.root, filepath.Join(c.root, c.fileName(url)), contentBytes); err != nil { return fmt.Errorf("failed to store crl bundle in file cache: %w", err) } return nil From d66c7ab85786ab3c0ce22caed90ccd34a024dff0 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Sat, 2 Nov 2024 01:40:07 +0800 Subject: [PATCH 04/15] fix: added tsa trust store root cert validation (#471) This PR adds tsa trust store root cert validation while getting certificates from trust store. This is to fail fast if cert in TSA trust store is not a root CA certificate. Resolves #470 --------- Signed-off-by: Patrick Zheng --- .../test-mismatch/DigiCertTSARootSHA384.cer | Bin 0 -> 1428 bytes .../wabbit-networks.io.crt | 0 .../tsa/test-nonSelfIssued/nonSelfIssued.crt | Bin 0 -> 1309 bytes verifier/truststore/truststore.go | 20 +++++++++++++ verifier/truststore/truststore_test.go | 28 ++++++++++++++++++ 5 files changed, 48 insertions(+) create mode 100644 verifier/testdata/truststore/x509/tsa/test-mismatch/DigiCertTSARootSHA384.cer rename verifier/testdata/truststore/x509/tsa/{test-mismatch => test-nonCA}/wabbit-networks.io.crt (100%) create mode 100644 verifier/testdata/truststore/x509/tsa/test-nonSelfIssued/nonSelfIssued.crt diff --git a/verifier/testdata/truststore/x509/tsa/test-mismatch/DigiCertTSARootSHA384.cer b/verifier/testdata/truststore/x509/tsa/test-mismatch/DigiCertTSARootSHA384.cer new file mode 100644 index 0000000000000000000000000000000000000000..99bcc84b7e68b5b28e4444f6fa21bc7c2baf497d GIT binary patch literal 1428 zcmXqLVx3^n#9Xm}nTe5!Nq}{>bojhJMWaWS?0c7&m&O?IvTn?JkswJuAWqo zP1e*s_a@Ho#N;1}iL*^!vmT3k6D_sp^~v*R*O)lOZ>&mtSAN1{MOt|H{E&z~9_{V^ z%MEUZy*pJM`*`h1|G1~7&kaxCnjCkhufO5ewuv(wCR84-IKFM;k*!%07R&;@H?Ej3 z(PORc_}XMAFtK2DXp^JS_1i4PT6q&0YZQI1>{%zxTpC-EcGJqxWtOqSeva!=o=Xlr zTe%?p?h^Gq3;iv(3Py;3SBY`!Px*c@v!iTAnQdgOQ(1fG^vo)c4-XazNvF*!Id#ul z?m1ubx@TA3Pnu*k&-M<(6Ia#FZL?e?wd)Q{*>Wi{_qFlOqxZd87|ztnOg-HHU2)SU z!R@>2KV9u9&~Z#ywJ}-3WvWzJQr)+P4ZmNcEHl2?$^LNf_GivZBz7z-XMD&%g-20# zQ;4Q&XUw*5U*l71pZrEK z{)j?gcK*iIZQcHduDQm~Rrs?|?&yL3MH}n5)MkEtlBqvKR`=`8m78RrN;5GtGB7T7 zGH@{92PS7(VMfOPEUX61K+1p*B)|_6U;*Z-HUn7@pN~b1MdZ!($4!?CV^e(Y>!sU2 z-!)^M48K2eDg$OPU@Bu|*qwN@c4f{!@gozZ4=-HA(EB(ggFozi`MQFie`k5k+~v@ z;|G_o$XKF&XYNn+bq1|Fzoq+H+4VTN((ZIU8a!-?Xwiwjs2;$JM? zvV8rD@42RPYNEQXEwY&TxuW}v?-ZoX1m*e!D1M{-ku zW1+3RZ-H_fkJp{XOJ|IxwD59pPM7gN@Ge`S#Ng5cOA~=sMNvkM7okS?3O#RXhzIyS z+vj_+bj^iRza4itFI{!{FsqBdj@j%-zaF{nP!7&v%TEujciZY?pQjO3sdj0}ilph6 zfR&$*WHWvetKHnrfA0t)=$1ze_=^}`TkG{L*Rlgt&`^}&Rl)f&LXk-+o%1iN!lfsC)s~w6 z?Tp>inj~vqxWQ7QGU@KxG3!Bhh+^5 ouE}lQ!_OaFs=4ZwaQTyaJ&lTM*#+DM*S6cTUo72o{&QL#0GZBIfB*mh literal 0 HcmV?d00001 diff --git a/verifier/testdata/truststore/x509/tsa/test-mismatch/wabbit-networks.io.crt b/verifier/testdata/truststore/x509/tsa/test-nonCA/wabbit-networks.io.crt similarity index 100% rename from verifier/testdata/truststore/x509/tsa/test-mismatch/wabbit-networks.io.crt rename to verifier/testdata/truststore/x509/tsa/test-nonCA/wabbit-networks.io.crt diff --git a/verifier/testdata/truststore/x509/tsa/test-nonSelfIssued/nonSelfIssued.crt b/verifier/testdata/truststore/x509/tsa/test-nonSelfIssued/nonSelfIssued.crt new file mode 100644 index 0000000000000000000000000000000000000000..6ec500520a70677de8fe99e14e217bc41f44be7c GIT binary patch literal 1309 zcmXqLVwE&#Vs2c(%*4pV#Kf@BfR~L^tIebBJ1-+6H!Fidu_3nsCmVAp3!5-gXfTY! zA?1ek@jK>{V2`FRQ< zsl_DZmRk>LXCs%sMu?+!8w z3(n9`Ru})z-RGfBJbGt&RE}cm89ZKyUxgOqJ|X`#BG8w%=X5 z*Lr6svGv1%EMFrV3ud9h0Zc5{3C zn3+VjWQF`cXv_R-$6TQczGlxaeR_A#J-hzWe{*r>c;%dMKYrgyN_=_II>PBYU$1A{ z-6kiOeZaBb;Dk2&-uXUSz!>L)qojD8OVYJ_*lePM9Lbcw-^1*-xnqsldq~GG;QVzPXPmYkhC(3 zgn?KCb_LdK9NKJ*tgP&ej4b*Fx(3=Xz5!#Kd`3x0ft9{~YDHphK~Ab(a(=FUGAMb+ z=O-5z=o=V_flOBgxrWDp3#O5o137g8^BpjCH8P}koLt}Ovq4!=A$D&%OUIi@#goqo zmY+ZCZ#UU;0o%L&jcp?Ns_V|R={hnkyLii0?%cVXEnl>z>obIGb#J|FKPg4I`;opb ztLE$e^{2N@_Ihu-BOz58ipvCp#oN4t7=UB2WTT0J%Bm-DK>@2_>TPIEZolVq?r$B|oTW$ZNuw!{6^ zaUz;Fd++p|4_H#Orh4-B4X4Ukl<(xfNiw&&!`#aw(DhGX4PWtnk;IlD)~dFvtJIg= z71WcPca5z(E6X(2v{}mZTKVdElJ<&@lAVmo3_7p*?=@=`dgLDdbKuIuMpfJQ5t?$V zrW$!Y>-@gEZ04ps%b=tynrr5D21m6BT Date: Sun, 3 Nov 2024 20:19:01 +0800 Subject: [PATCH 05/15] chore: add crl cache debug logs (#473) Signed-off-by: Patrick Zheng --- verifier/crl/crl.go | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/verifier/crl/crl.go b/verifier/crl/crl.go index 170d80f3..f1e576b9 100644 --- a/verifier/crl/crl.go +++ b/verifier/crl/crl.go @@ -88,32 +88,38 @@ func (c *FileCache) Get(ctx context.Context, url string) (*corecrl.Bundle, error logger.Debugf("CRL file cache miss. Key %q does not exist", url) return nil, corecrl.ErrCacheMiss } + logger.Debugf("failed to get crl bundle from file cache with key %q: %w", url, err) return nil, fmt.Errorf("failed to get crl bundle from file cache with key %q: %w", url, err) } // decode content to crl Bundle var content fileCacheContent if err := json.Unmarshal(contentBytes, &content); err != nil { + logger.Debugf("failed to decode file retrieved from file cache: %w", err) return nil, fmt.Errorf("failed to decode file retrieved from file cache: %w", err) } var bundle corecrl.Bundle bundle.BaseCRL, err = x509.ParseRevocationList(content.BaseCRL) if err != nil { + logger.Debugf("failed to parse base CRL of file retrieved from file cache: %w", err) return nil, fmt.Errorf("failed to parse base CRL of file retrieved from file cache: %w", err) } if content.DeltaCRL != nil { bundle.DeltaCRL, err = x509.ParseRevocationList(content.DeltaCRL) if err != nil { + logger.Debugf("failed to parse delta CRL of file retrieved from file cache: %w", err) return nil, fmt.Errorf("failed to parse delta CRL of file retrieved from file cache: %w", err) } } // check expiry if err := checkExpiry(ctx, bundle.BaseCRL.NextUpdate); err != nil { + logger.Debugf("check BaseCRL expiry failed: %w", err) return nil, err } if bundle.DeltaCRL != nil { if err := checkExpiry(ctx, bundle.DeltaCRL.NextUpdate); err != nil { + logger.Debugf("check DeltaCRL expiry failed: %w", err) return nil, err } } @@ -127,9 +133,11 @@ func (c *FileCache) Set(ctx context.Context, url string, bundle *corecrl.Bundle) logger.Debugf("Storing crl bundle to file cache with key %q ...", url) if bundle == nil { + logger.Debugln("failed to store crl bundle in file cache: bundle cannot be nil") return errors.New("failed to store crl bundle in file cache: bundle cannot be nil") } if bundle.BaseCRL == nil { + logger.Debugln("failed to store crl bundle in file cache: bundle BaseCRL cannot be nil") return errors.New("failed to store crl bundle in file cache: bundle BaseCRL cannot be nil") } @@ -142,9 +150,11 @@ func (c *FileCache) Set(ctx context.Context, url string, bundle *corecrl.Bundle) } contentBytes, err := json.Marshal(content) if err != nil { + logger.Debugf("failed to store crl bundle in file cache: %w", err) return fmt.Errorf("failed to store crl bundle in file cache: %w", err) } if err := file.WriteFile(c.root, filepath.Join(c.root, c.fileName(url)), contentBytes); err != nil { + logger.Debugf("failed to store crl bundle in file cache: %w", err) return fmt.Errorf("failed to store crl bundle in file cache: %w", err) } return nil From 0c84a376a5858518d8bc329912792836d7e23323 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 04:44:48 +0000 Subject: [PATCH 06/15] build(deps): bump golang.org/x/crypto from 0.27.0 to 0.28.0 (#468) Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 3ebdab9c..bb911658 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/veraison/go-cose v1.3.0 - golang.org/x/crypto v0.27.0 + golang.org/x/crypto v0.28.0 golang.org/x/mod v0.21.0 oras.land/oras-go/v2 v2.5.0 ) diff --git a/go.sum b/go.sum index af608f87..68396e3f 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,8 @@ 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.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= +golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= 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= From c32fb1aa7a5638756820777e2ac1f5129fde27e4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 17:42:01 +0000 Subject: [PATCH 07/15] build(deps): bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1 (#474) Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index bb911658..83391e78 100644 --- a/go.mod +++ b/go.mod @@ -19,7 +19,7 @@ require ( github.com/Azure/go-ntlmssp v0.0.0-20221128193559-754e69321358 // indirect github.com/fxamacker/cbor/v2 v2.7.0 // indirect github.com/go-asn1-ber/asn1-ber v1.5.5 // indirect - github.com/golang-jwt/jwt/v4 v4.5.0 // indirect + github.com/golang-jwt/jwt/v4 v4.5.1 // indirect github.com/google/uuid v1.6.0 // indirect github.com/x448/float16 v0.8.4 // indirect golang.org/x/sync v0.6.0 // indirect diff --git a/go.sum b/go.sum index 68396e3f..12343ed8 100644 --- a/go.sum +++ b/go.sum @@ -11,8 +11,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= From 5395b659c4fa8c5ccfb78a93ffc8e46fc057675b Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Nov 2024 17:44:50 +0000 Subject: [PATCH 08/15] build(deps): bump golang.org/x/crypto from 0.28.0 to 0.29.0 (#476) Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index 83391e78..eb9bd988 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/veraison/go-cose v1.3.0 - golang.org/x/crypto v0.28.0 + golang.org/x/crypto v0.29.0 golang.org/x/mod v0.21.0 oras.land/oras-go/v2 v2.5.0 ) diff --git a/go.sum b/go.sum index 12343ed8..0131e998 100644 --- a/go.sum +++ b/go.sum @@ -62,8 +62,8 @@ 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.28.0 h1:GBDwsMXVQi34v5CCYUm2jkJvu4cbtru2U4TN2PSyQnw= -golang.org/x/crypto v0.28.0/go.mod h1:rmgy+3RHxRZMyY0jjAJShp2zgEdOqj2AO7U0pYmeQ7U= +golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= +golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= From e277e402ba3b99089acc9a3ebf3fcd11271d8cf2 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Tue, 12 Nov 2024 07:51:07 +0800 Subject: [PATCH 09/15] fix: crl cache log and err msg (#475) Signed-off-by: Patrick Zheng --- verifier/crl/crl.go | 14 ++------------ verifier/crl/crl_test.go | 2 +- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/verifier/crl/crl.go b/verifier/crl/crl.go index f1e576b9..d7fdc27f 100644 --- a/verifier/crl/crl.go +++ b/verifier/crl/crl.go @@ -88,39 +88,33 @@ func (c *FileCache) Get(ctx context.Context, url string) (*corecrl.Bundle, error logger.Debugf("CRL file cache miss. Key %q does not exist", url) return nil, corecrl.ErrCacheMiss } - logger.Debugf("failed to get crl bundle from file cache with key %q: %w", url, err) return nil, fmt.Errorf("failed to get crl bundle from file cache with key %q: %w", url, err) } // decode content to crl Bundle var content fileCacheContent if err := json.Unmarshal(contentBytes, &content); err != nil { - logger.Debugf("failed to decode file retrieved from file cache: %w", err) return nil, fmt.Errorf("failed to decode file retrieved from file cache: %w", err) } var bundle corecrl.Bundle bundle.BaseCRL, err = x509.ParseRevocationList(content.BaseCRL) if err != nil { - logger.Debugf("failed to parse base CRL of file retrieved from file cache: %w", err) return nil, fmt.Errorf("failed to parse base CRL of file retrieved from file cache: %w", err) } if content.DeltaCRL != nil { bundle.DeltaCRL, err = x509.ParseRevocationList(content.DeltaCRL) if err != nil { - logger.Debugf("failed to parse delta CRL of file retrieved from file cache: %w", err) return nil, fmt.Errorf("failed to parse delta CRL of file retrieved from file cache: %w", err) } } // check expiry if err := checkExpiry(ctx, bundle.BaseCRL.NextUpdate); err != nil { - logger.Debugf("check BaseCRL expiry failed: %w", err) - return nil, err + return nil, fmt.Errorf("check BaseCRL expiry failed: %w", err) } if bundle.DeltaCRL != nil { if err := checkExpiry(ctx, bundle.DeltaCRL.NextUpdate); err != nil { - logger.Debugf("check DeltaCRL expiry failed: %w", err) - return nil, err + return nil, fmt.Errorf("check DeltaCRL expiry failed: %w", err) } } @@ -133,11 +127,9 @@ func (c *FileCache) Set(ctx context.Context, url string, bundle *corecrl.Bundle) logger.Debugf("Storing crl bundle to file cache with key %q ...", url) if bundle == nil { - logger.Debugln("failed to store crl bundle in file cache: bundle cannot be nil") return errors.New("failed to store crl bundle in file cache: bundle cannot be nil") } if bundle.BaseCRL == nil { - logger.Debugln("failed to store crl bundle in file cache: bundle BaseCRL cannot be nil") return errors.New("failed to store crl bundle in file cache: bundle BaseCRL cannot be nil") } @@ -150,11 +142,9 @@ func (c *FileCache) Set(ctx context.Context, url string, bundle *corecrl.Bundle) } contentBytes, err := json.Marshal(content) if err != nil { - logger.Debugf("failed to store crl bundle in file cache: %w", err) return fmt.Errorf("failed to store crl bundle in file cache: %w", err) } if err := file.WriteFile(c.root, filepath.Join(c.root, c.fileName(url)), contentBytes); err != nil { - logger.Debugf("failed to store crl bundle in file cache: %w", err) return fmt.Errorf("failed to store crl bundle in file cache: %w", err) } return nil diff --git a/verifier/crl/crl_test.go b/verifier/crl/crl_test.go index 6eafca3c..1d1a9dce 100644 --- a/verifier/crl/crl_test.go +++ b/verifier/crl/crl_test.go @@ -270,7 +270,7 @@ func TestGetFailed(t *testing.T) { t.Fatal(err) } _, err = cache.Get(ctx, "expiredKey") - expectedErrMsg := "crl bundle retrieved from file cache does not contain valid NextUpdate" + expectedErrMsg := "check BaseCRL expiry failed: crl bundle retrieved from file cache does not contain valid NextUpdate" if err == nil || err.Error() != expectedErrMsg { t.Fatalf("expected %s, but got %v", expectedErrMsg, err) } From 5384dde419424c7c38ff7c4e1dfd0d674319c156 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 14 Nov 2024 19:03:25 +0000 Subject: [PATCH 10/15] build(deps): bump golang.org/x/mod from 0.21.0 to 0.22.0 (#477) Signed-off-by: Patrick Zheng --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index eb9bd988..4c1e49e8 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/opencontainers/image-spec v1.1.0 github.com/veraison/go-cose v1.3.0 golang.org/x/crypto v0.29.0 - golang.org/x/mod v0.21.0 + golang.org/x/mod v0.22.0 oras.land/oras-go/v2 v2.5.0 ) diff --git a/go.sum b/go.sum index 0131e998..6f3a98cf 100644 --- a/go.sum +++ b/go.sum @@ -66,8 +66,8 @@ golang.org/x/crypto v0.29.0 h1:L5SG1JTTXupVV3n6sUqMTeWbjAyfPwoda2DLX8J8FrQ= golang.org/x/crypto v0.29.0/go.mod h1:+F4F4N5hv6v38hfeYwTdx20oUvLLc+QfrE9Ax9HtgRg= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= -golang.org/x/mod v0.21.0 h1:vvrHzRwRfVKSiLrG+d4FMl/Qi4ukBCE6kZlTUkDYRT0= -golang.org/x/mod v0.21.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= +golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= +golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20200114155413-6afb5195e5aa/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= From 2307de5f297b54486a94eb2b9fa7b36c990ec898 Mon Sep 17 00:00:00 2001 From: Pritesh Bandi Date: Thu, 14 Nov 2024 11:06:45 -0800 Subject: [PATCH 11/15] chore: Improve error message in case of plugin timeout (#472) When a plugin exceeds the specified timeout or deadline for content processing, the current error message displayed is ```signal: killed```. This PR updates the error message to a more informative message: ```[plugin_name] [command_name] command execution timeout: signal: killed``` --------- Signed-off-by: Pritesh Bandi Signed-off-by: Patrick Zheng --- plugin/plugin.go | 3 +++ plugin/plugin_test.go | 23 ++++++++++++++++++++++- 2 files changed, 25 insertions(+), 1 deletion(-) diff --git a/plugin/plugin.go b/plugin/plugin.go index e4579d85..71a8c895 100644 --- a/plugin/plugin.go +++ b/plugin/plugin.go @@ -226,6 +226,9 @@ func (c execCommander) Output(ctx context.Context, name string, command plugin.C cmd.Stdout = &stdout err := cmd.Run() if err != nil { + if errors.Is(ctx.Err(), context.DeadlineExceeded) { + return nil, stderr.Bytes(), fmt.Errorf("'%s %s' command execution timeout: %w", name, string(command), err); + } return nil, stderr.Bytes(), err } return stdout.Bytes(), nil, nil diff --git a/plugin/plugin_test.go b/plugin/plugin_test.go index 171767b8..fc77d13a 100644 --- a/plugin/plugin_test.go +++ b/plugin/plugin_test.go @@ -19,9 +19,11 @@ import ( "errors" "os" "reflect" + "runtime" "strconv" "strings" "testing" + "time" "github.com/notaryproject/notation-go/plugin/proto" ) @@ -181,7 +183,7 @@ func TestValidateMetadata(t *testing.T) { } } -func TestNewCLIPlugin_PathError(t *testing.T) { +func TestNewCLIPlugin_Error(t *testing.T) { ctx := context.Background() t.Run("plugin directory exists without executable.", func(t *testing.T) { p, err := NewCLIPlugin(ctx, "emptyplugin", "./testdata/plugins/emptyplugin/notation-emptyplugin") @@ -203,6 +205,25 @@ func TestNewCLIPlugin_PathError(t *testing.T) { t.Errorf("NewCLIPlugin() plugin = %v, want nil", p) } }) + + t.Run("plugin timeout error", func(t *testing.T) { + if runtime.GOOS == "windows" { + t.Skip("skipping test on Windows") + } + expectedErrMsg := "'sleep 2' command execution timeout: signal: killed" + ctxWithTimout, cancel := context.WithTimeout(ctx, 10 * time.Millisecond) + defer cancel() + + var twoSeconds proto.Command + twoSeconds = "2" + _, _, err := execCommander{}.Output(ctxWithTimout, "sleep", twoSeconds, nil); + if err == nil { + t.Errorf("execCommander{}.Output() expected error = %v, got nil", expectedErrMsg) + } + if err.Error() != expectedErrMsg { + t.Errorf("execCommander{}.Output() error = %v, want %v", err, expectedErrMsg) + } + }) } func TestNewCLIPlugin_ValidError(t *testing.T) { From ffc04d8aa8e7d725092eacb11141212425fff21e Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Fri, 15 Nov 2024 16:09:00 +0800 Subject: [PATCH 12/15] fix: timestamping (#478) Signed-off-by: Patrick Zheng Co-authored-by: Pritesh Bandi Signed-off-by: Patrick Zheng --- go.mod | 4 ++-- go.sum | 8 ++++---- verifier/timestamp_test.go | 25 ++++++++++++++++++++++++- verifier/verifier.go | 3 +++ 4 files changed, 33 insertions(+), 7 deletions(-) diff --git a/go.mod b/go.mod index 4c1e49e8..71bdf92e 100644 --- a/go.mod +++ b/go.mod @@ -4,9 +4,9 @@ go 1.22.0 require ( github.com/go-ldap/ldap/v3 v3.4.8 - github.com/notaryproject/notation-core-go v1.2.0-rc.1 + github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241112001243-33af15a18954 github.com/notaryproject/notation-plugin-framework-go v1.0.0 - github.com/notaryproject/tspclient-go v0.2.0 + github.com/notaryproject/tspclient-go v0.2.1-0.20241030015323-90a141e7525c github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.1.0 github.com/veraison/go-cose v1.3.0 diff --git a/go.sum b/go.sum index 6f3a98cf..deea61a7 100644 --- a/go.sum +++ b/go.sum @@ -32,12 +32,12 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6 github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/notaryproject/notation-core-go v1.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-core-go v1.2.0-rc.1.0.20241112001243-33af15a18954 h1:UbjH/ePjxU8jcYMca9NVYqU8Qcr7pP1SKDWCxl++ToA= +github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241112001243-33af15a18954/go.mod h1:phjvE2bqHsLfJMqMUYqRCqNIH3TQ4GCcFQuEVyQTpDg= github.com/notaryproject/notation-plugin-framework-go v1.0.0 h1:6Qzr7DGXoCgXEQN+1gTZWuJAZvxh3p8Lryjn5FaLzi4= github.com/notaryproject/notation-plugin-framework-go v1.0.0/go.mod h1:RqWSrTOtEASCrGOEffq0n8pSg2KOgKYiWqFWczRSics= -github.com/notaryproject/tspclient-go v0.2.0 h1:g/KpQGmyk/h7j60irIRG1mfWnibNOzJ8WhLqAzuiQAQ= -github.com/notaryproject/tspclient-go v0.2.0/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= +github.com/notaryproject/tspclient-go v0.2.1-0.20241030015323-90a141e7525c h1:bX6gGxFw9+DShmYTgbD+vr6neF1SoXIMUU2fDgdLsfA= +github.com/notaryproject/tspclient-go v0.2.1-0.20241030015323-90a141e7525c/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug= diff --git a/verifier/timestamp_test.go b/verifier/timestamp_test.go index f7eb90ec..22c75660 100644 --- a/verifier/timestamp_test.go +++ b/verifier/timestamp_test.go @@ -216,7 +216,7 @@ func TestAuthenticTimestamp(t *testing.T) { VerificationLevel: trustpolicy.LevelStrict, } authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestampingValidator, outcome) - expectedErrMsg := "failed to parse timestamp countersignature with error: unexpected content type: 1.2.840.113549.1.7.1" + expectedErrMsg := "failed to parse timestamp countersignature with error: unexpected content type: 1.2.840.113549.1.7.1. Expected to be id-ct-TSTInfo (1.2.840.113549.1.9.16.1.4)" if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { t.Fatalf("expected %s, but got %s", expectedErrMsg, err) } @@ -287,6 +287,29 @@ func TestAuthenticTimestamp(t *testing.T) { } }) + t.Run("verify Authentic Timestamp failed due to signing time after timestamp value", func(t *testing.T) { + signedToken, err := os.ReadFile("testdata/timestamp/countersignature/TimeStampToken.p7s") + if err != nil { + t.Fatalf("failed to get signedToken: %v", err) + } + envContent, err := parseEnvContent("testdata/timestamp/sigEnv/withoutTimestamp.sig", jws.MediaTypeEnvelope) + if err != nil { + t.Fatalf("failed to get signature envelope content: %v", err) + } + envContent.SignerInfo.UnsignedAttributes.TimestampSignature = signedToken + envContent.SignerInfo.Signature = []byte("notation") + envContent.SignerInfo.SignedAttributes.SigningTime = time.Date(3000, time.November, 10, 23, 0, 0, 0, time.UTC) + outcome := ¬ation.VerificationOutcome{ + EnvelopeContent: envContent, + VerificationLevel: trustpolicy.LevelStrict, + } + authenticTimestampResult := verifyAuthenticTimestamp(context.Background(), dummyTrustPolicy.Name, dummyTrustPolicy.TrustStores, dummyTrustPolicy.SignatureVerification, trustStore, revocationTimestampingValidator, outcome) + expectedErrMsg := "timestamp [2021-09-17T14:09:09Z, 2021-09-17T14:09:11Z] is not bounded after the signing time \"3000-11-10 23:00:00 +0000 UTC\"" + if err := authenticTimestampResult.Error; err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } + }) + t.Run("verify Authentic Timestamp failed due to trust store does not exist", func(t *testing.T) { dummyTrustPolicy := &trustpolicy.TrustPolicy{ Name: "test-timestamp", diff --git a/verifier/verifier.go b/verifier/verifier.go index e852a96a..c97f079e 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -924,6 +924,9 @@ func verifyTimestamp(ctx context.Context, policyName string, trustStores []strin if err != nil { return fmt.Errorf("failed to verify the timestamp countersignature with error: %w", err) } + if !timestamp.BoundedAfter(signerInfo.SignedAttributes.SigningTime) { + return fmt.Errorf("timestamp %s is not bounded after the signing time %q", timestamp.Format(time.RFC3339), signerInfo.SignedAttributes.SigningTime) + } // 3. Validate timestamping certificate chain logger.Debug("Validating timestamping certificate chain...") From 0a9ff2a2e200ab9bf756d188f84607a83346d4a6 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Fri, 29 Nov 2024 08:38:08 +0800 Subject: [PATCH 13/15] fix: add warning message for non-revokable certificate (#479) Fix: - added warning message for non-revokable certificate --------- Signed-off-by: Junjie Gao Signed-off-by: Patrick Zheng --- verifier/verifier.go | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/verifier/verifier.go b/verifier/verifier.go index c97f079e..e1d06528 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -704,6 +704,10 @@ func revocationFinalResult(certResults []*revocationresult.CertRevocationResult, revokedCertSubject = problematicCertSubject } } + + if i < len(certResults)-1 && certResult.Result == revocationresult.ResultNonRevokable { + logger.Warnf("Certificate #%d in the chain with subject %v neither has an OCSP nor a CRL revocation method.", (i + 1), cert.Subject.String()) + } } if revokedFound { problematicCertSubject = revokedCertSubject From e7005a6d13e5ba472d4e166fbb085152f909e102 Mon Sep 17 00:00:00 2001 From: Patrick Zheng Date: Mon, 2 Dec 2024 08:30:56 +0800 Subject: [PATCH 14/15] fix: enable timestamping cert chain revocation check during signing (#482) Signed-off-by: Patrick Zheng --- .github/.codecov.yml | 3 +++ example_signWithTimestmap_test.go | 17 ++++++++++++++--- go.mod | 2 +- go.sum | 4 ++-- notation.go | 6 ++++++ signer/signer.go | 22 +++++++++++++--------- signer/signer_test.go | 23 +++++++++++++++++++++++ 7 files changed, 62 insertions(+), 15 deletions(-) diff --git a/.github/.codecov.yml b/.github/.codecov.yml index cb44908a..56e810e1 100644 --- a/.github/.codecov.yml +++ b/.github/.codecov.yml @@ -14,5 +14,8 @@ coverage: status: project: + default: + target: 80% + patch: default: target: 80% \ No newline at end of file diff --git a/example_signWithTimestmap_test.go b/example_signWithTimestmap_test.go index 8e0ebe5c..ef4eeb47 100644 --- a/example_signWithTimestmap_test.go +++ b/example_signWithTimestmap_test.go @@ -21,6 +21,8 @@ import ( "oras.land/oras-go/v2/registry/remote" + "github.com/notaryproject/notation-core-go/revocation" + "github.com/notaryproject/notation-core-go/revocation/purpose" "github.com/notaryproject/notation-core-go/testhelper" "github.com/notaryproject/notation-go" "github.com/notaryproject/notation-go/registry" @@ -77,12 +79,21 @@ func Example_signWithTimestamp() { tsaRootCAs := x509.NewCertPool() tsaRootCAs.AddCert(tsaRootCert) + // enable timestamping certificate chain revocation check + tsaRevocationValidator, err := revocation.NewWithOptions(revocation.Options{ + CertChainPurpose: purpose.Timestamping, + }) + if err != nil { + panic(err) // Handle error + } + // exampleSignOptions is an example of notation.SignOptions. exampleSignOptions := notation.SignOptions{ SignerSignOptions: notation.SignerSignOptions{ - SignatureMediaType: exampleSignatureMediaType, - Timestamper: httpTimestamper, - TSARootCAs: tsaRootCAs, + SignatureMediaType: exampleSignatureMediaType, + Timestamper: httpTimestamper, + TSARootCAs: tsaRootCAs, + TSARevocationValidator: tsaRevocationValidator, }, ArtifactReference: exampleArtifactReference, } diff --git a/go.mod b/go.mod index 71bdf92e..500bf084 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.22.0 require ( github.com/go-ldap/ldap/v3 v3.4.8 - github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241112001243-33af15a18954 + github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241129024749-95d89543c9f9 github.com/notaryproject/notation-plugin-framework-go v1.0.0 github.com/notaryproject/tspclient-go v0.2.1-0.20241030015323-90a141e7525c github.com/opencontainers/go-digest v1.0.0 diff --git a/go.sum b/go.sum index deea61a7..887c93a4 100644 --- a/go.sum +++ b/go.sum @@ -32,8 +32,8 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1:x1Sv4HaTpepFkXbt2IkL29DXRf8sOfZXo8eRKh6 github.com/jcmturner/gokrb5/v8 v8.4.4/go.mod h1:1btQEpgT6k+unzCwX1KdWMEwPPkkgBtP+F6aCACiMrs= github.com/jcmturner/rpc/v2 v2.0.3 h1:7FXXj8Ti1IaVFpSAziCZWNzbNuZmnvw/i6CqLNdWfZY= github.com/jcmturner/rpc/v2 v2.0.3/go.mod h1:VUJYCIDm3PVOEHw8sgt091/20OJjskO/YJki3ELg/Hc= -github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241112001243-33af15a18954 h1:UbjH/ePjxU8jcYMca9NVYqU8Qcr7pP1SKDWCxl++ToA= -github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241112001243-33af15a18954/go.mod h1:phjvE2bqHsLfJMqMUYqRCqNIH3TQ4GCcFQuEVyQTpDg= +github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241129024749-95d89543c9f9 h1:FURo9xpGLKmghWCcWypCPQTlcOGKxzayeXacGfb8WUU= +github.com/notaryproject/notation-core-go v1.2.0-rc.1.0.20241129024749-95d89543c9f9/go.mod h1:Umjn4NKGmuHpVffMgKVcUnArNG3Qtd3duKYpPILUBg4= 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.1-0.20241030015323-90a141e7525c h1:bX6gGxFw9+DShmYTgbD+vr6neF1SoXIMUU2fDgdLsfA= diff --git a/notation.go b/notation.go index d64fd2cf..bb051d13 100644 --- a/notation.go +++ b/notation.go @@ -29,6 +29,7 @@ import ( orasRegistry "oras.land/oras-go/v2/registry" "oras.land/oras-go/v2/registry/remote" + "github.com/notaryproject/notation-core-go/revocation" "github.com/notaryproject/notation-core-go/signature" "github.com/notaryproject/notation-core-go/signature/cose" "github.com/notaryproject/notation-core-go/signature/jws" @@ -67,6 +68,11 @@ type SignerSignOptions struct { // TSARootCAs is the cert pool holding caller's TSA trust anchor TSARootCAs *x509.CertPool + + // TSARevocationValidator is used for validating revocation status of + // timestamping certificate chain with context during signing. + // When present, only used when timestamping is performed. + TSARevocationValidator revocation.Validator } // Signer is a generic interface for signing an OCI artifact. diff --git a/signer/signer.go b/signer/signer.go index 242c862e..1f7fe567 100644 --- a/signer/signer.go +++ b/signer/signer.go @@ -107,7 +107,6 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts if err != nil { return nil, nil, fmt.Errorf("envelope payload can't be marshalled: %w", err) } - var signingAgentId string if opts.SigningAgent != "" { signingAgentId = opts.SigningAgent @@ -125,12 +124,13 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts ContentType: envelope.MediaTypePayloadV1, Content: payloadBytes, }, - Signer: s.signer, - SigningTime: time.Now(), - SigningScheme: signature.SigningSchemeX509, - SigningAgent: signingAgentId, - Timestamper: opts.Timestamper, - TSARootCAs: opts.TSARootCAs, + Signer: s.signer, + SigningTime: time.Now(), + SigningScheme: signature.SigningSchemeX509, + SigningAgent: signingAgentId, + Timestamper: opts.Timestamper, + TSARootCAs: opts.TSARootCAs, + TSARevocationValidator: opts.TSARevocationValidator, } // Add expiry only if ExpiryDuration is not zero @@ -144,6 +144,12 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts logger.Debugf(" Expiry: %v", signReq.Expiry) logger.Debugf(" SigningScheme: %v", signReq.SigningScheme) logger.Debugf(" SigningAgent: %v", signReq.SigningAgent) + if signReq.Timestamper != nil { + logger.Debug("Enabled timestamping") + if signReq.TSARevocationValidator != nil { + logger.Debug("Enabled timestamping certificate chain revocation check") + } + } // Add ctx to the SignRequest signReq = signReq.WithContext(ctx) @@ -153,12 +159,10 @@ func (s *GenericSigner) Sign(ctx context.Context, desc ocispec.Descriptor, opts if err != nil { return nil, nil, err } - sig, err := sigEnv.Sign(signReq) if err != nil { return nil, nil, err } - envContent, err := sigEnv.Verify() if err != nil { return nil, nil, fmt.Errorf("generated signature failed verification: %v", err) diff --git a/signer/signer_test.go b/signer/signer_test.go index 1dac5ebe..a2f8848f 100644 --- a/signer/signer_test.go +++ b/signer/signer_test.go @@ -30,6 +30,8 @@ import ( "testing" "time" + "github.com/notaryproject/notation-core-go/revocation" + "github.com/notaryproject/notation-core-go/revocation/purpose" "github.com/notaryproject/notation-core-go/signature" _ "github.com/notaryproject/notation-core-go/signature/cose" _ "github.com/notaryproject/notation-core-go/signature/jws" @@ -257,6 +259,27 @@ func TestSignWithTimestamping(t *testing.T) { if err == nil || err.Error() != expectedErrMsg { t.Fatalf("expected %s, but got %s", expectedErrMsg, err) } + + // timestamping with unknown authority + desc, sOpts = generateSigningContent() + sOpts.SignatureMediaType = envelopeType + sOpts.Timestamper, err = tspclient.NewHTTPTimestamper(nil, rfc3161URL) + if err != nil { + t.Fatal(err) + } + sOpts.TSARootCAs = x509.NewCertPool() + tsaRevocationValidator, err := revocation.NewWithOptions(revocation.Options{ + CertChainPurpose: purpose.Timestamping, + }) + if err != nil { + t.Fatal(err) + } + sOpts.TSARevocationValidator = tsaRevocationValidator + _, _, err = s.Sign(ctx, desc, sOpts) + expectedErrMsg = "timestamp: failed to verify signed token: cms verification failure: x509: certificate signed by unknown authority" + if err == nil || err.Error() != expectedErrMsg { + t.Fatalf("expected %s, but got %s", expectedErrMsg, err) + } } func TestSignWithoutExpiry(t *testing.T) { From 5b21f2f46179dc8ba17374934cbe163adc8a6756 Mon Sep 17 00:00:00 2001 From: Junjie Gao Date: Mon, 2 Dec 2024 10:03:54 +0800 Subject: [PATCH 15/15] perf(log): encode objects only when logged (#481) Fix: - replaced `.String()` with the `%v` format to avoid rendering the string before actually logging it. Resolves #480 Signed-off-by: Junjie Gao Signed-off-by: Patrick Zheng --- notation.go | 4 ++-- verifier/verifier.go | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/notation.go b/notation.go index bb051d13..294664b0 100644 --- a/notation.go +++ b/notation.go @@ -134,7 +134,7 @@ func Sign(ctx context.Context, signer Signer, repo registry.Repository, signOpts } // artifactRef is a tag logger.Warnf("Always sign the artifact using digest(`@sha256:...`) rather than a tag(`:%s`) because tags are mutable and a tag reference can point to a different artifact than the one signed", artifactRef) - logger.Infof("Resolved artifact tag `%s` to digest `%s` before signing", artifactRef, targetDesc.Digest.String()) + logger.Infof("Resolved artifact tag `%s` to digest `%v` before signing", artifactRef, targetDesc.Digest) } descToSign, err := addUserMetadataToDescriptor(ctx, targetDesc, signOpts.UserMetadata) if err != nil { @@ -378,7 +378,7 @@ func Verify(ctx context.Context, verifier Verifier, repo registry.Repository, ve } if ref.ValidateReferenceAsDigest() != nil { // artifactRef is not a digest reference - logger.Infof("Resolved artifact tag `%s` to digest `%s` before verification", ref.Reference, artifactDescriptor.Digest.String()) + logger.Infof("Resolved artifact tag `%s` to digest `%v` before verification", ref.Reference, artifactDescriptor.Digest) logger.Warn("The resolved digest may not point to the same signed artifact, since tags are mutable") } else if ref.Reference != artifactDescriptor.Digest.String() { return ocispec.Descriptor{}, nil, ErrorSignatureRetrievalFailed{Msg: fmt.Sprintf("user input digest %s does not match the resolved digest %s", ref.Reference, artifactDescriptor.Digest.String())} diff --git a/verifier/verifier.go b/verifier/verifier.go index e1d06528..b50869ba 100644 --- a/verifier/verifier.go +++ b/verifier/verifier.go @@ -678,7 +678,7 @@ func revocationFinalResult(certResults []*revocationresult.CertRevocationResult, certResult := certResults[i] if certResult.RevocationMethod == revocationresult.RevocationMethodOCSPFallbackCRL { // log the fallback warning - logger.Warnf("OCSP check failed with unknown error and fallback to CRL check for certificate #%d in chain with subject %v", (i + 1), cert.Subject.String()) + logger.Warnf("OCSP check failed with unknown error and fallback to CRL check for certificate #%d in chain with subject %v", (i + 1), cert.Subject) } for _, serverResult := range certResult.ServerResults { if serverResult.Error != nil { @@ -687,10 +687,10 @@ func revocationFinalResult(certResults []*revocationresult.CertRevocationResult, // when the final revocation method is OCSPFallbackCRL, // the OCSP server results should not be logged as an error // since the CRL revocation check can succeed. - logger.Debugf("Certificate #%d in chain with subject %v encountered an error for revocation method %s at URL %q: %v", (i + 1), cert.Subject.String(), revocationresult.RevocationMethodOCSP, serverResult.Server, serverResult.Error) + logger.Debugf("Certificate #%d in chain with subject %v encountered an error for revocation method %s at URL %q: %v", (i + 1), cert.Subject, revocationresult.RevocationMethodOCSP, serverResult.Server, serverResult.Error) continue } - logger.Errorf("Certificate #%d in chain with subject %v encountered an error for revocation method %s at URL %q: %v", (i + 1), cert.Subject.String(), serverResult.RevocationMethod, serverResult.Server, serverResult.Error) + logger.Errorf("Certificate #%d in chain with subject %v encountered an error for revocation method %s at URL %q: %v", (i + 1), cert.Subject, serverResult.RevocationMethod, serverResult.Server, serverResult.Error) } } @@ -706,7 +706,7 @@ func revocationFinalResult(certResults []*revocationresult.CertRevocationResult, } if i < len(certResults)-1 && certResult.Result == revocationresult.ResultNonRevokable { - logger.Warnf("Certificate #%d in the chain with subject %v neither has an OCSP nor a CRL revocation method.", (i + 1), cert.Subject.String()) + logger.Warnf("Certificate #%d in the chain with subject %v neither has an OCSP nor a CRL revocation method.", (i + 1), cert.Subject) } } if revokedFound {