diff -pruN 1.2.1-4/.github/.codecov.yml 1.3.2-1/.github/.codecov.yml
--- 1.2.1-4/.github/.codecov.yml	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/.github/.codecov.yml	2025-10-31 17:46:39.000000000 +0000
@@ -15,4 +15,7 @@ coverage:
   status:
     project:
       default:
+        target: 80%
+    patch:
+      default:
         target: 80%
\ No newline at end of file
diff -pruN 1.2.1-4/Makefile 1.3.2-1/Makefile
--- 1.2.1-4/Makefile	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/Makefile	2025-10-31 17:46:39.000000000 +0000
@@ -29,7 +29,7 @@ clean:
 .PHONY: check-line-endings
 check-line-endings: ## check line endings
 	! find . -name "*.go" -type f -exec file "{}" ";" | grep CRLF
-	! find scripts -name "*.sh" -type f -exec file "{}" ";" | grep CRLF
+	! find . -name "*.sh" -type f -exec file "{}" ";" | grep CRLF
 
 .PHONY: fix-line-endings
 fix-line-endings: ## fix line endings
diff -pruN 1.2.1-4/config/errors.go 1.3.2-1/config/errors.go
--- 1.2.1-4/config/errors.go	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.2-1/config/errors.go	2025-10-31 17:46:39.000000000 +0000
@@ -0,0 +1,35 @@
+// 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 config
+
+import (
+	"errors"
+	"fmt"
+)
+
+// ErrKeyNameEmpty is used when key name is empty.
+var ErrKeyNameEmpty = errors.New("key name cannot be empty")
+
+// KeyNotFoundError is used when key is not found in the signingkeys.json file.
+type KeyNotFoundError struct {
+	KeyName string
+}
+
+// Error returns the error message.
+func (e KeyNotFoundError) Error() string {
+	if e.KeyName != "" {
+		return fmt.Sprintf("signing key %s not found", e.KeyName)
+	}
+	return "signing key not found"
+}
diff -pruN 1.2.1-4/config/errors_test.go 1.3.2-1/config/errors_test.go
--- 1.2.1-4/config/errors_test.go	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.2-1/config/errors_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -0,0 +1,28 @@
+// 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 config
+
+import "testing"
+
+func TestErrorKeyNotFound(t *testing.T) {
+	e := KeyNotFoundError{}
+	if e.Error() != "signing key not found" {
+		t.Fatalf("ErrorKeyNotFound.Error() = %v, want %v", e.Error(), "signing key not found")
+	}
+
+	e = KeyNotFoundError{KeyName: "testKey"}
+	if e.Error() != `signing key testKey not found` {
+		t.Fatalf("ErrorKeyNotFound.Error() = %v, want %v", e.Error(), "signing key testKey not found")
+	}
+}
diff -pruN 1.2.1-4/config/keys.go 1.3.2-1/config/keys.go
--- 1.2.1-4/config/keys.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/config/keys.go	2025-10-31 17:46:39.000000000 +0000
@@ -50,9 +50,6 @@ type KeySuite struct {
 	*ExternalKey
 }
 
-var errorKeyNameEmpty = errors.New("key name cannot be empty")
-var errKeyNotFound = errors.New("signing key not found")
-
 // SigningKeys reflects the signingkeys.json file.
 type SigningKeys struct {
 	Default *string    `json:"default,omitempty"`
@@ -67,13 +64,12 @@ func NewSigningKeys() *SigningKeys {
 // Add adds new signing key
 func (s *SigningKeys) Add(name, keyPath, certPath string, markDefault bool) error {
 	if name == "" {
-		return errorKeyNameEmpty
+		return ErrKeyNameEmpty
 	}
 	_, err := tls.LoadX509KeyPair(certPath, keyPath)
 	if err != nil {
 		return err
 	}
-
 	ks := KeySuite{
 		Name: name,
 		X509KeyPair: &X509KeyPair{
@@ -88,25 +84,20 @@ func (s *SigningKeys) Add(name, keyPath,
 func (s *SigningKeys) AddPlugin(ctx context.Context, keyName, id, pluginName string, pluginConfig map[string]string, markDefault bool) error {
 	logger := log.GetLogger(ctx)
 	logger.Debugf("Adding key with name %v and plugin name %v", keyName, pluginName)
-
 	if keyName == "" {
-		return errorKeyNameEmpty
+		return ErrKeyNameEmpty
 	}
-
 	if id == "" {
 		return errors.New("missing key id")
 	}
-
 	if pluginName == "" {
 		return errors.New("plugin name cannot be empty")
 	}
-
 	mgr := plugin.NewCLIManager(dir.PluginFS())
 	_, err := mgr.Get(ctx, pluginName)
 	if err != nil {
 		return err
 	}
-
 	ks := KeySuite{
 		Name: keyName,
 		ExternalKey: &ExternalKey{
@@ -115,7 +106,6 @@ func (s *SigningKeys) AddPlugin(ctx cont
 			PluginConfig: pluginConfig,
 		},
 	}
-
 	if err = s.add(ks, markDefault); err != nil {
 		logger.Error("Failed to add key with error: %v", err)
 		return err
@@ -127,14 +117,12 @@ func (s *SigningKeys) AddPlugin(ctx cont
 // Get returns signing key for the given name
 func (s *SigningKeys) Get(keyName string) (KeySuite, error) {
 	if keyName == "" {
-		return KeySuite{}, errorKeyNameEmpty
+		return KeySuite{}, ErrKeyNameEmpty
 	}
-
 	idx := slices.IndexIsser(s.Keys, keyName)
 	if idx < 0 {
-		return KeySuite{}, errKeyNotFound
+		return KeySuite{}, KeyNotFoundError{KeyName: keyName}
 	}
-
 	return s.Keys[idx], nil
 }
 
@@ -144,7 +132,6 @@ func (s *SigningKeys) GetDefault() (KeyS
 		return KeySuite{}, errors.New("default signing key not set." +
 			" Please set default signing key or specify a key name")
 	}
-
 	return s.Get(*s.Default)
 }
 
@@ -153,12 +140,11 @@ func (s *SigningKeys) Remove(keyName ...
 	var deletedNames []string
 	for _, name := range keyName {
 		if name == "" {
-			return deletedNames, errorKeyNameEmpty
+			return deletedNames, ErrKeyNameEmpty
 		}
-
 		idx := slices.IndexIsser(s.Keys, name)
 		if idx < 0 {
-			return deletedNames, errors.New(name + ": not found")
+			return deletedNames, KeyNotFoundError{KeyName: name}
 		}
 		s.Keys = slices.Delete(s.Keys, idx)
 		deletedNames = append(deletedNames, name)
@@ -172,13 +158,11 @@ func (s *SigningKeys) Remove(keyName ...
 // UpdateDefault updates default signing key
 func (s *SigningKeys) UpdateDefault(keyName string) error {
 	if keyName == "" {
-		return errorKeyNameEmpty
+		return ErrKeyNameEmpty
 	}
-
 	if !slices.ContainsIsser(s.Keys, keyName) {
-		return fmt.Errorf("key with name '%s' not found", keyName)
+		return KeyNotFoundError{KeyName: keyName}
 	}
-
 	s.Default = &keyName
 	return nil
 }
@@ -189,11 +173,9 @@ func (s *SigningKeys) Save() error {
 	if err != nil {
 		return err
 	}
-
 	if err := validateKeys(s); err != nil {
 		return err
 	}
-
 	return save(path, s)
 }
 
@@ -208,11 +190,9 @@ func LoadSigningKeys() (*SigningKeys, er
 		}
 		return nil, err
 	}
-
 	if err := validateKeys(&config); err != nil {
 		return nil, err
 	}
-
 	return &config, nil
 }
 
@@ -224,11 +204,9 @@ func LoadExecSaveSigningKeys(fn func(key
 	if err != nil {
 		return err
 	}
-
 	if err := fn(signingKeys); err != nil {
 		return err
 	}
-
 	return signingKeys.Save()
 }
 
@@ -241,12 +219,10 @@ func (s *SigningKeys) add(key KeySuite,
 	if slices.ContainsIsser(s.Keys, key.Name) {
 		return fmt.Errorf("signing key with name %q already exists", key.Name)
 	}
-
 	s.Keys = append(s.Keys, key)
 	if markDefault {
 		s.Default = &key.Name
 	}
-
 	return nil
 }
 
@@ -262,17 +238,14 @@ func validateKeys(config *SigningKeys) e
 		}
 		uniqueKeyNames.Add(key.Name)
 	}
-
 	if config.Default != nil {
 		defaultKey := *config.Default
 		if len(defaultKey) == 0 {
 			return fmt.Errorf("malformed %s: default key name cannot be empty", dir.PathSigningKeys)
 		}
-
 		if !uniqueKeyNames.Contains(defaultKey) {
 			return fmt.Errorf("malformed %s: default key '%s' not found", dir.PathSigningKeys, defaultKey)
 		}
 	}
-
 	return nil
 }
diff -pruN 1.2.1-4/config/keys_test.go 1.3.2-1/config/keys_test.go
--- 1.2.1-4/config/keys_test.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/config/keys_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -17,6 +17,7 @@ import (
 	"context"
 	"crypto/x509"
 	"encoding/pem"
+	"errors"
 	"os"
 	"path/filepath"
 	"reflect"
@@ -310,14 +311,22 @@ func TestGet(t *testing.T) {
 	})
 
 	t.Run("NonExistent", func(t *testing.T) {
-		if _, err := sampleSigningKeysInfo.Get("nonExistent"); err == nil {
+		_, err := sampleSigningKeysInfo.Get("nonExistent")
+		if err == nil {
 			t.Error("expected Get() to fail for nonExistent key name")
 		}
+		if !errors.Is(err, KeyNotFoundError{KeyName: "nonExistent"}) {
+			t.Error("expected Get() to return ErrorKeyNotFound")
+		}
 	})
 
-	t.Run("InvalidName", func(t *testing.T) {
-		if _, err := sampleSigningKeysInfo.Get(""); err == nil {
-			t.Error("expected Get() to fail for invalid key name")
+	t.Run("EmptyName", func(t *testing.T) {
+		_, err := sampleSigningKeysInfo.Get("")
+		if err == nil {
+			t.Error("expected Get() to fail for empty key name")
+		}
+		if !errors.Is(err, ErrKeyNameEmpty) {
+			t.Error("expected Get() to return ErrorKeyNameEmpty")
 		}
 	})
 }
@@ -358,14 +367,22 @@ func TestUpdateDefault(t *testing.T) {
 	})
 
 	t.Run("NonExistent", func(t *testing.T) {
-		if err := sampleSigningKeysInfo.UpdateDefault("nonExistent"); err == nil {
+		err := sampleSigningKeysInfo.UpdateDefault("nonExistent")
+		if err == nil {
 			t.Error("expected Get() to fail for nonExistent key name")
 		}
+		if !errors.Is(err, KeyNotFoundError{KeyName: "nonExistent"}) {
+			t.Error("expected Get() to return ErrorKeyNotFound")
+		}
 	})
 
-	t.Run("InvalidName", func(t *testing.T) {
-		if err := sampleSigningKeysInfo.UpdateDefault(""); err == nil {
-			t.Error("expected Get() to fail for invalid key name")
+	t.Run("EmptyName", func(t *testing.T) {
+		err := sampleSigningKeysInfo.UpdateDefault("")
+		if err == nil {
+			t.Error("expected Get() to fail for empty key name")
+		}
+		if !errors.Is(err, ErrKeyNameEmpty) {
+			t.Error("expected Get() to return ErrorKeyNameEmpty")
 		}
 	})
 }
@@ -382,21 +399,28 @@ func TestRemove(t *testing.T) {
 		if _, err := testSigningKeysInfo.Get(testKeyName); err == nil {
 			t.Error("Delete() filed to delete key")
 		}
-
 		if keys[0] != testKeyName {
 			t.Error("Delete() deleted key name mismatch")
 		}
 	})
 
 	t.Run("NonExistent", func(t *testing.T) {
-		if _, err := testSigningKeysInfo.Remove(testKeyName); err == nil {
+		_, err := testSigningKeysInfo.Remove("nonExistent")
+		if err == nil {
 			t.Error("expected Get() to fail for nonExistent key name")
 		}
+		if !errors.Is(err, KeyNotFoundError{KeyName: "nonExistent"}) {
+			t.Error("expected Get() to return ErrorKeyNotFound")
+		}
 	})
 
-	t.Run("InvalidName", func(t *testing.T) {
-		if _, err := testSigningKeysInfo.Remove(""); err == nil {
-			t.Error("expected Get() to fail for invalid key name")
+	t.Run("EmptyName", func(t *testing.T) {
+		_, err := testSigningKeysInfo.Remove("")
+		if err == nil {
+			t.Error("expected Get() to fail for empty key name")
+		}
+		if !errors.Is(err, ErrKeyNameEmpty) {
+			t.Error("expected Get() to return ErrorKeyNameEmpty")
 		}
 	})
 }
diff -pruN 1.2.1-4/debian/.gitignore 1.3.2-1/debian/.gitignore
--- 1.2.1-4/debian/.gitignore	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.2-1/debian/.gitignore	2025-10-31 17:48:39.000000000 +0000
@@ -0,0 +1,7 @@
+*.debhelper
+*.log
+*.substvars
+/.debhelper/
+/debhelper-build-stamp
+/files
+/golang-github-notaryproject-notation-go-dev/
diff -pruN 1.2.1-4/debian/changelog 1.3.2-1/debian/changelog
--- 1.2.1-4/debian/changelog	2025-05-14 19:40:00.000000000 +0000
+++ 1.3.2-1/debian/changelog	2025-10-31 17:48:39.000000000 +0000
@@ -1,3 +1,32 @@
+golang-github-notaryproject-notation-go (1.3.2-1) unstable; urgency=medium
+
+  [ Simon Josefsson ]
+  * Team upload.
+  * Upload to unstable.
+  * Use watch v5.
+  * New upstream version 1.3.2
+  * Drop Rules-Requires-Root: no.
+  * Standards-Version: 4.7.2.
+  * Bump debian/* copyright years.
+  * Add new variant of upstream copyright notices.
+  * Refresh patches.
+  * Bump version on B-D's.
+  * Fix executable-not-elf-or-script.
+  * Fix Forwarded: on patches.
+
+  [ Reinhard Tartler ]
+  * Also tighten dependends for the -dev package
+
+ -- Simon Josefsson <simon@josefsson.org>  Fri, 31 Oct 2025 18:48:39 +0100
+
+golang-github-notaryproject-notation-go (1.2.1-5) experimental; urgency=medium
+
+  * fix: enable timestamping cert chain revocation check during signing (#482)
+    Closes: #1094409
+  * Bump dependency on golang-github-notaryproject-notation-core-go-dev
+
+ -- Reinhard Tartler <siretart@tauware.de>  Sun, 01 Jun 2025 08:26:00 -0400
+
 golang-github-notaryproject-notation-go (1.2.1-4) unstable; urgency=medium
 
   * Team upload.
diff -pruN 1.2.1-4/debian/control 1.3.2-1/debian/control
--- 1.2.1-4/debian/control	2025-05-14 19:40:00.000000000 +0000
+++ 1.3.2-1/debian/control	2025-10-31 17:48:39.000000000 +0000
@@ -4,15 +4,14 @@ Priority: optional
 Maintainer: Debian Go Packaging Team <team+pkg-go@tracker.debian.org>
 Uploaders:
  Reinhard Tartler <siretart@tauware.de>
-Rules-Requires-Root: no
 Build-Depends:
  debhelper-compat (= 13),
  dh-sequence-golang,
  golang-any,
  golang-github-go-ldap-ldap-dev,
- golang-github-notaryproject-notation-core-go-dev,
+ golang-github-notaryproject-notation-core-go-dev (>= 1.3.0-1~),
  golang-github-notaryproject-notation-plugin-framework-go-dev,
- golang-github-notaryproject-tspclient-go-dev,
+ golang-github-notaryproject-tspclient-go-dev (>= 1.0.0-1~),
  golang-github-opencontainers-go-digest-dev,
  golang-github-opencontainers-image-spec-dev,
  golang-github-veraison-go-cose-dev,
@@ -20,7 +19,7 @@ Build-Depends:
  golang-golang-x-mod-dev,
  golang-oras-oras-go-dev
 Testsuite: autopkgtest-pkg-go
-Standards-Version: 4.7.0
+Standards-Version: 4.7.2
 Vcs-Browser: https://salsa.debian.org/go-team/packages/golang-github-notaryproject-notation-go
 Vcs-Git: https://salsa.debian.org/go-team/packages/golang-github-notaryproject-notation-go.git
 Homepage: https://github.com/notaryproject/notation-go
@@ -30,9 +29,9 @@ Package: golang-github-notaryproject-not
 Architecture: all
 Multi-Arch: foreign
 Depends:
- golang-github-notaryproject-notation-core-go-dev,
+ golang-github-notaryproject-notation-core-go-dev (>= 1.3.0-1~),
  golang-github-notaryproject-notation-plugin-framework-go-dev,
- golang-github-notaryproject-tspclient-go-dev,
+ golang-github-notaryproject-tspclient-go-dev (>= 1.0.0-1~),
  golang-github-opencontainers-go-digest-dev,
  golang-github-opencontainers-image-spec-dev,
  golang-github-veraison-go-cose-dev,
diff -pruN 1.2.1-4/debian/copyright 1.3.2-1/debian/copyright
--- 1.2.1-4/debian/copyright	2025-05-14 19:40:00.000000000 +0000
+++ 1.3.2-1/debian/copyright	2025-10-31 17:48:39.000000000 +0000
@@ -4,10 +4,12 @@ Upstream-Name: notation-go
 
 Files: *
 Copyright: 2020 Notary Project
+           The Notary Project Authors
 License: Apache-2.0
 
 Files: debian/*
 Copyright: 2024 Reinhard Tartler <siretart@tauware.de>
+           2025 Simon Josefsson <simon@josefsson.org>
 License: Apache-2.0
 Comment: Debian packaging is licensed under the same terms as upstream
 
diff -pruN 1.2.1-4/debian/patches/0001-Fix-overflow-on-32-bit-architectures.patch 1.3.2-1/debian/patches/0001-Fix-overflow-on-32-bit-architectures.patch
--- 1.2.1-4/debian/patches/0001-Fix-overflow-on-32-bit-architectures.patch	2025-05-14 19:40:00.000000000 +0000
+++ 1.3.2-1/debian/patches/0001-Fix-overflow-on-32-bit-architectures.patch	2025-10-31 17:48:39.000000000 +0000
@@ -1,17 +1,17 @@
 From: Reinhard Tartler <siretart@tauware.de>
 Date: Thu, 26 Dec 2024 07:17:09 -0500
 Subject: Fix overflow on 32-bit architectures
-
 Forwarded: https://github.com/notaryproject/notation-go/pull/500
+
 ---
  notation_test.go | 2 +-
  1 file changed, 1 insertion(+), 1 deletion(-)
 
 diff --git a/notation_test.go b/notation_test.go
-index 64fbe07..83b5934 100644
+index cae65c5..4ce29bc 100644
 --- a/notation_test.go
 +++ b/notation_test.go
-@@ -564,7 +564,7 @@ func TestLocalContent(t *testing.T) {
+@@ -586,7 +586,7 @@ func TestLocalContent(t *testing.T) {
  		// verify the artifact
  		verifyOpts := VerifyOptions{
  			ArtifactReference:    artifactReference,
@@ -19,4 +19,4 @@ index 64fbe07..83b5934 100644
 +			MaxSignatureAttempts: math.MaxInt,
  		}
  		policyDocument := dummyPolicyDocument()
- 		verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict}
+ 		verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict, false}
diff -pruN 1.2.1-4/debian/patches/0002-Allow-skipping-tests-that-connec-to-the-internet-Clo.patch 1.3.2-1/debian/patches/0002-Allow-skipping-tests-that-connec-to-the-internet-Clo.patch
--- 1.2.1-4/debian/patches/0002-Allow-skipping-tests-that-connec-to-the-internet-Clo.patch	2025-05-14 19:40:00.000000000 +0000
+++ 1.3.2-1/debian/patches/0002-Allow-skipping-tests-that-connec-to-the-internet-Clo.patch	2025-10-31 17:48:39.000000000 +0000
@@ -1,13 +1,14 @@
 From: Reinhard Tartler <siretart@tauware.de>
 Date: Thu, 26 Dec 2024 07:20:35 -0500
 Subject: Allow skipping tests that connec to the internet, Closes: #1090825
+Forwarded: not-needed
 
 ---
  signer/signer_test.go | 4 ++++
  1 file changed, 4 insertions(+)
 
 diff --git a/signer/signer_test.go b/signer/signer_test.go
-index 1dac5eb..bf937ea 100644
+index a2f8848..ef31e1d 100644
 --- a/signer/signer_test.go
 +++ b/signer/signer_test.go
 @@ -27,6 +27,7 @@ import (
@@ -18,7 +19,7 @@ index 1dac5eb..bf937ea 100644
  	"testing"
  	"time"
  
-@@ -398,6 +399,9 @@ func validateSignWithCerts(t *testing.T, envelopeType string, key crypto.Private
+@@ -421,6 +422,9 @@ func validateSignWithCerts(t *testing.T, envelopeType string, key crypto.Private
  	}
  	sig, _, err := s.Sign(ctx, desc, sOpts)
  	if err != nil {
diff -pruN 1.2.1-4/debian/patches/0004-disable-network-tests.patch 1.3.2-1/debian/patches/0004-disable-network-tests.patch
--- 1.2.1-4/debian/patches/0004-disable-network-tests.patch	2025-05-14 19:40:00.000000000 +0000
+++ 1.3.2-1/debian/patches/0004-disable-network-tests.patch	2025-10-31 17:48:39.000000000 +0000
@@ -1,6 +1,7 @@
 From: Santiago Vila <sanvila@debian.org>
 Subject: Disable network tests
 Bug-Debian: https://bugs.debian.org/1104509
+Forwarded: not-needed
 
 --- a/signer/signer_test.go
 +++ b/signer/signer_test.go
diff -pruN 1.2.1-4/debian/rules 1.3.2-1/debian/rules
--- 1.2.1-4/debian/rules	2025-05-14 19:40:00.000000000 +0000
+++ 1.3.2-1/debian/rules	2025-10-31 17:48:39.000000000 +0000
@@ -4,3 +4,7 @@ export DH_GOLANG_INSTALL_EXTRA := $(wild
 
 %:
 	dh $@ --builddirectory=_build --buildsystem=golang
+
+# executable-not-elf-or-script
+execute_before_dh_auto_install:
+	chmod -v -x $(CURDIR)/_build/src/github.com/notaryproject/notation-go/plugin/testdata/plugins/foo/notation-foo
diff -pruN 1.2.1-4/debian/watch 1.3.2-1/debian/watch
--- 1.2.1-4/debian/watch	2025-05-14 19:40:00.000000000 +0000
+++ 1.3.2-1/debian/watch	2025-10-31 17:48:39.000000000 +0000
@@ -1,4 +1,4 @@
-version=4
-opts="filenamemangle=s%(?:.*?)?v?(\d[\d.]*)\.tar\.gz%@PACKAGE@-$1.tar.gz%,\
-      uversionmangle=s/(\d)[_\.\-\+]?(RC|rc|pre|dev|beta|alpha)[.]?(\d*)$/$1~$2$3/" \
-  https://github.com/notaryproject/notation-go/tags .*/v?(\d\S*)\.tar\.gz debian
+Version: 5
+Template: Github
+Owner: notaryproject
+Project: notation-go
diff -pruN 1.2.1-4/dir/fs.go 1.3.2-1/dir/fs.go
--- 1.2.1-4/dir/fs.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/dir/fs.go	2025-10-31 17:46:39.000000000 +0000
@@ -58,3 +58,10 @@ func ConfigFS() SysFS {
 func PluginFS() SysFS {
 	return NewSysFS(filepath.Join(userLibexecDirPath(), PathPlugins))
 }
+
+// CacheFS is the cache SysFS.
+//
+// To get the root of crl file cache, use `CacheFS().SysFS(PathCRLCache)`.
+func CacheFS() SysFS {
+	return NewSysFS(userCacheDirPath())
+}
diff -pruN 1.2.1-4/dir/fs_test.go 1.3.2-1/dir/fs_test.go
--- 1.2.1-4/dir/fs_test.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/dir/fs_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -71,3 +71,14 @@ func TestPluginFS(t *testing.T) {
 		t.Fatalf(`SysPath() failed. got: %q, want: %q`, path, filepath.Join(userLibexecDirPath(), PathPlugins, "plugin"))
 	}
 }
+
+func TestCRLFileCacheFS(t *testing.T) {
+	cacheFS := CacheFS()
+	path, err := cacheFS.SysPath(PathCRLCache)
+	if err != nil {
+		t.Fatalf("SysPath() failed. err = %v", err)
+	}
+	if path != filepath.Join(UserCacheDir, PathCRLCache) {
+		t.Fatalf(`SysPath() failed. got: %q, want: %q`, path, UserConfigDir)
+	}
+}
diff -pruN 1.2.1-4/dir/path.go 1.3.2-1/dir/path.go
--- 1.2.1-4/dir/path.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/dir/path.go	2025-10-31 17:46:39.000000000 +0000
@@ -12,7 +12,7 @@
 // limitations under the License.
 
 // Package dir implements Notation directory structure.
-// [directory spec]: https://github.com/notaryproject/notation/blob/main/specs/directory.md
+// [directory spec]: https://notaryproject.dev/docs/user-guides/how-to/directory-structure/
 //
 // Example:
 //
@@ -31,7 +31,7 @@
 //   - Set custom configurations directory:
 //     dir.UserConfigDir = '/path/to/configurations/'
 //
-// Only user level directory is supported for RC.1, and system level directory
+// Only user level directory is supported, and system level directory
 // may be added later.
 package dir
 
@@ -44,6 +44,7 @@ import (
 var (
 	UserConfigDir  string // Absolute path of user level {NOTATION_CONFIG}
 	UserLibexecDir string // Absolute path of user level {NOTATION_LIBEXEC}
+	UserCacheDir   string // Absolute path of user level {NOTATION_CACHE}
 )
 
 const (
@@ -59,8 +60,6 @@ const (
 	PathSigningKeys = "signingkeys.json"
 	// PathTrustPolicy is the trust policy file relative path.
 	PathTrustPolicy = "trustpolicy.json"
-	// PathPlugins is the plugins directory relative path.
-	PathPlugins = "plugins"
 	// LocalKeysDir is the directory name for local key relative path.
 	LocalKeysDir = "localkeys"
 	// LocalCertificateExtension defines the extension of the certificate files.
@@ -71,7 +70,24 @@ const (
 	TrustStoreDir = "truststore"
 )
 
-var userConfigDir = os.UserConfigDir // for unit test
+// The relative path to {NOTATION_LIBEXEC}
+const (
+	// PathPlugins is the plugins directory relative path.
+	PathPlugins = "plugins"
+)
+
+// The relative path to {NOTATION_CACHE}
+const (
+	// PathCRLCache is the crl file cache directory relative path.
+	PathCRLCache = "crl"
+)
+
+// for unit tests
+var (
+	userConfigDir = os.UserConfigDir
+
+	userCacheDir = os.UserCacheDir
+)
 
 // userConfigDirPath returns the user level {NOTATION_CONFIG} path.
 func userConfigDirPath() string {
@@ -97,6 +113,21 @@ func userLibexecDirPath() string {
 	return UserLibexecDir
 }
 
+// userCacheDirPath returns the user level {NOTATION_CACHE} path.
+func userCacheDirPath() string {
+	if UserCacheDir == "" {
+		userDir, err := userCacheDir()
+		if err != nil {
+			// fallback to current directory
+			UserCacheDir = filepath.Join("."+notation, "cache")
+			return UserCacheDir
+		}
+		// set user cache
+		UserCacheDir = filepath.Join(userDir, notation)
+	}
+	return UserCacheDir
+}
+
 // LocalKeyPath returns the local key and local cert relative paths.
 func LocalKeyPath(name string) (keyPath, certPath string) {
 	basePath := path.Join(LocalKeysDir, name)
diff -pruN 1.2.1-4/dir/path_test.go 1.3.2-1/dir/path_test.go
--- 1.2.1-4/dir/path_test.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/dir/path_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -15,20 +15,22 @@ package dir
 
 import (
 	"os"
+	"path/filepath"
 	"testing"
 )
 
-func mockGetUserConfig() (string, error) {
+func mockUserPath() (string, error) {
 	return "/path/", nil
 }
 
 func setup() {
 	UserConfigDir = ""
 	UserLibexecDir = ""
+	UserCacheDir = ""
 }
 
 func Test_UserConfigDirPath(t *testing.T) {
-	userConfigDir = mockGetUserConfig
+	userConfigDir = mockUserPath
 	setup()
 	got := userConfigDirPath()
 	if got != "/path/notation" {
@@ -39,16 +41,22 @@ func Test_UserConfigDirPath(t *testing.T
 func Test_NoHomeVariable(t *testing.T) {
 	t.Setenv("HOME", "")
 	t.Setenv("XDG_CONFIG_HOME", "")
+	t.Setenv("XDG_CACHE_HOME", "")
 	setup()
 	userConfigDir = os.UserConfigDir
 	got := userConfigDirPath()
 	if got != ".notation" {
-		t.Fatalf(`UserConfigDirPath() = %q, want ".notation"`, UserConfigDir)
+		t.Fatalf(`userConfigDirPath() = %q, want ".notation"`, got)
+	}
+	got = userCacheDirPath()
+	want := filepath.Join("."+notation, "cache")
+	if got != want {
+		t.Fatalf(`userCacheDirPath() = %q, want %q`, got, want)
 	}
 }
 
 func Test_UserLibexecDirPath(t *testing.T) {
-	userConfigDir = mockGetUserConfig
+	userConfigDir = mockUserPath
 	setup()
 	got := userLibexecDirPath()
 	if got != "/path/notation" {
@@ -56,8 +64,17 @@ func Test_UserLibexecDirPath(t *testing.
 	}
 }
 
+func Test_UserCacheDirPath(t *testing.T) {
+	userCacheDir = mockUserPath
+	setup()
+	got := userCacheDirPath()
+	if got != "/path/notation" {
+		t.Fatalf(`UserCacheDirPath() = %q, want "/path/notation"`, got)
+	}
+}
+
 func TestLocalKeyPath(t *testing.T) {
-	userConfigDir = mockGetUserConfig
+	userConfigDir = mockUserPath
 	setup()
 	_ = userConfigDirPath()
 	_ = userLibexecDirPath()
@@ -71,7 +88,7 @@ func TestLocalKeyPath(t *testing.T) {
 }
 
 func TestX509TrustStoreDir(t *testing.T) {
-	userConfigDir = mockGetUserConfig
+	userConfigDir = mockUserPath
 	setup()
 	_ = userConfigDirPath()
 	_ = userLibexecDirPath()
diff -pruN 1.2.1-4/errors.go 1.3.2-1/errors.go
--- 1.2.1-4/errors.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/errors.go	2025-10-31 17:46:39.000000000 +0000
@@ -15,11 +15,17 @@ package notation
 
 // ErrorPushSignatureFailed is used when failed to push signature to the
 // target registry.
-type ErrorPushSignatureFailed struct {
+//
+// Deprecated: Use PushSignatureFailedError instead.
+type ErrorPushSignatureFailed = PushSignatureFailedError
+
+// PushSignatureFailedError is used when failed to push signature to the
+// target registry.
+type PushSignatureFailedError struct {
 	Msg string
 }
 
-func (e ErrorPushSignatureFailed) Error() string {
+func (e PushSignatureFailedError) Error() string {
 	if e.Msg != "" {
 		return "failed to push signature to registry with error: " + e.Msg
 	}
@@ -28,11 +34,17 @@ func (e ErrorPushSignatureFailed) Error(
 
 // ErrorVerificationInconclusive is used when signature verification fails due
 // to a runtime error (e.g. a network error)
-type ErrorVerificationInconclusive struct {
+//
+// Deprecated: Use VerificationInconclusiveError instead.
+type ErrorVerificationInconclusive = VerificationInconclusiveError
+
+// VerificationInconclusiveError is used when signature verification fails due
+// to a runtime error (e.g. a network error)
+type VerificationInconclusiveError struct {
 	Msg string
 }
 
-func (e ErrorVerificationInconclusive) Error() string {
+func (e VerificationInconclusiveError) Error() string {
 	if e.Msg != "" {
 		return e.Msg
 	}
@@ -41,11 +53,17 @@ func (e ErrorVerificationInconclusive) E
 
 // ErrorNoApplicableTrustPolicy is used when there is no trust policy that
 // applies to the given artifact
-type ErrorNoApplicableTrustPolicy struct {
+//
+// Deprecated: Use NoApplicableTrustPolicyError instead.
+type ErrorNoApplicableTrustPolicy = NoApplicableTrustPolicyError
+
+// NoApplicableTrustPolicyError is used when there is no trust policy that
+// applies to the given artifact
+type NoApplicableTrustPolicyError struct {
 	Msg string
 }
 
-func (e ErrorNoApplicableTrustPolicy) Error() string {
+func (e NoApplicableTrustPolicyError) Error() string {
 	if e.Msg != "" {
 		return e.Msg
 	}
@@ -54,11 +72,17 @@ func (e ErrorNoApplicableTrustPolicy) Er
 
 // ErrorSignatureRetrievalFailed is used when notation is unable to retrieve the
 // digital signature/s for the given artifact
-type ErrorSignatureRetrievalFailed struct {
+//
+// Deprecated: Use SignatureRetrievalFailedError instead.
+type ErrorSignatureRetrievalFailed = SignatureRetrievalFailedError
+
+// SignatureRetrievalFailedError is used when notation is unable to retrieve the
+// digital signature/s for the given artifact
+type SignatureRetrievalFailedError struct {
 	Msg string
 }
 
-func (e ErrorSignatureRetrievalFailed) Error() string {
+func (e SignatureRetrievalFailedError) Error() string {
 	if e.Msg != "" {
 		return e.Msg
 	}
@@ -67,11 +91,17 @@ func (e ErrorSignatureRetrievalFailed) E
 
 // ErrorVerificationFailed is used when it is determined that the digital
 // signature/s is not valid for the given artifact
-type ErrorVerificationFailed struct {
+//
+// Deprecated: Use VerificationFailedError instead.
+type ErrorVerificationFailed = VerificationFailedError
+
+// VerificationFailedError is used when it is determined that the digital
+// signature/s is not valid for the given artifact
+type VerificationFailedError struct {
 	Msg string
 }
 
-func (e ErrorVerificationFailed) Error() string {
+func (e VerificationFailedError) Error() string {
 	if e.Msg != "" {
 		return e.Msg
 	}
@@ -80,11 +110,17 @@ func (e ErrorVerificationFailed) Error()
 
 // ErrorUserMetadataVerificationFailed is used when the signature does not
 // contain the user specified metadata
-type ErrorUserMetadataVerificationFailed struct {
+//
+// Deprecated: Use UserMetadataVerificationFailedError instead.
+type ErrorUserMetadataVerificationFailed = UserMetadataVerificationFailedError
+
+// UserMetadataVerificationFailedError is used when the signature does not
+// contain the user specified metadata
+type UserMetadataVerificationFailedError struct {
 	Msg string
 }
 
-func (e ErrorUserMetadataVerificationFailed) Error() string {
+func (e UserMetadataVerificationFailedError) Error() string {
 	if e.Msg != "" {
 		return e.Msg
 	}
diff -pruN 1.2.1-4/errors_test.go 1.3.2-1/errors_test.go
--- 1.2.1-4/errors_test.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/errors_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -91,3 +91,80 @@ func TestErrorMessages(t *testing.T) {
 		})
 	}
 }
+
+func TestCustomErrorPrintsCorrectMessage(t *testing.T) {
+	tests := []struct {
+		name string
+		err  error
+		want string
+	}{
+		{
+			name: "PushSignatureFailedError with message",
+			err:  PushSignatureFailedError{Msg: "test message"},
+			want: "failed to push signature to registry with error: test message",
+		},
+		{
+			name: "PushSignatureFailedError without message",
+			err:  PushSignatureFailedError{},
+			want: "failed to push signature to registry",
+		},
+		{
+			name: "VerificationInconclusiveError with message",
+			err:  VerificationInconclusiveError{Msg: "test message"},
+			want: "test message",
+		},
+		{
+			name: "VerificationInconclusiveError without message",
+			err:  VerificationInconclusiveError{},
+			want: "signature verification was inclusive due to an unexpected error",
+		},
+		{
+			name: "NoApplicableTrustPolicyError with message",
+			err:  NoApplicableTrustPolicyError{Msg: "test message"},
+			want: "test message",
+		},
+		{
+			name: "NoApplicableTrustPolicyError without message",
+			err:  NoApplicableTrustPolicyError{},
+			want: "there is no applicable trust policy for the given artifact",
+		},
+		{
+			name: "SignatureRetrievalFailedError with message",
+			err:  SignatureRetrievalFailedError{Msg: "test message"},
+			want: "test message",
+		},
+		{
+			name: "SignatureRetrievalFailedError without message",
+			err:  SignatureRetrievalFailedError{},
+			want: "unable to retrieve the digital signature from the registry",
+		},
+		{
+			name: "VerificationFailedError with message",
+			err:  VerificationFailedError{Msg: "test message"},
+			want: "test message",
+		},
+		{
+			name: "VerificationFailedError without message",
+			err:  VerificationFailedError{},
+			want: "signature verification failed",
+		},
+		{
+			name: "UserMetadataVerificationFailedError with message",
+			err:  UserMetadataVerificationFailedError{Msg: "test message"},
+			want: "test message",
+		},
+		{
+			name: "UserMetadataVerificationFailedError without message",
+			err:  UserMetadataVerificationFailedError{},
+			want: "unable to find specified metadata in the signature",
+		},
+	}
+
+	for _, tt := range tests {
+		t.Run(tt.name, func(t *testing.T) {
+			if got := tt.err.Error(); got != tt.want {
+				t.Errorf("Error() = %v, want %v", got, tt.want)
+			}
+		})
+	}
+}
diff -pruN 1.2.1-4/example_signWithTimestmap_test.go 1.3.2-1/example_signWithTimestmap_test.go
--- 1.2.1-4/example_signWithTimestmap_test.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/example_signWithTimestmap_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -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 -pruN 1.2.1-4/go.mod 1.3.2-1/go.mod
--- 1.2.1-4/go.mod	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/go.mod	2025-10-31 17:46:39.000000000 +0000
@@ -1,26 +1,26 @@
 module github.com/notaryproject/notation-go
 
-go 1.22
+go 1.23.0
 
 require (
-	github.com/go-ldap/ldap/v3 v3.4.8
-	github.com/notaryproject/notation-core-go v1.1.0
+	github.com/go-ldap/ldap/v3 v3.4.10
+	github.com/notaryproject/notation-core-go v1.3.0
 	github.com/notaryproject/notation-plugin-framework-go v1.0.0
-	github.com/notaryproject/tspclient-go v0.2.0
+	github.com/notaryproject/tspclient-go v1.0.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
-	golang.org/x/crypto v0.26.0
-	golang.org/x/mod v0.20.0
+	github.com/opencontainers/image-spec v1.1.1
+	github.com/veraison/go-cose v1.3.0
+	golang.org/x/crypto v0.37.0
+	golang.org/x/mod v0.24.0
 	oras.land/oras-go/v2 v2.5.0
 )
 
 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/fxamacker/cbor/v2 v2.8.0 // indirect
+	github.com/go-asn1-ber/asn1-ber v1.5.7 // indirect
+	github.com/golang-jwt/jwt/v4 v4.5.2 // 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
+	golang.org/x/sync v0.10.0 // indirect
 )
diff -pruN 1.2.1-4/go.sum 1.3.2-1/go.sum
--- 1.2.1-4/go.sum	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/go.sum	2025-10-31 17:46:39.000000000 +0000
@@ -5,14 +5,15 @@ github.com/alexbrainman/sspi v0.0.0-2023
 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
 github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
-github.com/fxamacker/cbor/v2 v2.7.0 h1:iM5WgngdRBanHcxugY4JySA0nk1wZorNOpTgCMedv5E=
-github.com/fxamacker/cbor/v2 v2.7.0/go.mod h1:pxXPTn3joSm21Gbwsv0w9OSA2y1HFR9qXEeXQVeNoDQ=
-github.com/go-asn1-ber/asn1-ber v1.5.5 h1:MNHlNMBDgEKD4TcKr36vQN68BA00aDfjIt3/bD50WnA=
-github.com/go-asn1-ber/asn1-ber v1.5.5/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
-github.com/go-ldap/ldap/v3 v3.4.8 h1:loKJyspcRezt2Q3ZRMq2p/0v8iOurlmeXDPw6fikSvQ=
-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/fxamacker/cbor/v2 v2.8.0 h1:fFtUGXUzXPHTIUdne5+zzMPTfffl3RD5qYnkY40vtxU=
+github.com/fxamacker/cbor/v2 v2.8.0/go.mod h1:vM4b+DJCtHn+zz7h3FFp/hDAI9WNWCsZj23V5ytsSxQ=
+github.com/go-asn1-ber/asn1-ber v1.5.7 h1:DTX+lbVTWaTw1hQ+PbZPlnDZPEIs0SS/GCZAl535dDk=
+github.com/go-asn1-ber/asn1-ber v1.5.7/go.mod h1:hEBeB/ic+5LoWskz+yKT7vGhhPYkProFKoKdwZRWMe0=
+github.com/go-ldap/ldap/v3 v3.4.10 h1:ot/iwPOhfpNVgB1o+AVXljizWZ9JTp7YF5oeyONmcJU=
+github.com/go-ldap/ldap/v3 v3.4.10/go.mod h1:JXh4Uxgi40P6E9rdsYqpUtbW46D9UTjJ9QSwGRznplY=
+github.com/golang-jwt/jwt/v4 v4.5.2 h1:YtQM7lnr8iZ+j5q71MGKkNw9Mn7AjHM68uc9g5fXeUI=
+github.com/golang-jwt/jwt/v4 v4.5.2/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0=
+github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY=
 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=
@@ -32,16 +33,16 @@ github.com/jcmturner/gokrb5/v8 v8.4.4 h1
 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.1.0 h1:xCybcONOKcCyPNihJUSa+jRNsyQFNkrk0eJVVs1kWeg=
-github.com/notaryproject/notation-core-go v1.1.0/go.mod h1:+6AOh41JPrnVLbW/19SJqdhVHwKgIINBO/np0e7nXJA=
+github.com/notaryproject/notation-core-go v1.3.0 h1:mWJaw1QBpBxpjLSiKOjzbZvB+xh2Abzk14FHWQ+9Kfs=
+github.com/notaryproject/notation-core-go v1.3.0/go.mod h1:hzvEOit5lXfNATGNBT8UQRx2J6Fiw/dq/78TQL8aE64=
 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 h1:AwQ4x0gX8IHnyiZB1tggpn5NFqHpTEm1SDX8YNv4Dg4=
+github.com/notaryproject/tspclient-go v1.0.0/go.mod h1:LGyA/6Kwd2FlM0uk8Vc5il3j0CddbWSHBj/4kxQDbjs=
 github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U=
 github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM=
-github.com/opencontainers/image-spec v1.1.0 h1:8SG7/vwALn54lVB/0yZ/MMwhFrPYtpEHQb2IpWsCzug=
-github.com/opencontainers/image-spec v1.1.0/go.mod h1:W4s4sFTMaBeK1BQLXbG4AdM2szdn85PY75RI83NrTrM=
+github.com/opencontainers/image-spec v1.1.1 h1:y0fUlFfIZhPF1W537XOLg0/fcx6zcHCJwooC2xJA040=
+github.com/opencontainers/image-spec v1.1.1/go.mod h1:qpqAh3Dmcf36wStyyWU+kCeDgrGnAve2nCC8+7h8Q0M=
 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/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
@@ -52,22 +53,27 @@ github.com/stretchr/testify v1.7.1/go.mo
 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=
 golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
 golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
 golang.org/x/crypto v0.6.0/go.mod h1:OFC/31mSvZgRz0V1QTNCzfAI1aIRzbiufJtkMIlEp58=
+golang.org/x/crypto v0.13.0/go.mod h1:y6Z2r+Rw4iayiXXAIxJIDAJ1zMW4yaTpebo8fPOliYc=
 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.26.0 h1:RrRspgV4mU+YwB4FYnuBoKsUapNIL5cohGAmSH3azsw=
-golang.org/x/crypto v0.26.0/go.mod h1:GY7jblb9wI+FOo5y8/S2oY4zWP07AkOJ4+jxCqdqn54=
+golang.org/x/crypto v0.23.0/go.mod h1:CKFgDieR+mRhux2Lsu27y0fO304Db0wZe70UKqHu0v8=
+golang.org/x/crypto v0.31.0/go.mod h1:kDsLvtWBEx7MV9tJOj9bnXsPbxwJQ6csT/x4KIN4Ssk=
+golang.org/x/crypto v0.37.0 h1:kJNSjF/Xp7kU0iB2Z+9viTPMW4EqqsrywMXLJOOsXSE=
+golang.org/x/crypto v0.37.0/go.mod h1:vg+k43peMZ0pUMhYmVAWysMK35e6ioLh3wB8ZCAfbVc=
 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.20.0 h1:utOm6MM3R3dnawAiJgn0y+xvuYRsm1RKM/4giyfDgV0=
-golang.org/x/mod v0.20.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.12.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
+golang.org/x/mod v0.15.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.17.0/go.mod h1:hTbmBsO62+eylJbnUtE2MGJUyE7QWk4xUqPFrRgJ+7c=
+golang.org/x/mod v0.24.0 h1:ZfthKaKaT4NrhGVZHO1/WDTwGES4De8KtWO0SIbNJMU=
+golang.org/x/mod v0.24.0/go.mod h1:IXM97Txy2VM4PJ3gI61r1YEk/gAj6zAHN3AdZt6S9Ww=
 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=
@@ -75,14 +81,19 @@ golang.org/x/net v0.0.0-20220722155237-a
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 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.15.0/go.mod h1:idbUs1IY1+zTqbi8yxTbhexhEEk5ur9LInksu6HrEpk=
 golang.org/x/net v0.21.0/go.mod h1:bIjVDfnllIU7BJ2DNgfnXvpSvtn8VRwhlsaeUTyUS44=
-golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc=
-golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg=
+golang.org/x/net v0.25.0/go.mod h1:JkAGAh7GEvH74S6FOH42FLoXpXbE/aqXSrIQjXgsiwM=
+golang.org/x/net v0.33.0 h1:74SYHlV8BIgHIFC/LrYkOGIwL19eTYXQ5wc6TBuO36I=
+golang.org/x/net v0.33.0/go.mod h1:HXLR5J+9DxmrqMwG9qjGCxZ+zKXxBru04zlTvWlWuN4=
 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=
-golang.org/x/sync v0.6.0 h1:5BMeUDZ7vkXGfEr1x9B4bRcTH4lpkTkpdh0T/J+qjbQ=
+golang.org/x/sync v0.3.0/go.mod h1:FU7BRWz2tNW+3quACPkgCx/L+uEAv1htQ0V83Z9Rj+Y=
 golang.org/x/sync v0.6.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+golang.org/x/sync v0.7.0/go.mod h1:Czt+wKu1gCyEFDUtn0jG5QVvpJ6rzVqr5aXyt9drQfk=
+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.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
@@ -90,24 +101,34 @@ golang.org/x/sys v0.0.0-20220520151302-b
 golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 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.12.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.20.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/sys v0.28.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA=
+golang.org/x/telemetry v0.0.0-20240228155512-f48c80bd79b2/go.mod h1:TeRTkGYfJXctD9OcfyVLyj2J3IxLnKwHJR8f4D8a3YE=
 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.12.0/go.mod h1:owVbMEjm3cBLCHdkQu9b1opXd4ETQWc3BhuQGKgXgvU=
 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.20.0/go.mod h1:8UkIAJTvZgivsXaD6/pH6U9ecQzZ45awqEOzuCvwpFY=
+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=
 golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
+golang.org/x/text v0.13.0/go.mod h1:TvPlkZtksWOMsz7fbANvkp4WM8x/WCo/om8BMLbz+aE=
 golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.15.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU=
+golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
 golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
+golang.org/x/tools v0.13.0/go.mod h1:HvlwmtVNQAhOuCjW7xxvovg8wbNq7LwfXh/k7wXUl58=
+golang.org/x/tools v0.21.1-0.20240508182429-e35e4ccd0d2d/go.mod h1:aiJjzUbINMkxbQROHiO6hDPo2LHcIPhhQsa9DLh0yGk=
 golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
 gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
diff -pruN 1.2.1-4/internal/file/file.go 1.3.2-1/internal/file/file.go
--- 1.2.1-4/internal/file/file.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/internal/file/file.go	2025-10-31 17:46:39.000000000 +0000
@@ -15,6 +15,7 @@ package file
 
 import (
 	"errors"
+	"fmt"
 	"io"
 	"io/fs"
 	"os"
@@ -23,6 +24,11 @@ import (
 	"strings"
 )
 
+const (
+	// tempFileNamePrefix is the prefix of the temporary file
+	tempFileNamePrefix = "notation-*"
+)
+
 // ErrNotRegularFile is returned when the file is not an regular file.
 var ErrNotRegularFile = errors.New("not regular file")
 
@@ -110,3 +116,38 @@ func CopyDirToDir(src, dst string) error
 func TrimFileExtension(fileName string) string {
 	return strings.TrimSuffix(fileName, filepath.Ext(fileName))
 }
+
+// WriteFile writes content to a temporary file and moves it to path.
+// If path already exists and is a file, WriteFile overwrites it.
+//
+// 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)
+	}
+	defer func() {
+		// remove the temp file in case of error
+		if writeErr != nil {
+			tempFile.Close()
+			os.Remove(tempFile.Name())
+		}
+	}()
+
+	if _, err := tempFile.Write(content); err != nil {
+		return fmt.Errorf("failed to write content to temp file: %w", err)
+	}
+
+	// close before moving
+	if err := tempFile.Close(); err != nil {
+		return fmt.Errorf("failed to close temp file: %w", err)
+	}
+
+	// rename is atomic on UNIX-like platforms
+	return os.Rename(tempFile.Name(), path)
+}
diff -pruN 1.2.1-4/internal/file/file_test.go 1.3.2-1/internal/file/file_test.go
--- 1.2.1-4/internal/file/file_test.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/internal/file/file_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -18,6 +18,7 @@ import (
 	"os"
 	"path/filepath"
 	"runtime"
+	"strings"
 	"testing"
 )
 
@@ -26,7 +27,10 @@ func TestCopyToDir(t *testing.T) {
 		tempDir := t.TempDir()
 		data := []byte("data")
 		filename := filepath.Join(tempDir, "a", "file.txt")
-		if err := writeFile(filename, data); err != nil {
+		if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil {
+			t.Fatal(err)
+		}
+		if err := WriteFile(tempDir, filename, data); err != nil {
 			t.Fatal(err)
 		}
 
@@ -45,7 +49,10 @@ func TestCopyToDir(t *testing.T) {
 		destDir := t.TempDir()
 		data := []byte("data")
 		filename := filepath.Join(tempDir, "a", "file.txt")
-		if err := writeFile(filename, data); err != nil {
+		if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil {
+			t.Fatal(err)
+		}
+		if err := WriteFile(tempDir, filename, data); err != nil {
 			t.Fatal(err)
 		}
 
@@ -77,7 +84,10 @@ func TestCopyToDir(t *testing.T) {
 		data := []byte("data")
 		// prepare file
 		filename := filepath.Join(tempDir, "a", "file.txt")
-		if err := writeFile(filename, data); err != nil {
+		if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil {
+			t.Fatal(err)
+		}
+		if err := WriteFile(tempDir, filename, data); err != nil {
 			t.Fatal(err)
 		}
 		// forbid reading
@@ -100,7 +110,10 @@ func TestCopyToDir(t *testing.T) {
 		data := []byte("data")
 		// prepare file
 		filename := filepath.Join(tempDir, "a", "file.txt")
-		if err := writeFile(filename, data); err != nil {
+		if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil {
+			t.Fatal(err)
+		}
+		if err := WriteFile(tempDir, filename, data); err != nil {
 			t.Fatal(err)
 		}
 		// forbid dest directory operation
@@ -123,7 +136,10 @@ func TestCopyToDir(t *testing.T) {
 		data := []byte("data")
 		// prepare file
 		filename := filepath.Join(tempDir, "a", "file.txt")
-		if err := writeFile(filename, data); err != nil {
+		if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil {
+			t.Fatal(err)
+		}
+		if err := WriteFile(tempDir, filename, data); err != nil {
 			t.Fatal(err)
 		}
 		// forbid writing to destTempDir
@@ -140,7 +156,10 @@ func TestCopyToDir(t *testing.T) {
 		tempDir := t.TempDir()
 		data := []byte("data")
 		filename := filepath.Join(tempDir, "a", "file.txt")
-		if err := writeFile(filename, data); err != nil {
+		if err := os.MkdirAll(filepath.Dir(filename), 0700); err != nil {
+			t.Fatal(err)
+		}
+		if err := WriteFile(tempDir, filename, data); err != nil {
 			t.Fatal(err)
 		}
 
@@ -161,6 +180,29 @@ func TestFileNameWithoutExtension(t *tes
 	}
 }
 
+func TestWriteFile(t *testing.T) {
+	tempDir := t.TempDir()
+	content := []byte("test WriteFile")
+
+	t.Run("permission denied", func(t *testing.T) {
+		if runtime.GOOS == "windows" {
+			t.Skip("skipping test on Windows")
+		}
+		err := os.Chmod(tempDir, 0)
+		if err != nil {
+			t.Fatal(err)
+		}
+		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)
+		}
+		err = os.Chmod(tempDir, 0700)
+		if err != nil {
+			t.Fatal(err)
+		}
+	})
+}
+
 func validFileContent(t *testing.T, filename string, content []byte) {
 	b, err := os.ReadFile(filename)
 	if err != nil {
@@ -170,10 +212,3 @@ func validFileContent(t *testing.T, file
 		t.Fatal("file content is not correct")
 	}
 }
-
-func writeFile(path string, data []byte) error {
-	if err := os.MkdirAll(filepath.Dir(path), 0700); err != nil {
-		return err
-	}
-	return os.WriteFile(path, data, 0600)
-}
diff -pruN 1.2.1-4/internal/io/limitedwriter.go 1.3.2-1/internal/io/limitedwriter.go
--- 1.2.1-4/internal/io/limitedwriter.go	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.2-1/internal/io/limitedwriter.go	2025-10-31 17:46:39.000000000 +0000
@@ -0,0 +1,53 @@
+// 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 io provides a LimitWriter that writes to an underlying writer up to
+// a limit.
+
+package io
+
+import (
+	"errors"
+	"io"
+)
+
+// ErrLimitExceeded is returned when the write limit is exceeded.
+var ErrLimitExceeded = errors.New("write limit exceeded")
+
+// LimitedWriter is a writer that writes to an underlying writer up to a limit.
+type LimitedWriter struct {
+	W io.Writer // underlying writer
+	N int64     // remaining bytes
+}
+
+// LimitWriter returns a new LimitWriter that writes to w.
+//
+// parameters:
+// w: the writer to write to
+// limit: the maximum number of bytes to write
+func LimitWriter(w io.Writer, limit int64) *LimitedWriter {
+	return &LimitedWriter{W: w, N: limit}
+}
+
+// Write writes p to the underlying writer up to the limit.
+func (l *LimitedWriter) Write(p []byte) (int, error) {
+	if l.N <= 0 {
+		return 0, ErrLimitExceeded
+	}
+	if int64(len(p)) > l.N {
+		p = p[:l.N]
+	}
+	n, err := l.W.Write(p)
+	l.N -= int64(n)
+	return n, err
+}
diff -pruN 1.2.1-4/internal/io/limitedwriter_test.go 1.3.2-1/internal/io/limitedwriter_test.go
--- 1.2.1-4/internal/io/limitedwriter_test.go	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.2-1/internal/io/limitedwriter_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -0,0 +1,67 @@
+// 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 io
+
+import (
+	"bytes"
+	"errors"
+	"testing"
+)
+
+func TestLimitWriter(t *testing.T) {
+	limit := int64(10)
+
+	tests := []struct {
+		input    string
+		expected string
+		written  int
+	}{
+		{"hello", "hello", 5},
+		{" world", " world", 6},
+		{"!", "!", 1},
+		{"1234567891011", "1234567891", 10},
+	}
+
+	for _, tt := range tests {
+		var buf bytes.Buffer
+		lw := LimitWriter(&buf, limit)
+		n, err := lw.Write([]byte(tt.input))
+		if err != nil {
+			t.Fatalf("unexpected error: %v", err)
+		}
+		if n != tt.written {
+			t.Errorf("expected %d bytes written, got %d", tt.written, n)
+		}
+		if buf.String() != tt.expected {
+			t.Errorf("expected buffer %q, got %q", tt.expected, buf.String())
+		}
+	}
+}
+
+func TestLimitWriterFailed(t *testing.T) {
+	limit := int64(10)
+	longString := "1234567891011"
+
+	var buf bytes.Buffer
+	lw := LimitWriter(&buf, limit)
+	_, err := lw.Write([]byte(longString))
+	if err != nil {
+		t.Fatalf("unexpected error: %v", err)
+	}
+	_, err = lw.Write([]byte(longString))
+	expectedErr := errors.New("write limit exceeded")
+	if err.Error() != expectedErr.Error() {
+		t.Errorf("expected error %v, got %v", expectedErr, err)
+	}
+}
diff -pruN 1.2.1-4/internal/pkix/fuzz_test.go 1.3.2-1/internal/pkix/fuzz_test.go
--- 1.2.1-4/internal/pkix/fuzz_test.go	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.2-1/internal/pkix/fuzz_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -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)
+	})
+}
diff -pruN 1.2.1-4/notation.go 1.3.2-1/notation.go
--- 1.2.1-4/notation.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/notation.go	2025-10-31 17:46:39.000000000 +0000
@@ -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.
@@ -128,7 +134,7 @@ func Sign(ctx context.Context, signer Si
 		}
 		// 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 {
@@ -351,10 +357,10 @@ func Verify(ctx context.Context, verifie
 			return ocispec.Descriptor{}, nil, err
 		}
 		if skip {
-			logger.Infoln("Verification skipped for", verifyOpts.ArtifactReference)
+			logger.Infoln("Signature verification skipped for", verifyOpts.ArtifactReference)
 			return ocispec.Descriptor{}, []*VerificationOutcome{{VerificationLevel: verificationLevel}}, nil
 		}
-		logger.Info("Check over. Trust policy is not configured to skip signature verification")
+		logger.Info("Check over. The signature verification level is not set to 'skip' in the trust policy.")
 	}
 
 	// get artifact descriptor
@@ -372,7 +378,7 @@ func Verify(ctx context.Context, verifie
 	}
 	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 -pruN 1.2.1-4/notation_test.go 1.3.2-1/notation_test.go
--- 1.2.1-4/notation_test.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/notation_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -225,7 +225,7 @@ func TestSignOptsUnknownMediaType(t *tes
 func TestRegistryResolveError(t *testing.T) {
 	repo := mock.NewRepository()
 	policyDocument := dummyPolicyDocument()
-	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict}
+	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict, false}
 
 	errorMessage := "network error"
 	expectedErr := ErrorSignatureRetrievalFailed{Msg: errorMessage}
@@ -243,7 +243,7 @@ func TestRegistryResolveError(t *testing
 func TestVerifyEmptyReference(t *testing.T) {
 	repo := mock.NewRepository()
 	policyDocument := dummyPolicyDocument()
-	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict}
+	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict, false}
 
 	errorMessage := "reference is missing digest or tag"
 	expectedErr := ErrorSignatureRetrievalFailed{Msg: errorMessage}
@@ -259,7 +259,7 @@ func TestVerifyEmptyReference(t *testing
 func TestVerifyTagReferenceFailed(t *testing.T) {
 	repo := mock.NewRepository()
 	policyDocument := dummyPolicyDocument()
-	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict}
+	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict, false}
 
 	errorMessage := "invalid reference: invalid repository \"UPPERCASE/test\""
 	expectedErr := ErrorSignatureRetrievalFailed{Msg: errorMessage}
@@ -276,7 +276,7 @@ func TestVerifyDigestNotMatchResolve(t *
 	repo := mock.NewRepository()
 	repo.MissMatchDigest = true
 	policyDocument := dummyPolicyDocument()
-	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict}
+	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict, false}
 
 	errorMessage := fmt.Sprintf("user input digest %s does not match the resolved digest %s", mock.SampleDigest, mock.ZeroDigest)
 	expectedErr := ErrorSignatureRetrievalFailed{Msg: errorMessage}
@@ -300,7 +300,7 @@ func TestSignDigestNotMatchResolve(t *te
 	}
 
 	errorMessage := fmt.Sprintf("user input digest %s does not match the resolved digest %s", mock.SampleDigest, mock.ZeroDigest)
-	expectedErr := fmt.Errorf(errorMessage)
+	expectedErr := errors.New(errorMessage)
 
 	_, err := Sign(context.Background(), &dummySigner{}, repo, signOpts)
 	if err == nil || err.Error() != errorMessage {
@@ -311,7 +311,7 @@ func TestSignDigestNotMatchResolve(t *te
 func TestSkippedSignatureVerification(t *testing.T) {
 	repo := mock.NewRepository()
 	policyDocument := dummyPolicyDocument()
-	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelSkip}
+	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelSkip, false}
 
 	opts := VerifyOptions{ArtifactReference: mock.SampleArtifactUri, MaxSignatureAttempts: 50}
 	_, outcomes, err := Verify(context.Background(), &verifier, repo, opts)
@@ -324,7 +324,7 @@ func TestSkippedSignatureVerification(t
 func TestRegistryNoSignatureManifests(t *testing.T) {
 	repo := mock.NewRepository()
 	policyDocument := dummyPolicyDocument()
-	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict}
+	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict, false}
 	errorMessage := fmt.Sprintf("no signature is associated with %q, make sure the artifact was signed successfully", mock.SampleArtifactUri)
 	expectedErr := ErrorSignatureRetrievalFailed{Msg: errorMessage}
 
@@ -341,7 +341,7 @@ func TestRegistryNoSignatureManifests(t
 func TestRegistryFetchSignatureBlobError(t *testing.T) {
 	repo := mock.NewRepository()
 	policyDocument := dummyPolicyDocument()
-	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict}
+	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict, false}
 	errorMessage := fmt.Sprintf("unable to retrieve digital signature with digest %q associated with %q from the Repository, error : network error", mock.SampleDigest, mock.SampleArtifactUri)
 	expectedErr := ErrorSignatureRetrievalFailed{Msg: errorMessage}
 
@@ -358,21 +358,35 @@ func TestRegistryFetchSignatureBlobError
 func TestVerifyValid(t *testing.T) {
 	repo := mock.NewRepository()
 	policyDocument := dummyPolicyDocument()
-	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict}
+	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict, false}
 
 	// mock the repository
 	opts := VerifyOptions{ArtifactReference: mock.SampleArtifactUri, MaxSignatureAttempts: 50}
 	_, _, err := Verify(context.Background(), &verifier, repo, opts)
 
 	if err != nil {
-		t.Fatalf("SignaureMediaTypeMismatch expected: %v got: %v", nil, err)
+		t.Fatalf("expected nil error, but got: %v", err)
+	}
+}
+
+func TestVerifySkip(t *testing.T) {
+	repo := mock.NewRepository()
+	policyDocument := dummyPolicyDocument()
+	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict, true}
+
+	// mock the repository
+	opts := VerifyOptions{ArtifactReference: mock.SampleArtifactUri, MaxSignatureAttempts: 50}
+	_, _, err := Verify(context.Background(), &verifier, repo, opts)
+
+	if err != nil {
+		t.Fatalf("expected nil error, but got: %v", err)
 	}
 }
 
 func TestMaxSignatureAttemptsMissing(t *testing.T) {
 	repo := mock.NewRepository()
 	policyDocument := dummyPolicyDocument()
-	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict}
+	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict, false}
 	expectedErr := ErrorSignatureRetrievalFailed{Msg: fmt.Sprintf("verifyOptions.MaxSignatureAttempts expects a positive number, got %d", 0)}
 
 	// mock the repository
@@ -388,7 +402,7 @@ func TestExceededMaxSignatureAttempts(t
 	repo := mock.NewRepository()
 	repo.ExceededNumOfSignatures = true
 	policyDocument := dummyPolicyDocument()
-	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, true, *trustpolicy.LevelStrict}
+	verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, true, *trustpolicy.LevelStrict, false}
 
 	expectedErr := ErrorVerificationFailed{Msg: fmt.Sprintf("signature evaluation stopped. The configured limit of %d signatures to verify per artifact exceeded", 1)}
 
@@ -405,7 +419,7 @@ func TestVerifyFailed(t *testing.T) {
 	t.Run("verification error", func(t *testing.T) {
 		policyDocument := dummyPolicyDocument()
 		repo := mock.NewRepository()
-		verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, true, *trustpolicy.LevelStrict}
+		verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, true, *trustpolicy.LevelStrict, false}
 		expectedErr := ErrorVerificationFailed{}
 
 		// mock the repository
@@ -432,7 +446,7 @@ func TestVerifyFailed(t *testing.T) {
 
 	t.Run("repo is nil", func(t *testing.T) {
 		policyDocument := dummyPolicyDocument()
-		verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict}
+		verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict, false}
 		expectedErr := errors.New("repo cannot be nil")
 
 		// mock the repository
@@ -494,6 +508,7 @@ type dummyVerifier struct {
 	PluginManager     plugin.Manager
 	FailVerify        bool
 	VerificationLevel trustpolicy.VerificationLevel
+	SkipVerification  bool
 }
 
 func (v *dummyVerifier) Verify(_ context.Context, _ ocispec.Descriptor, _ []byte, _ VerifierVerifyOptions) (*VerificationOutcome, error) {
@@ -507,6 +522,13 @@ func (v *dummyVerifier) Verify(_ context
 	return outcome, nil
 }
 
+func (v *dummyVerifier) SkipVerify(_ context.Context, _ VerifierVerifyOptions) (bool, *trustpolicy.VerificationLevel, error) {
+	if v.SkipVerification {
+		return true, nil, nil
+	}
+	return false, nil, nil
+}
+
 var (
 	reference         = "sha256:19dbd2e48e921426ee8ace4dc892edfb2ecdc1d1a72d5416c83670c30acecef0"
 	artifactReference = "local/oci-layout@sha256:19dbd2e48e921426ee8ace4dc892edfb2ecdc1d1a72d5416c83670c30acecef0"
@@ -567,7 +589,7 @@ func TestLocalContent(t *testing.T) {
 			MaxSignatureAttempts: math.MaxInt64,
 		}
 		policyDocument := dummyPolicyDocument()
-		verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict}
+		verifier := dummyVerifier{&policyDocument, mock.PluginManager{}, false, *trustpolicy.LevelStrict, false}
 		// verify signatures inside the OCI layout folder
 		_, _, err = Verify(context.Background(), &verifier, repo, verifyOpts)
 		if err != nil {
diff -pruN 1.2.1-4/plugin/plugin.go 1.3.2-1/plugin/plugin.go
--- 1.2.1-4/plugin/plugin.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/plugin/plugin.go	2025-10-31 17:46:39.000000000 +0000
@@ -27,12 +27,16 @@ import (
 	"path/filepath"
 	"strings"
 
+	"github.com/notaryproject/notation-go/internal/io"
 	"github.com/notaryproject/notation-go/internal/slices"
 	"github.com/notaryproject/notation-go/log"
 	"github.com/notaryproject/notation-go/plugin/proto"
 	"github.com/notaryproject/notation-plugin-framework-go/plugin"
 )
 
+// maxPluginOutputSize is the maximum size of the plugin output.
+const maxPluginOutputSize = 64 * 1024 * 1024 // 64 MiB
+
 var executor commander = &execCommander{} // for unit test
 
 // GenericPlugin is the base requirement to be a plugin.
@@ -222,10 +226,15 @@ func (c execCommander) Output(ctx contex
 	var stdout, stderr bytes.Buffer
 	cmd := exec.CommandContext(ctx, name, string(command))
 	cmd.Stdin = bytes.NewReader(req)
-	cmd.Stderr = &stderr
-	cmd.Stdout = &stdout
+	// The limit writer will be handled by the caller in run() by comparing the
+	// bytes written with the expected length of the bytes.
+	cmd.Stderr = io.LimitWriter(&stderr, maxPluginOutputSize)
+	cmd.Stdout = io.LimitWriter(&stdout, maxPluginOutputSize)
 	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 -pruN 1.2.1-4/plugin/plugin_test.go 1.3.2-1/plugin/plugin_test.go
--- 1.2.1-4/plugin/plugin_test.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/plugin/plugin_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -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 *testi
 			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) {
diff -pruN 1.2.1-4/signer/signer.go 1.3.2-1/signer/signer.go
--- 1.2.1-4/signer/signer.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/signer/signer.go	2025-10-31 17:46:39.000000000 +0000
@@ -34,7 +34,7 @@ import (
 )
 
 // signingAgent is the unprotected header field used by signature.
-const signingAgent = "notation-go/1.2.1"
+const signingAgent = "notation-go/1.3.2"
 
 // GenericSigner implements notation.Signer and embeds signature.Signer
 type GenericSigner struct {
@@ -107,7 +107,6 @@ func (s *GenericSigner) Sign(ctx context
 	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
 			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
 	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
 	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 -pruN 1.2.1-4/signer/signer_test.go 1.3.2-1/signer/signer_test.go
--- 1.2.1-4/signer/signer_test.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/signer/signer_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -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
 	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) {
diff -pruN 1.2.1-4/verifier/crl/crl.go 1.3.2-1/verifier/crl/crl.go
--- 1.2.1-4/verifier/crl/crl.go	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.2-1/verifier/crl/crl.go	2025-10-31 17:46:39.000000000 +0000
@@ -0,0 +1,171 @@
+// 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 provides functionalities for crl revocation check.
+package crl
+
+import (
+	"context"
+	"crypto/sha256"
+	"crypto/x509"
+	"encoding/hex"
+	"encoding/json"
+	"errors"
+	"fmt"
+	"io/fs"
+	"os"
+	"path/filepath"
+	"time"
+
+	corecrl "github.com/notaryproject/notation-core-go/revocation/crl"
+	"github.com/notaryproject/notation-go/internal/file"
+	"github.com/notaryproject/notation-go/log"
+)
+
+// FileCache implements corecrl.Cache.
+//
+// Key: url of the CRL.
+//
+// Value: corecrl.Bundle.
+//
+// This cache builds on top of the UNIX file system to leverage the file system's
+// atomic operations. The `rename` and `remove` operations will unlink the old
+// file but keep the inode and file descriptor for existing processes to access
+// the file. The old inode will be dereferenced when all processes close the old
+// file descriptor. Additionally, the operations are proven to be atomic on
+// UNIX-like platforms, so there is no need to handle file locking.
+//
+// NOTE: For Windows, the `open`, `rename` and `remove` operations need file
+// locking to ensure atomicity. The current implementation does not handle
+// file locking, so the concurrent write from multiple processes may be failed.
+// Please do not use this cache in a multi-process environment on Windows.
+type FileCache struct {
+	// root is the root directory of the cache
+	root string
+}
+
+// fileCacheContent is the actual content saved in a FileCache
+type fileCacheContent struct {
+	// BaseCRL is the ASN.1 encoded base CRL
+	BaseCRL []byte `json:"baseCRL"`
+
+	// DeltaCRL is the ASN.1 encoded delta CRL
+	DeltaCRL []byte `json:"deltaCRL,omitempty"`
+}
+
+// NewFileCache creates a FileCache with root as the root directory
+//
+// An example for root is `dir.CacheFS().SysPath(dir.PathCRLCache)`
+func NewFileCache(root string) (*FileCache, error) {
+	if err := os.MkdirAll(root, 0700); err != nil {
+		return nil, fmt.Errorf("failed to create crl file cache: %w", err)
+	}
+	return &FileCache{
+		root: root,
+	}, nil
+}
+
+// Get retrieves CRL bundle from c given url as key. If the key does not exist
+// or the content has expired, corecrl.ErrCacheMiss is returned.
+func (c *FileCache) Get(ctx context.Context, url string) (*corecrl.Bundle, error) {
+	logger := log.GetLogger(ctx)
+	logger.Debugf("Retrieving crl bundle from file cache with key %q ...", url)
+
+	// get content from file cache
+	contentBytes, err := os.ReadFile(filepath.Join(c.root, c.fileName(url)))
+	if err != nil {
+		if errors.Is(err, fs.ErrNotExist) {
+			logger.Debugf("CRL file cache miss. Key %q does not exist", url)
+			return nil, corecrl.ErrCacheMiss
+		}
+		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 {
+		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 {
+		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 {
+			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 {
+		return nil, fmt.Errorf("check BaseCRL expiry failed: %w", err)
+	}
+	if bundle.DeltaCRL != nil {
+		if err := checkExpiry(ctx, bundle.DeltaCRL.NextUpdate); err != nil {
+			return nil, fmt.Errorf("check DeltaCRL expiry failed: %w", err)
+		}
+	}
+
+	return &bundle, nil
+}
+
+// Set stores the CRL bundle in c with url as key.
+func (c *FileCache) Set(ctx context.Context, url string, bundle *corecrl.Bundle) error {
+	logger := log.GetLogger(ctx)
+	logger.Debugf("Storing crl bundle to file cache with key %q ...", url)
+
+	if bundle == nil {
+		return errors.New("failed to store crl bundle in file cache: bundle cannot be nil")
+	}
+	if bundle.BaseCRL == nil {
+		return errors.New("failed to store crl bundle in file cache: bundle BaseCRL cannot be nil")
+	}
+
+	// actual content to be saved in the cache
+	content := fileCacheContent{
+		BaseCRL: bundle.BaseCRL.Raw,
+	}
+	if bundle.DeltaCRL != nil {
+		content.DeltaCRL = bundle.DeltaCRL.Raw
+	}
+	contentBytes, err := json.Marshal(content)
+	if err != nil {
+		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 {
+		return fmt.Errorf("failed to store crl bundle in file cache: %w", err)
+	}
+	return nil
+}
+
+// fileName returns the filename of the content stored in c
+func (c *FileCache) fileName(url string) string {
+	hash := sha256.Sum256([]byte(url))
+	return hex.EncodeToString(hash[:])
+}
+
+// checkExpiry returns nil when nextUpdate is bounded before current time
+func checkExpiry(ctx context.Context, nextUpdate time.Time) error {
+	logger := log.GetLogger(ctx)
+
+	if nextUpdate.IsZero() {
+		return errors.New("crl bundle retrieved from file cache does not contain valid NextUpdate")
+	}
+	if time.Now().After(nextUpdate) {
+		logger.Debugf("CRL bundle retrieved from file cache has expired at %s", nextUpdate)
+		return corecrl.ErrCacheMiss
+	}
+	return nil
+}
diff -pruN 1.2.1-4/verifier/crl/crl_test.go 1.3.2-1/verifier/crl/crl_test.go
--- 1.2.1-4/verifier/crl/crl_test.go	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.2-1/verifier/crl/crl_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -0,0 +1,395 @@
+// 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"
+	"crypto/rand"
+	"crypto/x509"
+	"encoding/json"
+	"errors"
+	"math/big"
+	"os"
+	"path/filepath"
+	"reflect"
+	"runtime"
+	"strings"
+	"testing"
+	"time"
+
+	corecrl "github.com/notaryproject/notation-core-go/revocation/crl"
+	"github.com/notaryproject/notation-core-go/testhelper"
+)
+
+func TestCache(t *testing.T) {
+	t.Run("file cache implement Cache interface", func(t *testing.T) {
+		root := t.TempDir()
+		var coreCache corecrl.Cache
+		var err error
+		coreCache, err = NewFileCache(root)
+		if err != nil {
+			t.Fatal(err)
+		}
+		if _, ok := coreCache.(*FileCache); !ok {
+			t.Fatal("FileCache does not implement coreCache")
+		}
+	})
+}
+
+func TestFileCache(t *testing.T) {
+	now := time.Now()
+	certChain := testhelper.GetRevokableRSAChainWithRevocations(2, false, true)
+	crlBytes, err := x509.CreateRevocationList(rand.Reader, &x509.RevocationList{
+		Number:     big.NewInt(1),
+		NextUpdate: now.Add(time.Hour),
+	}, certChain[1].Cert, certChain[1].PrivateKey)
+	if err != nil {
+		t.Fatal(err)
+	}
+	baseCRL, err := x509.ParseRevocationList(crlBytes)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	ctx := context.Background()
+	root := t.TempDir()
+	cache, err := NewFileCache(root)
+	t.Run("NewFileCache", func(t *testing.T) {
+		if err != nil {
+			t.Fatalf("expected no error, but got %v", err)
+		}
+		if cache.root != root {
+			t.Fatalf("expected root %v, but got %v", root, cache.root)
+		}
+	})
+
+	key := "http://example.com"
+	t.Run("comformance", func(t *testing.T) {
+		bundle := &corecrl.Bundle{BaseCRL: baseCRL}
+		if err := cache.Set(ctx, key, bundle); err != nil {
+			t.Fatal(err)
+		}
+		retrievedBundle, err := cache.Get(ctx, key)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if !reflect.DeepEqual(retrievedBundle.BaseCRL, bundle.BaseCRL) {
+			t.Fatalf("expected BaseCRL %+v, but got %+v", bundle.BaseCRL, retrievedBundle.BaseCRL)
+		}
+
+		if bundle.DeltaCRL != nil {
+			t.Fatalf("expected DeltaCRL to be nil, but got %+v", retrievedBundle.DeltaCRL)
+		}
+	})
+
+	t.Run("comformance with delta crl", func(t *testing.T) {
+		crlBytes, err := x509.CreateRevocationList(rand.Reader, &x509.RevocationList{
+			Number:     big.NewInt(2),
+			NextUpdate: now.Add(time.Hour),
+		}, certChain[1].Cert, certChain[1].PrivateKey)
+		if err != nil {
+			t.Fatal(err)
+		}
+		deltaCRL, err := x509.ParseRevocationList(crlBytes)
+		if err != nil {
+			t.Fatal(err)
+		}
+		bundle := &corecrl.Bundle{BaseCRL: baseCRL, DeltaCRL: deltaCRL}
+		if err := cache.Set(ctx, key, bundle); err != nil {
+			t.Fatal(err)
+		}
+		retrievedBundle, err := cache.Get(ctx, key)
+		if err != nil {
+			t.Fatal(err)
+		}
+
+		if !reflect.DeepEqual(retrievedBundle.BaseCRL, bundle.BaseCRL) {
+			t.Fatalf("expected BaseCRL %+v, but got %+v", bundle.BaseCRL, retrievedBundle.BaseCRL)
+		}
+
+		if !reflect.DeepEqual(retrievedBundle.DeltaCRL, bundle.DeltaCRL) {
+			t.Fatalf("expected DeltaCRL %+v, but got %+v", bundle.DeltaCRL, retrievedBundle.DeltaCRL)
+		}
+	})
+}
+
+func TestNewFileCacheFailed(t *testing.T) {
+	tempDir := t.TempDir()
+	t.Run("without permission to create cache directory", func(t *testing.T) {
+		if runtime.GOOS == "windows" {
+			t.Skip("skipping test on Windows")
+		}
+
+		if err := os.Chmod(tempDir, 0); err != nil {
+			t.Fatal(err)
+		}
+		root := filepath.Join(tempDir, "test")
+		_, err := NewFileCache(root)
+		if !strings.Contains(err.Error(), "permission denied") {
+			t.Fatalf("expected permission denied error, but got %v", err)
+		}
+		// restore permission
+		if err := os.Chmod(tempDir, 0755); err != nil {
+			t.Fatalf("failed to change permission: %v", err)
+		}
+	})
+}
+
+func TestGetFailed(t *testing.T) {
+	tempDir := t.TempDir()
+	cache, err := NewFileCache(tempDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	t.Run("key does not exist", func(t *testing.T) {
+		_, err := cache.Get(context.Background(), "nonExistKey")
+		if !errors.Is(err, corecrl.ErrCacheMiss) {
+			t.Fatalf("expected ErrCacheMiss, but got %v", err)
+		}
+	})
+
+	invalidFile := filepath.Join(tempDir, cache.fileName("invalid"))
+	if err := os.WriteFile(invalidFile, []byte("invalid"), 0644); err != nil {
+		t.Fatalf("failed to write file: %v", err)
+	}
+
+	t.Run("no permission to read file", func(t *testing.T) {
+		if runtime.GOOS == "windows" {
+			t.Skip("skipping test on Windows")
+		}
+
+		if err := os.Chmod(invalidFile, 0); err != nil {
+			t.Fatal(err)
+		}
+		_, err := cache.Get(context.Background(), "invalid")
+		if err == nil || !strings.Contains(err.Error(), "permission denied") {
+			t.Fatalf("expected permission denied error, but got %v", err)
+		}
+		// restore permission
+		if err := os.Chmod(invalidFile, 0755); err != nil {
+			t.Fatal(err)
+		}
+	})
+
+	t.Run("invalid content", func(t *testing.T) {
+		_, err := cache.Get(context.Background(), "invalid")
+		expectedErrMsg := "failed to decode file retrieved from file cache: invalid character 'i' looking for beginning of value"
+		if err == nil || err.Error() != expectedErrMsg {
+			t.Fatalf("expected %s, but got %v", expectedErrMsg, err)
+		}
+	})
+
+	now := time.Now()
+	certChain := testhelper.GetRevokableRSAChainWithRevocations(2, false, true)
+	crlBytes, err := x509.CreateRevocationList(rand.Reader, &x509.RevocationList{
+		Number: big.NewInt(1),
+	}, certChain[1].Cert, certChain[1].PrivateKey)
+	if err != nil {
+		t.Fatalf("failed to create base CRL: %v", err)
+	}
+	baseCRL, err := x509.ParseRevocationList(crlBytes)
+	if err != nil {
+		t.Fatalf("failed to parse base CRL: %v", err)
+	}
+
+	t.Run("empty RawBaseCRL of content", func(t *testing.T) {
+		content := fileCacheContent{
+			BaseCRL: []byte{},
+		}
+		b, err := json.Marshal(content)
+		if err != nil {
+			t.Fatal(err)
+		}
+		invalidBundleFile := filepath.Join(tempDir, cache.fileName("invalidBundle"))
+		if err := os.WriteFile(invalidBundleFile, b, 0644); err != nil {
+			t.Fatalf("failed to write file: %v", err)
+		}
+		_, err = cache.Get(context.Background(), "invalidBundle")
+		expectedErrMsg := "failed to parse base CRL of file retrieved from file cache: x509: malformed crl"
+		if err == nil || err.Error() != expectedErrMsg {
+			t.Fatalf("expected %s, but got %v", expectedErrMsg, err)
+		}
+	})
+
+	t.Run("invalid RawBaseCRL of content", func(t *testing.T) {
+		content := fileCacheContent{
+			BaseCRL: []byte("invalid"),
+		}
+		b, err := json.Marshal(content)
+		if err != nil {
+			t.Fatal(err)
+		}
+		invalidBundleFile := filepath.Join(tempDir, cache.fileName("invalidBundle"))
+		if err := os.WriteFile(invalidBundleFile, b, 0644); err != nil {
+			t.Fatalf("failed to write file: %v", err)
+		}
+		_, err = cache.Get(context.Background(), "invalidBundle")
+		expectedErrMsg := "failed to parse base CRL of file retrieved from file cache: x509: malformed crl"
+		if err == nil || err.Error() != expectedErrMsg {
+			t.Fatalf("expected %s, but got %v", expectedErrMsg, err)
+		}
+	})
+
+	t.Run("invalid RawDeltaCRL of content", func(t *testing.T) {
+		content := fileCacheContent{
+			BaseCRL:  baseCRL.Raw,
+			DeltaCRL: []byte("invalid"),
+		}
+		b, err := json.Marshal(content)
+		if err != nil {
+			t.Fatal(err)
+		}
+		invalidBundleFile := filepath.Join(tempDir, cache.fileName("invalidBundle"))
+		if err := os.WriteFile(invalidBundleFile, b, 0644); err != nil {
+			t.Fatalf("failed to write file: %v", err)
+		}
+		_, err = cache.Get(context.Background(), "invalidBundle")
+		expectedErrMsg := "failed to parse delta CRL of file retrieved from file cache: x509: malformed crl"
+		if err == nil || err.Error() != expectedErrMsg {
+			t.Fatalf("expected %s, but got %v", expectedErrMsg, err)
+		}
+	})
+
+	t.Run("bundle with invalid NextUpdate", func(t *testing.T) {
+		ctx := context.Background()
+		expiredBundle := &corecrl.Bundle{BaseCRL: baseCRL}
+		if err := cache.Set(ctx, "expiredKey", expiredBundle); err != nil {
+			t.Fatal(err)
+		}
+		_, err = cache.Get(ctx, "expiredKey")
+		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)
+		}
+	})
+
+	crlBytes, err = x509.CreateRevocationList(rand.Reader, &x509.RevocationList{
+		Number:     big.NewInt(1),
+		NextUpdate: now.Add(-time.Hour),
+	}, certChain[1].Cert, certChain[1].PrivateKey)
+	if err != nil {
+		t.Fatalf("failed to create base CRL: %v", err)
+	}
+	expiredBaseCRL, err := x509.ParseRevocationList(crlBytes)
+	if err != nil {
+		t.Fatalf("failed to parse base CRL: %v", err)
+	}
+	t.Run("base crl in cache has expired", func(t *testing.T) {
+		ctx := context.Background()
+		expiredBundle := &corecrl.Bundle{BaseCRL: expiredBaseCRL}
+		if err := cache.Set(ctx, "expiredKey", expiredBundle); err != nil {
+			t.Fatal(err)
+		}
+		_, err = cache.Get(ctx, "expiredKey")
+		if !errors.Is(err, corecrl.ErrCacheMiss) {
+			t.Fatalf("expected ErrCacheMiss, but got %v", err)
+		}
+	})
+
+	t.Run("delta crl in cache has expired", func(t *testing.T) {
+		ctx := context.Background()
+		crlBytes, err := x509.CreateRevocationList(rand.Reader, &x509.RevocationList{
+			Number:     big.NewInt(1),
+			NextUpdate: now.Add(time.Hour),
+		}, certChain[1].Cert, certChain[1].PrivateKey)
+		if err != nil {
+			t.Fatalf("failed to create base CRL: %v", err)
+		}
+		baseCRL, err := x509.ParseRevocationList(crlBytes)
+		if err != nil {
+			t.Fatalf("failed to parse base CRL: %v", err)
+		}
+		crlBytes, err = x509.CreateRevocationList(rand.Reader, &x509.RevocationList{
+			Number:     big.NewInt(1),
+			NextUpdate: now.Add(-time.Hour),
+		}, certChain[1].Cert, certChain[1].PrivateKey)
+		if err != nil {
+			t.Fatalf("failed to create base CRL: %v", err)
+		}
+		expiredDeltaCRL, err := x509.ParseRevocationList(crlBytes)
+		if err != nil {
+			t.Fatalf("failed to parse base CRL: %v", err)
+		}
+		expiredBundle := &corecrl.Bundle{BaseCRL: baseCRL, DeltaCRL: expiredDeltaCRL}
+		if err := cache.Set(ctx, "expiredKey", expiredBundle); err != nil {
+			t.Fatal(err)
+		}
+		_, err = cache.Get(ctx, "expiredKey")
+		if !errors.Is(err, corecrl.ErrCacheMiss) {
+			t.Fatalf("expected ErrCacheMiss, but got %v", err)
+		}
+	})
+}
+
+func TestSetFailed(t *testing.T) {
+	tempDir := t.TempDir()
+	cache, err := NewFileCache(tempDir)
+	if err != nil {
+		t.Fatal(err)
+	}
+
+	now := time.Now()
+	certChain := testhelper.GetRevokableRSAChainWithRevocations(2, false, true)
+	crlBytes, err := x509.CreateRevocationList(rand.Reader, &x509.RevocationList{
+		Number:     big.NewInt(1),
+		NextUpdate: now.Add(time.Hour),
+	}, certChain[1].Cert, certChain[1].PrivateKey)
+	if err != nil {
+		t.Fatal(err)
+	}
+	baseCRL, err := x509.ParseRevocationList(crlBytes)
+	if err != nil {
+		t.Fatal(err)
+	}
+	ctx := context.Background()
+	key := "testKey"
+
+	t.Run("nil bundle", func(t *testing.T) {
+		err := cache.Set(ctx, key, nil)
+		expectedErrMsg := "failed to store crl bundle in file cache: bundle cannot be nil"
+		if err == nil || err.Error() != expectedErrMsg {
+			t.Fatalf("expected %s, but got %v", expectedErrMsg, err)
+		}
+	})
+
+	t.Run("nil bundle BaseCRL", func(t *testing.T) {
+		bundle := &corecrl.Bundle{}
+		err := cache.Set(ctx, key, bundle)
+		expectedErrMsg := "failed to store crl bundle in file cache: bundle BaseCRL cannot be nil"
+		if err == nil || err.Error() != expectedErrMsg {
+			t.Fatalf("expected %s, but got %v", expectedErrMsg, err)
+		}
+	})
+
+	t.Run("failed to write into cache due to permission denied", func(t *testing.T) {
+		if runtime.GOOS == "windows" {
+			t.Skip("skipping test on Windows")
+		}
+
+		if err := os.Chmod(tempDir, 0); err != nil {
+			t.Fatal(err)
+		}
+		bundle := &corecrl.Bundle{BaseCRL: baseCRL}
+		err := cache.Set(ctx, key, bundle)
+		if err == nil || !strings.Contains(err.Error(), "permission denied") {
+			t.Fatalf("expected permission denied error, but got %v", err)
+		}
+		// restore permission
+		if err := os.Chmod(tempDir, 0755); err != nil {
+			t.Fatalf("failed to change permission: %v", err)
+		}
+	})
+}
Binary files 1.2.1-4/verifier/testdata/truststore/x509/tsa/test-mismatch/DigiCertTSARootSHA384.cer and 1.3.2-1/verifier/testdata/truststore/x509/tsa/test-mismatch/DigiCertTSARootSHA384.cer differ
diff -pruN 1.2.1-4/verifier/testdata/truststore/x509/tsa/test-mismatch/wabbit-networks.io.crt 1.3.2-1/verifier/testdata/truststore/x509/tsa/test-mismatch/wabbit-networks.io.crt
--- 1.2.1-4/verifier/testdata/truststore/x509/tsa/test-mismatch/wabbit-networks.io.crt	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/verifier/testdata/truststore/x509/tsa/test-mismatch/wabbit-networks.io.crt	1970-01-01 00:00:00.000000000 +0000
@@ -1,20 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIDVjCCAj6gAwIBAgIBUTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzEL
-MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEb
-MBkGA1UEAxMSd2FiYml0LW5ldHdvcmtzLmlvMB4XDTIzMDExOTA4MTkwN1oXDTMz
-MDExOTA4MTkwN1owWjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQH
-EwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3RhcnkxGzAZBgNVBAMTEndhYmJpdC1uZXR3
-b3Jrcy5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANHhlP+SiY7h
-sGlf2mADOzJW/J9siqMkiQvSOx0OSM2yxetfVQL/abi4iqCXM6wkSxviBeNwIoYE
-s4thMA8NGEbnKoXktyh9vmiLB1FW7HHr4QLwjgLzgWJKIQTy1JmDBecXZh56d0f3
-w3Yj1IDTvkIScXCNI+5v/08GUQKhyBwv7Fq9MYpo2lfXSI7V33BKKddXIxPGVWwK
-GvPE0sg2VV7WM84ZZLdDKz2mq0PtPTHrSwg3hlK/mjn+blg3gsYQ4h9/7Z6nNaF9
-X0SdyESl841ZWrtMhAOFpIzLbz9ete8NRd3bYCRBIr5gscHWTf6lyUgy4xzsSwMH
-PsGLM4A+Z00CAwEAAaMnMCUwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsG
-AQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBAQAbN0Eru56uTQSC28ZTf8D7VyCkYrrW
-LYiJMYdOKBzzKV9mKaM0OGF2uyWwDaPxp9KTdLXmBp9EFq5SXXArFA+nRS7KinDA
-e2O7A/9Std2XjKi927rkA2cj239d5lRsjWXqJXf9vAMV9a2FjUM/in2Eevlq7bvj
-FE3l26VXCKtOs9ErmfxrL+6ETRKSVYOOG/rSHFv/SB2MlqDg5QsXC9lZjzL5/X/i
-oe2qZKhp6X5DPpad1q1Q4ItKdTN+2EXyMyoHn1BJKNba7CUUvXf03EJebT/Im+qo
-zfEksJeZJUSlSujANUPoCpsEYGWWQx5G+ViG05Sqs+6ppKrut+P+DVPo
------END CERTIFICATE-----
diff -pruN 1.2.1-4/verifier/testdata/truststore/x509/tsa/test-nonCA/wabbit-networks.io.crt 1.3.2-1/verifier/testdata/truststore/x509/tsa/test-nonCA/wabbit-networks.io.crt
--- 1.2.1-4/verifier/testdata/truststore/x509/tsa/test-nonCA/wabbit-networks.io.crt	1970-01-01 00:00:00.000000000 +0000
+++ 1.3.2-1/verifier/testdata/truststore/x509/tsa/test-nonCA/wabbit-networks.io.crt	2025-10-31 17:46:39.000000000 +0000
@@ -0,0 +1,20 @@
+-----BEGIN CERTIFICATE-----
+MIIDVjCCAj6gAwIBAgIBUTANBgkqhkiG9w0BAQsFADBaMQswCQYDVQQGEwJVUzEL
+MAkGA1UECBMCV0ExEDAOBgNVBAcTB1NlYXR0bGUxDzANBgNVBAoTBk5vdGFyeTEb
+MBkGA1UEAxMSd2FiYml0LW5ldHdvcmtzLmlvMB4XDTIzMDExOTA4MTkwN1oXDTMz
+MDExOTA4MTkwN1owWjELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAldBMRAwDgYDVQQH
+EwdTZWF0dGxlMQ8wDQYDVQQKEwZOb3RhcnkxGzAZBgNVBAMTEndhYmJpdC1uZXR3
+b3Jrcy5pbzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANHhlP+SiY7h
+sGlf2mADOzJW/J9siqMkiQvSOx0OSM2yxetfVQL/abi4iqCXM6wkSxviBeNwIoYE
+s4thMA8NGEbnKoXktyh9vmiLB1FW7HHr4QLwjgLzgWJKIQTy1JmDBecXZh56d0f3
+w3Yj1IDTvkIScXCNI+5v/08GUQKhyBwv7Fq9MYpo2lfXSI7V33BKKddXIxPGVWwK
+GvPE0sg2VV7WM84ZZLdDKz2mq0PtPTHrSwg3hlK/mjn+blg3gsYQ4h9/7Z6nNaF9
+X0SdyESl841ZWrtMhAOFpIzLbz9ete8NRd3bYCRBIr5gscHWTf6lyUgy4xzsSwMH
+PsGLM4A+Z00CAwEAAaMnMCUwDgYDVR0PAQH/BAQDAgeAMBMGA1UdJQQMMAoGCCsG
+AQUFBwMDMA0GCSqGSIb3DQEBCwUAA4IBAQAbN0Eru56uTQSC28ZTf8D7VyCkYrrW
+LYiJMYdOKBzzKV9mKaM0OGF2uyWwDaPxp9KTdLXmBp9EFq5SXXArFA+nRS7KinDA
+e2O7A/9Std2XjKi927rkA2cj239d5lRsjWXqJXf9vAMV9a2FjUM/in2Eevlq7bvj
+FE3l26VXCKtOs9ErmfxrL+6ETRKSVYOOG/rSHFv/SB2MlqDg5QsXC9lZjzL5/X/i
+oe2qZKhp6X5DPpad1q1Q4ItKdTN+2EXyMyoHn1BJKNba7CUUvXf03EJebT/Im+qo
+zfEksJeZJUSlSujANUPoCpsEYGWWQx5G+ViG05Sqs+6ppKrut+P+DVPo
+-----END CERTIFICATE-----
Binary files 1.2.1-4/verifier/testdata/truststore/x509/tsa/test-nonSelfIssued/nonSelfIssued.crt and 1.3.2-1/verifier/testdata/truststore/x509/tsa/test-nonSelfIssued/nonSelfIssued.crt differ
diff -pruN 1.2.1-4/verifier/timestamp_test.go 1.3.2-1/verifier/timestamp_test.go
--- 1.2.1-4/verifier/timestamp_test.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/verifier/timestamp_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -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)
 		}
diff -pruN 1.2.1-4/verifier/truststore/truststore.go 1.3.2-1/verifier/truststore/truststore.go
--- 1.2.1-4/verifier/truststore/truststore.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/verifier/truststore/truststore.go	2025-10-31 17:46:39.000000000 +0000
@@ -15,6 +15,7 @@
 package truststore
 
 import (
+	"bytes"
 	"context"
 	"crypto/x509"
 	"errors"
@@ -106,6 +107,14 @@ func (trustStore *x509TrustStore) GetCer
 		if err := ValidateCertificates(certs); err != nil {
 			return nil, CertificateError{InnerError: err, Msg: fmt.Sprintf("failed to validate the trusted certificate %s in trust store %s of type %s", certFileName, namedStore, storeType)}
 		}
+		// we require TSA certificates in trust store to be root CA certificates
+		if storeType == TypeTSA {
+			for _, cert := range certs {
+				if err := isRootCACertificate(cert); err != nil {
+					return nil, CertificateError{InnerError: err, Msg: fmt.Sprintf("trusted certificate %s in trust store %s of type %s is invalid: %v", certFileName, namedStore, storeType, err.Error())}
+				}
+			}
+		}
 		certificates = append(certificates, certs...)
 	}
 	if len(certificates) < 1 {
@@ -137,3 +146,14 @@ func ValidateCertificates(certs []*x509.
 func isValidStoreType(storeType Type) bool {
 	return slices.Contains(Types, storeType)
 }
+
+// isRootCACertificate returns nil if cert is a root CA certificate
+func isRootCACertificate(cert *x509.Certificate) error {
+	if err := cert.CheckSignatureFrom(cert); err != nil {
+		return fmt.Errorf("certificate with subject %q is not a root CA certificate: %w", cert.Subject, err)
+	}
+	if !bytes.Equal(cert.RawSubject, cert.RawIssuer) {
+		return fmt.Errorf("certificate with subject %q is not a root CA certificate: issuer (%s) and subject (%s) are not the same", cert.Subject, cert.Issuer, cert.Subject)
+	}
+	return nil
+}
diff -pruN 1.2.1-4/verifier/truststore/truststore_test.go 1.3.2-1/verifier/truststore/truststore_test.go
--- 1.2.1-4/verifier/truststore/truststore_test.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/verifier/truststore/truststore_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -98,3 +98,31 @@ func TestValidateCertsWithLeafCert(t *te
 		t.Fatalf("leaf cert in a trust store should return error %q, got: %v", expectedErr, err)
 	}
 }
+
+func TestGetCertFromValidTsaTrustStore(t *testing.T) {
+	// testing ../testdata/truststore/x509/tsa/test-nonCA/globalsignRoot.cer
+	_, err := trustStore.GetCertificates(context.Background(), "tsa", "test-timestamp")
+	if err != nil {
+		t.Fatalf("expected nil error, but got %s", err)
+	}
+}
+
+func TestGetCertFromInvalidTsaTrustStore(t *testing.T) {
+	t.Run("non CA certificate", func(t *testing.T) {
+		// testing ../testdata/truststore/x509/tsa/test-nonCA/wabbit-networks.io
+		expectedErrMsg := `trusted certificate wabbit-networks.io.crt in trust store test-nonCA of type tsa is invalid: certificate with subject "CN=wabbit-networks.io,O=Notary,L=Seattle,ST=WA,C=US" is not a root CA certificate: x509: invalid signature: parent certificate cannot sign this kind of certificate`
+		_, err := trustStore.GetCertificates(context.Background(), "tsa", "test-nonCA")
+		if err == nil || err.Error() != expectedErrMsg {
+			t.Fatalf("expected error: %s, but got %s", expectedErrMsg, err)
+		}
+	})
+
+	t.Run("not self-issued", func(t *testing.T) {
+		//testing ../testdata/truststore/x509/tsa/test-nonSelfIssued/nonSelfIssued.crt
+		expectedErrMsg := `trusted certificate nonSelfIssued.crt in trust store test-nonSelfIssued of type tsa is invalid: certificate with subject "CN=Notation Test Revokable RSA Chain Cert 2,O=Notary,L=Seattle,ST=WA,C=US" is not a root CA certificate: issuer (CN=Notation Test Revokable RSA Chain Cert Root,O=Notary,L=Seattle,ST=WA,C=US) and subject (CN=Notation Test Revokable RSA Chain Cert 2,O=Notary,L=Seattle,ST=WA,C=US) are not the same`
+		_, err := trustStore.GetCertificates(context.Background(), "tsa", "test-nonSelfIssued")
+		if err == nil || err.Error() != expectedErrMsg {
+			t.Fatalf("expected error: %s, but got %s", expectedErrMsg, err)
+		}
+	})
+}
diff -pruN 1.2.1-4/verifier/verifier.go 1.3.2-1/verifier/verifier.go
--- 1.2.1-4/verifier/verifier.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/verifier/verifier.go	2025-10-31 17:46:39.000000000 +0000
@@ -273,7 +273,7 @@ func (v *verifier) processSignature(ctx
 
 	var installedPlugin pluginframework.VerifyPlugin
 	if verificationPluginName != "" {
-		logger.Debugf("Finding verification plugin %s", verificationPluginName)
+		logger.Debugf("Finding verification plugin %q", verificationPluginName)
 		verificationPluginMinVersion, err := getVerificationPluginMinVersion(&outcome.EnvelopeContent.SignerInfo)
 		if err != nil && err != errExtendedAttributeNotExist {
 			return notation.ErrorVerificationInconclusive{Msg: fmt.Sprintf("error while getting plugin minimum version, error: %s", err)}
@@ -674,20 +674,40 @@ func revocationFinalResult(certResults [
 	revokedFound := false
 	var revokedCertSubject string
 	for i := len(certResults) - 1; i >= 0; i-- {
-		if len(certResults[i].ServerResults) > 0 && certResults[i].ServerResults[0].Error != nil {
-			logger.Debugf("Error for certificate #%d in chain with subject %v for server %q: %v", (i + 1), certChain[i].Subject.String(), certResults[i].ServerResults[0].Server, certResults[i].ServerResults[0].Error)
+		cert := certChain[i]
+		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 %q", (i + 1), cert.Subject)
+		}
+		for _, serverResult := range certResult.ServerResults {
+			if serverResult.Error != nil {
+				// log individual server errors
+				if certResult.RevocationMethod == revocationresult.RevocationMethodOCSPFallbackCRL && serverResult.RevocationMethod == revocationresult.RevocationMethodOCSP {
+					// 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 %q 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 %q encountered an error for revocation method %s at URL %q: %v", (i + 1), cert.Subject, serverResult.RevocationMethod, serverResult.Server, serverResult.Error)
+			}
 		}
 
-		if certResults[i].Result == revocationresult.ResultOK || certResults[i].Result == revocationresult.ResultNonRevokable {
+		if certResult.Result == revocationresult.ResultOK || certResult.Result == revocationresult.ResultNonRevokable {
 			numOKResults++
 		} else {
-			finalResult = certResults[i].Result
-			problematicCertSubject = certChain[i].Subject.String()
-			if certResults[i].Result == revocationresult.ResultRevoked {
+			finalResult = certResult.Result
+			problematicCertSubject = cert.Subject.String()
+			if certResult.Result == revocationresult.ResultRevoked {
 				revokedFound = true
 				revokedCertSubject = problematicCertSubject
 			}
 		}
+
+		if i < len(certResults)-1 && certResult.Result == revocationresult.ResultNonRevokable {
+			logger.Warnf("Certificate #%d in the chain with subject %q neither has an OCSP nor a CRL revocation method.", (i + 1), cert.Subject)
+		}
 	}
 	if revokedFound {
 		problematicCertSubject = revokedCertSubject
@@ -868,7 +888,7 @@ func verifyTimestamp(ctx context.Context
 	}
 
 	// Performing timestamp verification
-	logger.Info("Performing timestamp verification...")
+	logger.Debug("Performing timestamp verification...")
 
 	// 1. Timestamp countersignature MUST be present
 	logger.Debug("Checking timestamp countersignature existence...")
@@ -914,7 +934,7 @@ func verifyTimestamp(ctx context.Context
 	if err := nx509.ValidateTimestampingCertChain(tsaCertChain); err != nil {
 		return fmt.Errorf("failed to validate the timestamping certificate chain with error: %w", err)
 	}
-	logger.Info("TSA identity is: ", tsaCertChain[0].Subject)
+	logger.Debug("The subject of TSA signing certificate is: ", tsaCertChain[0].Subject)
 
 	// 4. Check the timestamp against the signing certificate chain
 	logger.Debug("Checking the timestamp against the signing certificate chain...")
@@ -926,6 +946,9 @@ func verifyTimestamp(ctx context.Context
 		if !timestamp.BoundedBefore(cert.NotAfter) {
 			return fmt.Errorf("timestamp can be after certificate %q validity period, it was expired at %q", cert.Subject, cert.NotAfter.Format(time.RFC1123Z))
 		}
+		if timeOfVerification.After(cert.NotAfter) {
+			logger.Debugf("Certificate %q expired at %q, but timestamp is within certificate validity period", cert.Subject, cert.NotAfter.Format(time.RFC1123Z))
+		}
 	}
 
 	// 5. Perform the timestamping certificate chain revocation check
@@ -948,5 +971,6 @@ func verifyTimestamp(ctx context.Context
 	}
 
 	// success
+	logger.Debug("Timestamp verification: Success")
 	return nil
 }
diff -pruN 1.2.1-4/verifier/verifier_test.go 1.3.2-1/verifier/verifier_test.go
--- 1.2.1-4/verifier/verifier_test.go	2024-09-05 01:43:37.000000000 +0000
+++ 1.3.2-1/verifier/verifier_test.go	2025-10-31 17:46:39.000000000 +0000
@@ -16,6 +16,7 @@ package verifier
 import (
 	"context"
 	"crypto/x509"
+	"crypto/x509/pkix"
 	"encoding/json"
 	"errors"
 	"fmt"
@@ -30,6 +31,7 @@ import (
 
 	"github.com/notaryproject/notation-core-go/revocation"
 	"github.com/notaryproject/notation-core-go/revocation/purpose"
+	"github.com/notaryproject/notation-core-go/revocation/result"
 	"github.com/notaryproject/notation-core-go/signature"
 	_ "github.com/notaryproject/notation-core-go/signature/cose"
 	"github.com/notaryproject/notation-core-go/testhelper"
@@ -38,6 +40,7 @@ import (
 	"github.com/notaryproject/notation-go/dir"
 	"github.com/notaryproject/notation-go/internal/envelope"
 	"github.com/notaryproject/notation-go/internal/mock"
+	"github.com/notaryproject/notation-go/log"
 	"github.com/notaryproject/notation-go/plugin/proto"
 	"github.com/notaryproject/notation-go/signer"
 	"github.com/notaryproject/notation-go/verifier/trustpolicy"
@@ -210,7 +213,7 @@ func assertNotationVerification(t *testi
 	for _, level := range verificationLevels {
 		policyDocument := dummyPolicyDocument()
 		policyDocument.TrustPolicies[0].TrustStores = []string{"ca:valid-trust-store-2", "signingAuthority:valid-trust-store-2"} // trust store is not configured with the root certificate of the signature
-		expectedErr := fmt.Errorf("signature is not produced by a trusted signer")
+		expectedErr := fmt.Errorf("the signature's certificate chain does not contain any trusted certificate")
 		testCases = append(testCases, testCase{
 			signatureBlob:     validSigEnv,
 			verificationType:  trustpolicy.TypeAuthenticity,
@@ -1235,6 +1238,120 @@ func TestIsRequiredVerificationPluginVer
 	}
 }
 
+func TestRevocationFinalResult(t *testing.T) {
+	certResult := []*result.CertRevocationResult{
+		{
+			// update leaf cert result in each sub-test
+		},
+		{
+			Result: result.ResultNonRevokable,
+			ServerResults: []*result.ServerResult{
+				{
+					Result: result.ResultNonRevokable,
+				},
+			},
+		},
+	}
+	certChain := []*x509.Certificate{
+		{
+			Subject: pkix.Name{
+				CommonName: "leafCert",
+			},
+		},
+		{
+			Subject: pkix.Name{
+				CommonName: "rootCert",
+			},
+		},
+	}
+	t.Run("OCSP error without fallback", func(t *testing.T) {
+		certResult[0] = &result.CertRevocationResult{
+			Result: result.ResultUnknown,
+			ServerResults: []*result.ServerResult{
+				{
+					Server:           "http://ocsp.example.com",
+					Result:           result.ResultUnknown,
+					Error:            errors.New("ocsp error"),
+					RevocationMethod: result.RevocationMethodOCSP,
+				},
+			},
+		}
+
+		finalResult, problematicCertSubject := revocationFinalResult(certResult, certChain, log.Discard)
+		if finalResult != result.ResultUnknown || problematicCertSubject != "CN=leafCert" {
+			t.Fatalf("unexpected final result: %v, problematic cert subject: %s", finalResult, problematicCertSubject)
+		}
+	})
+
+	t.Run("OCSP error with fallback", func(t *testing.T) {
+		certResult[0] = &result.CertRevocationResult{
+			Result: result.ResultOK,
+			ServerResults: []*result.ServerResult{
+				{
+					Server:           "http://ocsp.example.com",
+					Result:           result.ResultUnknown,
+					Error:            errors.New("ocsp error"),
+					RevocationMethod: result.RevocationMethodOCSP,
+				},
+				{
+					Result:           result.ResultOK,
+					Server:           "http://crl.example.com",
+					RevocationMethod: result.RevocationMethodCRL,
+				},
+			},
+			RevocationMethod: result.RevocationMethodOCSPFallbackCRL,
+		}
+
+		finalResult, problematicCertSubject := revocationFinalResult(certResult, certChain, log.Discard)
+		if finalResult != result.ResultOK || problematicCertSubject != "" {
+			t.Fatalf("unexpected final result: %v, problematic cert subject: %s", finalResult, problematicCertSubject)
+		}
+	})
+
+	t.Run("OCSP error with fallback and CRL error", func(t *testing.T) {
+		certResult[0] = &result.CertRevocationResult{
+			Result: result.ResultUnknown,
+			ServerResults: []*result.ServerResult{
+				{
+					Server:           "http://ocsp.example.com",
+					Result:           result.ResultUnknown,
+					Error:            errors.New("ocsp error"),
+					RevocationMethod: result.RevocationMethodOCSP,
+				},
+				{
+					Result:           result.ResultUnknown,
+					Error:            errors.New("crl error"),
+					RevocationMethod: result.RevocationMethodCRL,
+				},
+			},
+			RevocationMethod: result.RevocationMethodOCSPFallbackCRL,
+		}
+
+		finalResult, problematicCertSubject := revocationFinalResult(certResult, certChain, log.Discard)
+		if finalResult != result.ResultUnknown || problematicCertSubject != "CN=leafCert" {
+			t.Fatalf("unexpected final result: %v, problematic cert subject: %s", finalResult, problematicCertSubject)
+		}
+	})
+
+	t.Run("revocation method unknown error(should never reach here)", func(t *testing.T) {
+		certResult[0] = &result.CertRevocationResult{
+			Result: result.ResultUnknown,
+			ServerResults: []*result.ServerResult{
+				{
+					Result:           result.ResultUnknown,
+					Error:            errors.New("unknown error"),
+					RevocationMethod: result.RevocationMethodUnknown,
+				},
+			},
+		}
+
+		finalResult, problematicCertSubject := revocationFinalResult(certResult, certChain, log.Discard)
+		if finalResult != result.ResultUnknown || problematicCertSubject != "CN=leafCert" {
+			t.Fatalf("unexpected final result: %v, problematic cert subject: %s", finalResult, problematicCertSubject)
+		}
+	})
+}
+
 func verifyResult(outcome *notation.VerificationOutcome, expectedResult notation.ValidationResult, expectedErr error, t *testing.T) {
 	var actualResult *notation.ValidationResult
 	for _, r := range outcome.VerificationResults {
