Repository: theupdateframework/go-tuf
Pull request #625 (2024-03-09 00:29:27)

Use the correct verifier for RSA PSS scheme keys
The following PR fixes an issue with go-tuf's support for RSA key types.

**Details:**

Apparently for RSA key types `signature.LoadVerifier()` is defaulting to returning a verifier that is `RSAPKCS1v15Verifier` which corresponds to the RSA PKCS#1 scheme. 

Based on [the latest TUF spec](https://theupdateframework.github.io/specification/latest/#file-formats-keys), TUF uses RSA PSS instead of PKCS#1. This manifests itself by causing go-tuf v2 TUF clients to fail metadata verification in case of RSA key types.

The fix for this is to invoke the proper verifier for the PSS scheme. This means that when we are verifying a metadata signed by an RSA key type, we should use `LoadRSAPSSVerifier()` instead of the generic `LoadVerifier()`.

**References:**

* https://theupdateframework.github.io/specification/latest/#file-formats-keys
* https://github.com/sigstore/sigstore/blob/a153736bf87443389feee6aa787e97b81839175d/pkg/signature/verifier.go#L41

**Credits:**

Thanks to @kairoaraujo for reaching out and helping track this together! 🚀 Cheers! 🍻 

**What's left:**
- [ ] Update the tests

kairoaraujo: I've tested it, and it solves the issue 😃 
jku: > Based on the latest TUF spec, TUF uses RSA PSS instead of PKCS#1

Note that these are just examples essentially, definitely not an exhaustive list of the only schemes that can be supported: I would avoid removing support for the pkcs1v15 scheme if possible as removing optional features can be a real head ache for users...
jku: Just as an idea... I would love a keytype support test in tuf-conformance: https://github.com/theupdateframework/tuf-conformance/issues/159 -- implementing that would give you keytype test coverage "for free" in go-tuf and should not be more than 20 lines of code.
kommendorkapten: A lot of the tests are working, I'll hunt down the rest failures tomorrow I hope
kommendorkapten: This is now ready for review, the tests were failing as they were signed using PKCS#1 v1.5 but the key scheme said `rsa-pss-sha256`, I resigned the test data (with the helper tool added to this pr), and then made sure any signing and verification in the tests uses PSS. And when comparing to/from bytes I ignore whitespaces as its brittle to care about them.
rdimitrov: Thank you all for reviewing and contributing to this! 🙌 💯 

Patch:
diff --git a/examples/repository/basic_repository.go b/examples/repository/basic_repository.go
index e8942b7..479a957 100644
--- a/examples/repository/basic_repository.go
+++ b/examples/repository/basic_repository.go
@@ -499,7 +499,9 @@ func main() {
 
 	// Use a mixture of key types
 	// ==========================
-	// Create an RSA key
+	// Create an RSA key.
+	// Note TUF should use an RSA PSS key scheme, not RSA PKCS1v15.
+	// Reference: https://theupdateframework.github.io/specification/latest/#file-formats-keys
 	anotherRootKeyRSA, _ := rsa.GenerateKey(rand.Reader, 2048)
 	if err != nil {
 		panic(fmt.Sprintln("basic_repository.go:", "RSA key generation failed", err))
@@ -549,7 +551,7 @@ func main() {
 	}
 
 	// Sign root with the new RSA and ECDSA keys
-	outofbandSignerRSA, err := signature.LoadSigner(anotherRootKeyRSA, crypto.SHA256)
+	outofbandSignerRSA, err := signature.LoadRSAPSSSigner(anotherRootKeyRSA, crypto.SHA256, &rsa.PSSOptions{Hash: crypto.SHA256})
 	if err != nil {
 		panic(fmt.Sprintln("basic_repository.go:", "loading RSA signer failed", err))
 	}
diff --git a/metadata/metadata.go b/metadata/metadata.go
index 3e0a9e1..f71c08f 100644
--- a/metadata/metadata.go
+++ b/metadata/metadata.go
@@ -21,6 +21,7 @@ import (
 	"bytes"
 	"crypto"
 	"crypto/hmac"
+	"crypto/rsa"
 	"crypto/sha256"
 	"crypto/sha512"
 	"encoding/base64"
@@ -322,7 +323,21 @@ func (meta *Metadata[T]) VerifyDelegate(delegatedRole string, delegatedMetadata
 			}
 		}
 		// load a verifier based on that key
-		verifier, err := signature.LoadVerifier(publicKey, hash)
+		// handle RSA PSS scheme separately as the LoadVerifier function doesn't identify it correctly
+		// Note we should support RSA PSS, not RSA PKCS1v15 (which is what LoadVerifier would return)
+		// Reference: https://theupdateframework.github.io/specification/latest/#file-formats-keys
+		var verifier signature.Verifier
+		if key.Type == KeyTypeRSASSA_PSS_SHA256 {
+			// Load a verifier for rsa
+			publicKeyRSAPSS, ok := publicKey.(*rsa.PublicKey)
+			if !ok {
+				return &ErrType{Msg: "failed to convert public key to RSA PSS key"}
+			}
+			verifier, err = signature.LoadRSAPSSVerifier(publicKeyRSAPSS, hash, &rsa.PSSOptions{Hash: crypto.SHA256})
+		} else {
+			// Load a verifier for ed25519 and ecdsa
+			verifier, err = signature.LoadVerifier(publicKey, hash)
+		}
 		if err != nil {
 			return err
 		}


Test patch:
diff --git a/internal/testutils/repository_data/repository/metadata/root.json b/internal/testutils/repository_data/repository/metadata/root.json
index 584a3ec..6acbb83 100644
--- a/internal/testutils/repository_data/repository/metadata/root.json
+++ b/internal/testutils/repository_data/repository/metadata/root.json
@@ -1,71 +1,71 @@
 {
-	"signatures": [
-		{
-			"keyid": "74b58be26a6ff00ab2eec9b14da29038591a69c212223033f4efdf24489913f2",
-			"sig": "d0283ac0653e324ce132e47a518f8a1539b59430efe5cdec58ec53f824bec28628b57dd5fb2452bde83fc8f5d11ab0b7350a9bbcbefc7acc6c447785545fa1e36f1352c9e20dd1ebcc3ab16a2a7ff702e32e481ceba88e0f348dc2cddd26ca577445d00c7194e8656d901fd2382c479555af93a64eef48cf79cdff6ecdcd7cb7"
-		}
-	],
-	"signed": {
-		"_type": "root",
-		"consistent_snapshot": true,
-		"expires": "2030-08-15T14:30:45.0000001Z",
-		"keys": {
-			"142919f8e933d7045abff3be450070057814da36331d7a22ccade8b35a9e3946": {
-				"keytype": "rsa",
-				"keyval": {
-					"public": "-----BEGIN PUBLIC KEY-----\nMIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHXjYnWGuCIOh5T3XGmgG/RsXWHP\nTbyu7OImP6O+uHg8hui8C1nY/mcJdFdxqgl1vKEco/Nwebh2T8L6XbNfcgV9VVst\nWpeCalZYWi55lZSLe9KixQIAyg15rNdhN9pcD3OuLmFvslgTx+dTbZ3ZoYMbcb4C\n5yqvqzcOoCTQMeWbAgMBAAE=\n-----END PUBLIC KEY-----\n"
-				},
-				"scheme": "rsassa-pss-sha256"
-			},
-			"282612f348dcd7fe3f19e0f890e89fad48d45335deeb91deef92873934e6fe6d": {
-				"keytype": "rsa",
-				"keyval": {
-					"public": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjm6HPktvTGsygQ8Gvmu+zydTN\ne1zqoxLxV7mVRbmsCI4kn7JTHc4fmWZwvo7f/Wbto6Xj5HqGJFSlYIGZuTwZqPg3\nw8wqv8cuPxbmsFSxMoHfzBBIuJe0FlwXFysojbdhrSUqNL84tlwTFXEhePYrpTNM\nDn+9T55B0WJYT/VPxwIDAQAB\n-----END PUBLIC KEY-----\n"
-				},
-				"scheme": "rsassa-pss-sha256"
-			},
-			"74b58be26a6ff00ab2eec9b14da29038591a69c212223033f4efdf24489913f2": {
-				"keytype": "rsa",
-				"keyval": {
-					"public": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDydf/VEpxBOCDoxpM6IVhq9i67\nP9BiVv2zwZSUO/M0RTToAvFvNgDKXwtnp8LyjVk++wMA1aceMa+pS7vYrKvPIJa7\nWIT+mwy86/fIdnllJDMw5tmLr2mE3oBMxOhpEiD2tO+liGacklFNk6nHHorX9S91\niqpdRVa3zJw5ALvLdwIDAQAB\n-----END PUBLIC KEY-----\n"
-				},
-				"scheme": "rsassa-pss-sha256"
-			},
-			"8a14f637b21578cc292a67899df0e46cc160d7fd56e9beae898adb666f4fd9d6": {
-				"keytype": "rsa",
-				"keyval": {
-					"public": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCPQoHresXRRRGoinN3bNn+BI23\nKolXdXLGqYkTvr9AjemUQJxbqmvZXHboQMAYw8OuBrRNt5Fz20wjsrJwOBEU5U3n\nHSJI4zYPGckYci0/0Eo2Kjws5BmIj38qgIfhsH4zyZ4FZZ+GLRn+W3i3wl6SfRMC\n/HCg0DDwi75faC0vGQIDAQAB\n-----END PUBLIC KEY-----\n"
-				},
-				"scheme": "rsassa-pss-sha256"
-			}
-		},
-		"roles": {
-			"root": {
-				"keyids": [
-					"74b58be26a6ff00ab2eec9b14da29038591a69c212223033f4efdf24489913f2"
-				],
-				"threshold": 1
-			},
-			"snapshot": {
-				"keyids": [
-					"8a14f637b21578cc292a67899df0e46cc160d7fd56e9beae898adb666f4fd9d6"
-				],
-				"threshold": 1
-			},
-			"targets": {
-				"keyids": [
-					"282612f348dcd7fe3f19e0f890e89fad48d45335deeb91deef92873934e6fe6d"
-				],
-				"threshold": 1
-			},
-			"timestamp": {
-				"keyids": [
-					"142919f8e933d7045abff3be450070057814da36331d7a22ccade8b35a9e3946"
-				],
-				"threshold": 1
-			}
-		},
-		"spec_version": "1.0.31",
-		"version": 1
-	}
+ "signatures": [
+  {
+   "keyid": "74b58be26a6ff00ab2eec9b14da29038591a69c212223033f4efdf24489913f2",
+   "sig": "60d502a798f44577a76a1d7656a60099cd3a995d3d71a0a234aadbd16e38c14611920b8aef9ed78ca4ac0c02277cd72a6fc5ef484a3d66a6c70a61199e462681eb2e667046d4fbc2be1e50cf9fe00fda8fcd6534599eddc91716bf38e7fbbf375524fdb702c74076fd37dcd401d5263783150e851bdba9ef6f9c9a08adf6b289"
+  }
+ ],
+ "signed": {
+  "_type": "root",
+  "consistent_snapshot": true,
+  "expires": "2030-08-15T14:30:45.0000001Z",
+  "keys": {
+   "142919f8e933d7045abff3be450070057814da36331d7a22ccade8b35a9e3946": {
+    "keytype": "rsa",
+    "keyval": {
+     "public": "-----BEGIN PUBLIC KEY-----\nMIGeMA0GCSqGSIb3DQEBAQUAA4GMADCBiAKBgHXjYnWGuCIOh5T3XGmgG/RsXWHP\nTbyu7OImP6O+uHg8hui8C1nY/mcJdFdxqgl1vKEco/Nwebh2T8L6XbNfcgV9VVst\nWpeCalZYWi55lZSLe9KixQIAyg15rNdhN9pcD3OuLmFvslgTx+dTbZ3ZoYMbcb4C\n5yqvqzcOoCTQMeWbAgMBAAE=\n-----END PUBLIC KEY-----\n"
+    },
+    "scheme": "rsassa-pss-sha256"
+   },
+   "282612f348dcd7fe3f19e0f890e89fad48d45335deeb91deef92873934e6fe6d": {
+    "keytype": "rsa",
+    "keyval": {
+     "public": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCjm6HPktvTGsygQ8Gvmu+zydTN\ne1zqoxLxV7mVRbmsCI4kn7JTHc4fmWZwvo7f/Wbto6Xj5HqGJFSlYIGZuTwZqPg3\nw8wqv8cuPxbmsFSxMoHfzBBIuJe0FlwXFysojbdhrSUqNL84tlwTFXEhePYrpTNM\nDn+9T55B0WJYT/VPxwIDAQAB\n-----END PUBLIC KEY-----\n"
+    },
+    "scheme": "rsassa-pss-sha256"
+   },
+   "74b58be26a6ff00ab2eec9b14da29038591a69c212223033f4efdf24489913f2": {
+    "keytype": "rsa",
+    "keyval": {
+     "public": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDydf/VEpxBOCDoxpM6IVhq9i67\nP9BiVv2zwZSUO/M0RTToAvFvNgDKXwtnp8LyjVk++wMA1aceMa+pS7vYrKvPIJa7\nWIT+mwy86/fIdnllJDMw5tmLr2mE3oBMxOhpEiD2tO+liGacklFNk6nHHorX9S91\niqpdRVa3zJw5ALvLdwIDAQAB\n-----END PUBLIC KEY-----\n"
+    },
+    "scheme": "rsassa-pss-sha256"
+   },
+   "8a14f637b21578cc292a67899df0e46cc160d7fd56e9beae898adb666f4fd9d6": {
+    "keytype": "rsa",
+    "keyval": {
+     "public": "-----BEGIN PUBLIC KEY-----\nMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCPQoHresXRRRGoinN3bNn+BI23\nKolXdXLGqYkTvr9AjemUQJxbqmvZXHboQMAYw8OuBrRNt5Fz20wjsrJwOBEU5U3n\nHSJI4zYPGckYci0/0Eo2Kjws5BmIj38qgIfhsH4zyZ4FZZ+GLRn+W3i3wl6SfRMC\n/HCg0DDwi75faC0vGQIDAQAB\n-----END PUBLIC KEY-----\n"
+    },
+    "scheme": "rsassa-pss-sha256"
+   }
+  },
+  "roles": {
+   "root": {
+    "keyids": [
+     "74b58be26a6ff00ab2eec9b14da29038591a69c212223033f4efdf24489913f2"
+    ],
+    "threshold": 1
+   },
+   "snapshot": {
+    "keyids": [
+     "8a14f637b21578cc292a67899df0e46cc160d7fd56e9beae898adb666f4fd9d6"
+    ],
+    "threshold": 1
+   },
+   "targets": {
+    "keyids": [
+     "282612f348dcd7fe3f19e0f890e89fad48d45335deeb91deef92873934e6fe6d"
+    ],
+    "threshold": 1
+   },
+   "timestamp": {
+    "keyids": [
+     "142919f8e933d7045abff3be450070057814da36331d7a22ccade8b35a9e3946"
+    ],
+    "threshold": 1
+   }
+  },
+  "spec_version": "1.0.31",
+  "version": 1
+ }
 }
\ No newline at end of file
diff --git a/internal/testutils/repository_data/repository/metadata/snapshot.json b/internal/testutils/repository_data/repository/metadata/snapshot.json
index ed379e0..24ec151 100644
--- a/internal/testutils/repository_data/repository/metadata/snapshot.json
+++ b/internal/testutils/repository_data/repository/metadata/snapshot.json
@@ -1,25 +1,25 @@
 {
-	"signatures": [
-		{
-			"keyid": "8a14f637b21578cc292a67899df0e46cc160d7fd56e9beae898adb666f4fd9d6",
-			"sig": "3075fe9ef3008603eb0531500a93101b8f7eb52b07ce63fb71abaffd5eb20784bcab888abfca8041798b13dd35c6e18ff4a64d536161c4d5e7535f006edec3a46c71684a632269222da82d50bf380e20eb477032e45df0b44af9e1dc46f25cd72f9901b4fc41b90869649b6257a66188b61b83c7295baf16f113e9cc4d39b3a6"
-		}
-	],
-	"signed": {
-		"_type": "snapshot",
-		"expires": "2030-08-15T14:30:45.0000001Z",
-		"meta": {
-			"role1.json": {
-				"version": 1
-			},
-			"role2.json": {
-				"version": 1
-			},
-			"targets.json": {
-				"version": 1
-			}
-		},
-		"spec_version": "1.0.31",
-		"version": 1
-	}
+ "signatures": [
+  {
+   "keyid": "8a14f637b21578cc292a67899df0e46cc160d7fd56e9beae898adb666f4fd9d6",
+   "sig": "1fdc41488f58482d8af1dad681b9076d54c61b3f5e11bd6cf3c8102b2863471f82c0be2cccd978a9bb6afb43e07dd7e806028a883eaeafd32d5f5277d6419363ecb1475286a61996a4bb4b325b703d3bd60381227af0a3826f7f119a451086bcb5b13a525184d1b2a941ab9a270d2c9c8e584162c5857b138a38c33892e2a921"
+  }
+ ],
+ "signed": {
+  "_type": "snapshot",
+  "expires": "2030-08-15T14:30:45.0000001Z",
+  "meta": {
+   "role1.json": {
+    "version": 1
+   },
+   "role2.json": {
+    "version": 1
+   },
+   "targets.json": {
+    "version": 1
+   }
+  },
+  "spec_version": "1.0.31",
+  "version": 1
+ }
 }
\ No newline at end of file
diff --git a/internal/testutils/repository_data/repository/metadata/targets.json b/internal/testutils/repository_data/repository/metadata/targets.json
index 41399c9..1e06afa 100644
--- a/internal/testutils/repository_data/repository/metadata/targets.json
+++ b/internal/testutils/repository_data/repository/metadata/targets.json
@@ -1,50 +1,50 @@
 {
-	"signatures": [
-		{
-			"keyid": "282612f348dcd7fe3f19e0f890e89fad48d45335deeb91deef92873934e6fe6d",
-			"sig": "80cd125a4b128c9508df8bc6f71ad2ed9896a9e7afccd53fca9e7dbc2f02db69c3ae712234d3730c929d891fa035bdf059736e7debf62cbac6f0e8d22ab0c5de3b3e47b249eb0d41dea66d9fda9588893cde824a95614129263b6fed72fafb21cd7114e603fe3a30e3871e9eb5b5029e3e9a8353190f1bcb332a81ec211a93eb"
-		}
-	],
-	"signed": {
-		"_type": "targets",
-		"delegations": {
-			"keys": {
-				"c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": {
-					"keyid_hash_algorithms": [
-						"sha256",
-						"sha512"
-					],
-					"keytype": "ed25519",
-					"keyval": {
-						"public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9"
-					},
-					"scheme": "ed25519"
-				}
-			},
-			"roles": [
-				{
-					"keyids": [
-						"c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a"
-					],
-					"name": "role1",
-					"paths": [
-						"file3.txt"
-					],
-					"terminating": false,
-					"threshold": 1
-				}
-			]
-		},
-		"expires": "2030-08-15T14:30:45.0000001Z",
-		"spec_version": "1.0.31",
-		"targets": {
-			"file1.txt": {
-				"hashes": {
-					"sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da"
-				},
-				"length": 31
-			}
-		},
-		"version": 1
-	}
+ "signatures": [
+  {
+   "keyid": "282612f348dcd7fe3f19e0f890e89fad48d45335deeb91deef92873934e6fe6d",
+   "sig": "699c0c762032f6471fceabfd2d61b80f352ad6bf2ba5fd7b114fd0b9b1ab8d94f1482776b3fef43c53183a9c9cd7f5de671cbdafdd5032bbe2c42273e953bf3ce9f99c2d46dac8802d6155082e10313e22c4886af2be113b626f2a8af930e01ed41df50a5dbe6ca4cedf5f5d2a7f3b7e7090abacc8aebd6e021ad021d3580cad"
+  }
+ ],
+ "signed": {
+  "_type": "targets",
+  "delegations": {
+   "keys": {
+    "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a": {
+     "keyid_hash_algorithms": [
+      "sha256",
+      "sha512"
+     ],
+     "keytype": "ed25519",
+     "keyval": {
+      "public": "fcf224e55fa226056adf113ef1eb3d55e308b75b321c8c8316999d8c4fd9e0d9"
+     },
+     "scheme": "ed25519"
+    }
+   },
+   "roles": [
+    {
+     "keyids": [
+      "c8022fa1e9b9cb239a6b362bbdffa9649e61ad2cb699d2e4bc4fdf7930a0e64a"
+     ],
+     "name": "role1",
+     "paths": [
+      "file3.txt"
+     ],
+     "terminating": false,
+     "threshold": 1
+    }
+   ]
+  },
+  "expires": "2030-08-15T14:30:45.0000001Z",
+  "spec_version": "1.0.31",
+  "targets": {
+   "file1.txt": {
+    "hashes": {
+     "sha256": "65b8c67f51c993d898250f40aa57a317d854900b3a04895464313e48785440da"
+    },
+    "length": 31
+   }
+  },
+  "version": 1
+ }
 }
\ No newline at end of file
diff --git a/internal/testutils/repository_data/repository/metadata/timestamp.json b/internal/testutils/repository_data/repository/metadata/timestamp.json
index aa11c74..c361c55 100644
--- a/internal/testutils/repository_data/repository/metadata/timestamp.json
+++ b/internal/testutils/repository_data/repository/metadata/timestamp.json
@@ -1,19 +1,19 @@
 {
-	"signatures": [
-		{
-			"keyid": "142919f8e933d7045abff3be450070057814da36331d7a22ccade8b35a9e3946",
-			"sig": "639c9ce3dbb705265b5e9ad6d67fea2b38780c48ff7917e372adace8e50a7a2f054383d5960457a113059be521b8ce7e6d8a5787c600c4850b8c0ed1ae17a931a6bfe794476e7824c6f53df5232561e0a2e146b11dde7889b397c6f8136e2105bbb21b4b59b5addc032a0e755d97e531255f3b458d474184168541e542626e81"
-		}
-	],
-	"signed": {
-		"_type": "timestamp",
-		"expires": "2030-08-15T14:30:45.0000001Z",
-		"meta": {
-			"snapshot.json": {
-				"version": 1
-			}
-		},
-		"spec_version": "1.0.31",
-		"version": 1
-	}
+ "signatures": [
+  {
+   "keyid": "142919f8e933d7045abff3be450070057814da36331d7a22ccade8b35a9e3946",
+   "sig": "043b312da9ee1444e3ef539d943891b2690a8d75624c0f05ec148790fd698a7eb1501428167872794857e9669a451619cc796658782b1d46ecc59d1aca0db7233416e81074ef4f54fd845ad8e4216b4cd5163d815be9ecbf73f34aacd25b60c99da88cf641ba5715c37f34a6bc036061c05a42066f554714ee8647c47ae5c16e"
+  }
+ ],
+ "signed": {
+  "_type": "timestamp",
+  "expires": "2030-08-15T14:30:45.0000001Z",
+  "meta": {
+   "snapshot.json": {
+    "version": 1
+   }
+  },
+  "spec_version": "1.0.31",
+  "version": 1
+ }
 }
\ No newline at end of file
diff --git a/internal/testutils/rsapss/signer.go b/internal/testutils/rsapss/signer.go
new file mode 100644
index 0000000..9b0c165
--- /dev/null
+++ b/internal/testutils/rsapss/signer.go
@@ -0,0 +1,35 @@
+package rsapss
+
+import (
+	"crypto"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/pem"
+	"errors"
+	"os"
+
+	"github.com/sigstore/sigstore/pkg/signature"
+	"github.com/sigstore/sigstore/pkg/signature/options"
+)
+
+func LoadRSAPSSSignerFromPEMFile(p string) (signature.Signer, error) {
+	var b []byte
+	var block *pem.Block
+	var pk any
+	var err error
+
+	if b, err = os.ReadFile(p); err != nil {
+		return nil, err
+	}
+
+	if block, _ = pem.Decode(b); len(block.Bytes) == 0 {
+		return nil, errors.New("empty PEM block")
+	}
+
+	if pk, err = x509.ParsePKCS1PrivateKey(block.Bytes); err != nil {
+		return nil, err
+	}
+	var pssOpt = rsa.PSSOptions{Hash: crypto.SHA256}
+
+	return signature.LoadSignerWithOpts(pk, options.WithRSAPSS(&pssOpt))
+}
diff --git a/internal/testutils/signer/signer.go b/internal/testutils/signer/signer.go
new file mode 100644
index 0000000..5d893f4
--- /dev/null
+++ b/internal/testutils/signer/signer.go
@@ -0,0 +1,203 @@
+// Copyright 2024 The Update Framework 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
+//
+// SPDX-License-Identifier: Apache-2.0
+//
+
+package main
+
+import (
+	"crypto"
+	"crypto/rsa"
+	"crypto/x509"
+	"encoding/json"
+	"encoding/pem"
+	"errors"
+	"flag"
+	"fmt"
+	"os"
+
+	"github.com/sigstore/sigstore/pkg/signature"
+	"github.com/sigstore/sigstore/pkg/signature/options"
+	"github.com/theupdateframework/go-tuf/v2/metadata"
+)
+
+type tufSigner interface {
+	Sign(s signature.Signer) (*metadata.Signature, error)
+}
+
+/*
+   Run this to sign test data, like this:
+   ~/git/go-tuf/internal/testutils $ go run \
+       signer/signer.go \
+       -k repository_data/keystore/timestamp_key \
+       -s rsassa-pss-sha256 \
+       -f repository_data/repository/metadata/timestamp.json
+*/
+
+func main() {
+	var scheme = flag.String("s", "", "set scheme to use for key")
+	var key = flag.String("k", "", "key file to load")
+	var f = flag.String("f", "", "file to sign")
+
+	flag.Parse()
+
+	if *scheme == "" {
+		fmt.Println("no scheme is set")
+		os.Exit(1)
+	}
+	if *key == "" {
+		fmt.Println("no key provided")
+		os.Exit(1)
+	}
+	if *f == "" {
+		fmt.Println("no metadata file provided")
+		os.Exit(1)
+	}
+
+	t, err := getTUFMDRole(*f)
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+
+	s, err := loadSigner(*key, *scheme)
+	if err != nil {
+		fmt.Println(err)
+		os.Exit(1)
+	}
+
+	var ts tufSigner
+
+	switch t {
+	case metadata.ROOT:
+		var rmd metadata.Metadata[metadata.RootType]
+		if _, err = rmd.FromFile(*f); err != nil {
+			fmt.Println(err)
+			os.Exit(1)
+		}
+		rmd.Signatures = []metadata.Signature{}
+		ts = &rmd
+	case metadata.TARGETS:
+		var tmd metadata.Metadata[metadata.TargetsType]
+		if _, err = tmd.FromFile(*f); err != nil {
+			fmt.Println(err)
+			os.Exit(1)
+		}
+		tmd.Signatures = []metadata.Signature{}
+		ts = &tmd
+	case metadata.SNAPSHOT:
+		var smd metadata.Metadata[metadata.SnapshotType]
+		if _, err = smd.FromFile(*f); err != nil {
+			fmt.Println(err)
+			os.Exit(1)
+		}
+		smd.Signatures = []metadata.Signature{}
+		ts = &smd
+	case metadata.TIMESTAMP:
+		var tsmd metadata.Metadata[metadata.TimestampType]
+		if _, err = tsmd.FromFile(*f); err != nil {
+			fmt.Println(err)
+			os.Exit(1)
+		}
+		tsmd.Signatures = []metadata.Signature{}
+		ts = &tsmd
+	}
+
+	if _, err = ts.Sign(s); err != nil {
+		fmt.Printf("failed to sign metadata of type %s: %s\n",
+			t, err)
+		os.Exit(1)
+	}
+
+	if err = persist(*f, ts); err != nil {
+		fmt.Printf("failed to persist updated metadata %s: %s\n",
+			*f, err)
+	}
+}
+
+func persist(p string, md any) error {
+	jsonBytes, err := json.MarshalIndent(md, "", " ")
+	if err != nil {
+		return err
+	}
+
+	err = os.WriteFile(p, jsonBytes, 0600)
+	return err
+}
+
+func loadSigner(k, s string) (signature.Signer, error) {
+	var pk any
+	var err error
+	var opts []signature.LoadOption
+	var rawKey []byte
+
+	switch s {
+	case metadata.KeySchemeRSASSA_PSS_SHA256:
+		if rawKey, err = getPemBytes(k); err != nil {
+			return nil, err
+		}
+		if pk, err = x509.ParsePKCS1PrivateKey(rawKey); err != nil {
+			return nil, err
+		}
+		var pssOpt = rsa.PSSOptions{Hash: crypto.SHA256}
+		opts = append(opts, options.WithRSAPSS(&pssOpt))
+	default:
+		return nil, fmt.Errorf("unsupported key scheme %s\n", s)
+	}
+
+	return signature.LoadSignerWithOpts(pk, opts...)
+}
+
+func getPemBytes(p string) ([]byte, error) {
+	var b []byte
+	var block *pem.Block
+	var err error
+
+	if b, err = os.ReadFile(p); err != nil {
+		return nil, err
+	}
+
+	if block, _ = pem.Decode(b); len(block.Bytes) == 0 {
+		return nil, errors.New("empty PEM block")
+	}
+
+	return block.Bytes, nil
+}
+
+func getTUFMDRole(p string) (string, error) {
+	var m map[string]any
+
+	mdBytes, err := os.ReadFile(p)
+	if err != nil {
+		return "", fmt.Errorf("failed to read file %s: %w", p, err)
+	}
+
+	if err := json.Unmarshal(mdBytes, &m); err != nil {
+		return "", fmt.Errorf("failed to parse TUF metadata: %w", err)
+	}
+	signedType := m["signed"].(map[string]any)["_type"].(string)
+	switch signedType {
+	case metadata.ROOT:
+		fallthrough
+	case metadata.TARGETS:
+		fallthrough
+	case metadata.SNAPSHOT:
+		fallthrough
+	case metadata.TIMESTAMP:
+		return signedType, nil
+	default:
+		return "", fmt.Errorf("unsupported role '%s'", signedType)
+	}
+}
diff --git a/metadata/metadata_api_test.go b/metadata/metadata_api_test.go
index 4b3f781..5ae503d 100644
--- a/metadata/metadata_api_test.go
+++ b/metadata/metadata_api_test.go
@@ -20,6 +20,7 @@ package metadata
 import (
 	"bytes"
 	"crypto"
+	"crypto/rsa"
 	"crypto/sha256"
 	"encoding/json"
 	"fmt"
@@ -35,6 +36,7 @@ import (
 	"github.com/sigstore/sigstore/pkg/signature"
 	"github.com/stretchr/testify/assert"
 	"github.com/theupdateframework/go-tuf/v2/internal/testutils"
+	"github.com/theupdateframework/go-tuf/v2/internal/testutils/rsapss"
 )
 
 func TestMain(m *testing.M) {
@@ -147,7 +149,7 @@ func TestCompareFromBytesFromFileToBytes(t *testing.T) {
 	assert.NoError(t, err)
 	rootBytesActual, err := root.ToBytes(true)
 	assert.NoError(t, err)
-	assert.Equal(t, rootBytesWant, rootBytesActual)
+	assert.Equal(t, stripWhitespaces(rootBytesWant), stripWhitespaces(rootBytesActual))
 
 	targetsPath := filepath.Join(testutils.RepoDir, "targets.json")
 	targetsBytesWant, err := os.ReadFile(targetsPath)
@@ -156,7 +158,7 @@ func TestCompareFromBytesFromFileToBytes(t *testing.T) {
 	assert.NoError(t, err)
 	targetsBytesActual, err := targets.ToBytes(true)
 	assert.NoError(t, err)
-	assert.Equal(t, targetsBytesWant, targetsBytesActual)
+	assert.Equal(t, stripWhitespaces(targetsBytesWant), stripWhitespaces(targetsBytesActual))
 
 	snapshotPath := filepath.Join(testutils.RepoDir, "snapshot.json")
 	snapshotBytesWant, err := os.ReadFile(snapshotPath)
@@ -165,7 +167,7 @@ func TestCompareFromBytesFromFileToBytes(t *testing.T) {
 	assert.NoError(t, err)
 	snapshotBytesActual, err := snapshot.ToBytes(true)
 	assert.NoError(t, err)
-	assert.Equal(t, snapshotBytesWant, snapshotBytesActual)
+	assert.Equal(t, stripWhitespaces(snapshotBytesWant), stripWhitespaces(snapshotBytesActual))
 
 	timestampPath := filepath.Join(testutils.RepoDir, "timestamp.json")
 	timestampBytesWant, err := os.ReadFile(timestampPath)
@@ -174,7 +176,7 @@ func TestCompareFromBytesFromFileToBytes(t *testing.T) {
 	assert.NoError(t, err)
 	timestampBytesActual, err := timestamp.ToBytes(true)
 	assert.NoError(t, err)
-	assert.Equal(t, timestampBytesWant, timestampBytesActual)
+	assert.Equal(t, stripWhitespaces(timestampBytesWant), stripWhitespaces(timestampBytesActual))
 }
 
 func TestRootReadWriteReadCompare(t *testing.T) {
@@ -265,6 +267,11 @@ func TestTimestampReadWriteReadCompare(t *testing.T) {
 	assert.NoError(t, err)
 }
 
+func stripWhitespaces(b []byte) []byte {
+	tmp := strings.ReplaceAll(string(b), " ", "")
+	return []byte(strings.ReplaceAll(tmp, "\t", ""))
+}
+
 func TestToFromBytes(t *testing.T) {
 	// ROOT
 	rootPath := filepath.Join(testutils.RepoDir, "root.json")
@@ -278,15 +285,16 @@ func TestToFromBytes(t *testing.T) {
 
 	// Case 1: test noncompact by overriding the default serializer.
 	rootBytesWant, err := root.ToBytes(true)
+
 	assert.NoError(t, err)
-	assert.Equal(t, data, rootBytesWant)
+	assert.Equal(t, stripWhitespaces(rootBytesWant), stripWhitespaces(data))
 
 	// Case 2: test compact by using the default serializer.
 	root2, err := Root().FromBytes(rootBytesWant)
 	assert.NoError(t, err)
 	rootBytesActual, err := root2.ToBytes(true)
 	assert.NoError(t, err)
-	assert.Equal(t, rootBytesWant, rootBytesActual)
+	assert.Equal(t, stripWhitespaces(rootBytesWant), stripWhitespaces(rootBytesActual))
 
 	// SNAPSHOT
 	data, err = os.ReadFile(filepath.Join(testutils.RepoDir, "snapshot.json"))
@@ -297,14 +305,14 @@ func TestToFromBytes(t *testing.T) {
 	// Case 1: test noncompact by overriding the default serializer.
 	snapshotBytesWant, err := snapshot.ToBytes(true)
 	assert.NoError(t, err)
-	assert.Equal(t, data, snapshotBytesWant)
+	assert.Equal(t, stripWhitespaces(data), stripWhitespaces(snapshotBytesWant))
 
 	// Case 2: test compact by using the default serializer.
 	snapshot2, err := Snapshot().FromBytes(snapshotBytesWant)
 	assert.NoError(t, err)
 	snapshotBytesActual, err := snapshot2.ToBytes(true)
 	assert.NoError(t, err)
-	assert.Equal(t, snapshotBytesWant, snapshotBytesActual)
+	assert.Equal(t, stripWhitespaces(snapshotBytesWant), stripWhitespaces(snapshotBytesActual))
 
 	// TARGETS
 	data, err = os.ReadFile(filepath.Join(testutils.RepoDir, "targets.json"))
@@ -315,14 +323,14 @@ func TestToFromBytes(t *testing.T) {
 	// Case 1: test noncompact by overriding the default serializer.
 	targetsBytesWant, err := targets.ToBytes(true)
 	assert.NoError(t, err)
-	assert.Equal(t, data, targetsBytesWant)
+	assert.Equal(t, stripWhitespaces(data), stripWhitespaces(targetsBytesWant))
 
 	// Case 2: test compact by using the default serializer.
 	targets2, err := Targets().FromBytes(targetsBytesWant)
 	assert.NoError(t, err)
 	targetsBytesActual, err := targets2.ToBytes(true)
 	assert.NoError(t, err)
-	assert.Equal(t, targetsBytesWant, targetsBytesActual)
+	assert.Equal(t, stripWhitespaces(targetsBytesWant), stripWhitespaces(targetsBytesActual))
 
 	// TIMESTAMP
 	data, err = os.ReadFile(filepath.Join(testutils.RepoDir, "timestamp.json"))
@@ -333,15 +341,14 @@ func TestToFromBytes(t *testing.T) {
 	// Case 1: test noncompact by overriding the default serializer.
 	timestampBytesWant, err := timestamp.ToBytes(true)
 	assert.NoError(t, err)
-	assert.Equal(t, data, timestampBytesWant)
+	assert.Equal(t, stripWhitespaces(data), stripWhitespaces(timestampBytesWant))
 
 	// Case 2: test compact by using the default serializer.
 	timestamp2, err := Timestamp().FromBytes(timestampBytesWant)
 	assert.NoError(t, err)
 	timestampBytesActual, err := timestamp2.ToBytes(true)
 	assert.NoError(t, err)
-	assert.Equal(t, timestampBytesWant, timestampBytesActual)
-
+	assert.Equal(t, stripWhitespaces(timestampBytesWant), stripWhitespaces(timestampBytesActual))
 }
 
 func TestSignVerify(t *testing.T) {
@@ -371,7 +378,11 @@ func TestSignVerify(t *testing.T) {
 	targetsPublicKey, err := targetsKey.ToPublicKey()
 	assert.NoError(t, err)
 	targetsHash := crypto.SHA256
-	targetsVerifier, err := signature.LoadVerifier(targetsPublicKey, targetsHash)
+	targetsVerifier, err := signature.LoadRSAPSSVerifier(
+		targetsPublicKey.(*rsa.PublicKey),
+		targetsHash,
+		&rsa.PSSOptions{Hash: targetsHash},
+	)
 	assert.NoError(t, err)
 	err = targetsVerifier.VerifySignature(bytes.NewReader(sig), bytes.NewReader(data))
 	assert.NoError(t, err)
@@ -459,7 +470,11 @@ func TestKeyVerifyFailures(t *testing.T) {
 	timestampPublicKey, err = timestampKey.ToPublicKey()
 	assert.NoError(t, err)
 	timestampHash = crypto.SHA256
-	timestampVerifier, err = signature.LoadVerifier(timestampPublicKey, timestampHash)
+	timestampVerifier, err = signature.LoadRSAPSSVerifier(
+		timestampPublicKey.(*rsa.PublicKey),
+		timestampHash,
+		&rsa.PSSOptions{Hash: timestampHash},
+	)
 	assert.NoError(t, err)
 	err = timestampVerifier.VerifySignature(bytes.NewReader(timestampSig), bytes.NewReader(data))
 	assert.NoError(t, err)
@@ -587,7 +602,7 @@ func TestMetadataVerifyDelegate(t *testing.T) {
 
 	// Verify succeeds when we correct the new signature and reach the
 	// threshold of 2 keys
-	signer, err := signature.LoadSignerFromPEMFile(filepath.Join(testutils.KeystoreDir, "timestamp_key"), crypto.SHA256, cryptoutils.SkipPassword)
+	signer, err := rsapss.LoadRSAPSSSignerFromPEMFile(filepath.Join(testutils.KeystoreDir, "timestamp_key"))
 	assert.NoError(t, err)
 	_, err = snapshot.Sign(signer)
 	assert.NoError(t, err)
diff --git a/metadata/trustedmetadata/trustedmetadata_test.go b/metadata/trustedmetadata/trustedmetadata_test.go
index 676bc3b..86afddd 100644
--- a/metadata/trustedmetadata/trustedmetadata_test.go
+++ b/metadata/trustedmetadata/trustedmetadata_test.go
@@ -18,16 +18,15 @@
 package trustedmetadata
 
 import (
-	"crypto"
 	"os"
 	"path/filepath"
 	"testing"
 	"time"
 
-	"github.com/sigstore/sigstore/pkg/cryptoutils"
-	"github.com/sigstore/sigstore/pkg/signature"
 	"github.com/stretchr/testify/assert"
+	"github.com/stretchr/testify/require"
 	"github.com/theupdateframework/go-tuf/v2/internal/testutils"
+	"github.com/theupdateframework/go-tuf/v2/internal/testutils/rsapss"
 	"github.com/theupdateframework/go-tuf/v2/metadata"
 )
 
@@ -114,7 +113,7 @@ func modifyRootMetadata(fn modifyRoot) ([]byte, error) {
 	}
 	fn(root)
 
-	signer, err := signature.LoadSignerFromPEMFile(filepath.Join(testutils.KeystoreDir, "root_key"), crypto.SHA256, cryptoutils.SkipPassword)
+	signer, err := rsapss.LoadRSAPSSSignerFromPEMFile(filepath.Join(testutils.KeystoreDir, "root_key"))
 	if err != nil {
 		log.Error(err, "failed to load signer from pem file")
 	}
@@ -137,7 +136,7 @@ func modifyTimestamptMetadata(fn modifyTimestamp) ([]byte, error) {
 	}
 	fn(timestamp)
 
-	signer, err := signature.LoadSignerFromPEMFile(filepath.Join(testutils.KeystoreDir, "timestamp_key"), crypto.SHA256, cryptoutils.SkipPassword)
+	signer, err := rsapss.LoadRSAPSSSignerFromPEMFile(filepath.Join(testutils.KeystoreDir, "timestamp_key"))
 	if err != nil {
 		log.Error(err, "failed to load signer from pem file")
 	}
@@ -160,7 +159,7 @@ func modifySnapshotMetadata(fn modifySnapshot) ([]byte, error) {
 	}
 	fn(snapshot)
 
-	signer, err := signature.LoadSignerFromPEMFile(filepath.Join(testutils.KeystoreDir, "snapshot_key"), crypto.SHA256, cryptoutils.SkipPassword)
+	signer, err := rsapss.LoadRSAPSSSignerFromPEMFile(filepath.Join(testutils.KeystoreDir, "snapshot_key"))
 	if err != nil {
 		log.Error(err, "failed to load signer from pem file")
 	}
@@ -183,7 +182,7 @@ func modifyTargetsMetadata(fn modifyTargets) ([]byte, error) {
 	}
 	fn(targets)
 
-	signer, err := signature.LoadSignerFromPEMFile(filepath.Join(testutils.KeystoreDir, "targets_key"), crypto.SHA256, cryptoutils.SkipPassword)
+	signer, err := rsapss.LoadRSAPSSSignerFromPEMFile(filepath.Join(testutils.KeystoreDir, "targets_key"))
 	if err != nil {
 		log.Error(err, "failed to load signer from pem file")
 	}
@@ -197,7 +196,7 @@ func modifyTargetsMetadata(fn modifyTargets) ([]byte, error) {
 
 func TestUpdate(t *testing.T) {
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP])
 	assert.NoError(t, err)
 	_, err = trustedSet.UpdateSnapshot(allRoles[metadata.SNAPSHOT], false)
@@ -219,7 +218,7 @@ func TestUpdate(t *testing.T) {
 
 func TestOutOfOrderOps(t *testing.T) {
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	//  Update snapshot before timestamp
 	_, err = trustedSet.UpdateSnapshot(allRoles[metadata.SNAPSHOT], false)
@@ -260,7 +259,7 @@ func TestOutOfOrderOps(t *testing.T) {
 
 func TestRootWithInvalidJson(t *testing.T) {
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	// Test loading initial root and root update
 
@@ -284,7 +283,7 @@ func TestRootWithInvalidJson(t *testing.T) {
 
 func TestTopLevelMetadataWithInvalidJSON(t *testing.T) {
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	//TIMESTAMP
 	// timestamp is not json
@@ -359,7 +358,7 @@ func TestUpdateRootNewRoot(t *testing.T) {
 	assert.NoError(t, err)
 
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateRoot(root)
 	assert.NoError(t, err)
 }
@@ -374,14 +373,14 @@ func TestUpdateRootNewRootFailTreshholdVerification(t *testing.T) {
 	assert.NoError(t, err)
 
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateRoot(root)
 	assert.ErrorIs(t, err, &metadata.ErrUnsignedMetadata{Msg: "Verifying root failed, not enough signatures, got 1, want 2"})
 }
 
 func TestUpdateRootNewRootVerSameAsTrustedRootVer(t *testing.T) {
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	_, err = trustedSet.UpdateRoot(allRoles[metadata.ROOT])
 	assert.ErrorIs(t, err, &metadata.ErrBadVersionNumber{Msg: "bad version number, expected 2, got 1"})
@@ -397,7 +396,7 @@ func TestRootExpiredFinalRoot(t *testing.T) {
 	root, err := modifyRootMetadata(modifyRootExpiry)
 	assert.NoError(t, err)
 	trustedSet, err := New(root)
-	assert.NoError(t, err)
+	require.NoError(t, err)
 
 	// Update timestamp to trigger final root expiry check
 	_, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP])
@@ -413,7 +412,7 @@ func TestUpdateTimestampNewTimestampVerBelowTrustedVer(t *testing.T) {
 	assert.NoError(t, err)
 
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateTimestamp(timestamp)
 	assert.NoError(t, err)
 	_, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP])
@@ -424,7 +423,7 @@ func TestUpdateTimestampWithSameTimestamp(t *testing.T) {
 	// Test that timestamp is NOT updated if:
 	// newTimestamp.Version = trustedTimestamp.Version
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP])
 	assert.NoError(t, err)
 
@@ -448,7 +447,7 @@ func TestUpdateTimestampSnapshotCerBellowCurrent(t *testing.T) {
 	timestamp, err := modifyTimestamptMetadata(bumpSnapshotVersion)
 	assert.NoError(t, err)
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateTimestamp(timestamp)
 	assert.NoError(t, err)
 
@@ -466,7 +465,7 @@ func TestUpdateTimestampExpired(t *testing.T) {
 	timestamp, err := modifyTimestamptMetadata(modifyTimestampExpiry)
 	assert.NoError(t, err)
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateTimestamp(timestamp)
 	assert.ErrorIs(t, err, &metadata.ErrExpiredMetadata{Msg: "timestamp.json is expired"})
 	_, err = trustedSet.UpdateSnapshot(allRoles[metadata.SNAPSHOT], false)
@@ -481,7 +480,7 @@ func TestUpdateSnapshotLengthOrHashMismatch(t *testing.T) {
 	timestamp, err := modifyTimestamptMetadata(modifySnapshotLength)
 	assert.NoError(t, err)
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateTimestamp(timestamp)
 	assert.NoError(t, err)
 	_, err = trustedSet.UpdateSnapshot(allRoles[metadata.SNAPSHOT], false)
@@ -490,7 +489,7 @@ func TestUpdateSnapshotLengthOrHashMismatch(t *testing.T) {
 
 func TestUpdateSnapshotFailThreshholdVerification(t *testing.T) {
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP])
 	assert.NoError(t, err)
 
@@ -510,7 +509,7 @@ func TestUpdateSnapshotVersionDivergeTimestampSnapshotVersion(t *testing.T) {
 	timestamp, err := modifyTimestamptMetadata(modifyTimestampVersion)
 	assert.NoError(t, err)
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateTimestamp(timestamp)
 	assert.NoError(t, err)
 
@@ -544,7 +543,7 @@ func updateAllBesidesTargets(trustedSet *TrustedMetadata, timestampBytes []byte,
 
 func TestUpdateSnapshotFileRemovedFromMeta(t *testing.T) {
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	err = updateAllBesidesTargets(trustedSet, allRoles[metadata.TIMESTAMP], []byte{})
 	assert.NoError(t, err)
 	removeFileFromMeta := func(snaphot *metadata.Metadata[metadata.SnapshotType]) {
@@ -559,7 +558,7 @@ func TestUpdateSnapshotFileRemovedFromMeta(t *testing.T) {
 
 func TestUpdateSnapshotMetaVersionDecreases(t *testing.T) {
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP])
 	assert.NoError(t, err)
 
@@ -577,7 +576,7 @@ func TestUpdateSnapshotMetaVersionDecreases(t *testing.T) {
 
 func TestUpdateSnapshotExpiredNewSnapshot(t *testing.T) {
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP])
 	assert.NoError(t, err)
 
@@ -600,7 +599,7 @@ func TestUpdateSnapshotExpiredNewSnapshot(t *testing.T) {
 func TestUpdateSnapshotSuccessfulRollbackChecks(t *testing.T) {
 	// Load a "local" timestamp, then update to newer one:
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	_, err = trustedSet.UpdateTimestamp(allRoles[metadata.TIMESTAMP])
 	assert.NoError(t, err)
 
@@ -641,7 +640,7 @@ func TestUpdateTargetsMoMetaInSnapshot(t *testing.T) {
 	snapshot, err := modifySnapshotMetadata(clearMeta)
 	assert.NoError(t, err)
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	err = updateAllBesidesTargets(trustedSet, allRoles[metadata.TIMESTAMP], snapshot)
 	assert.NoError(t, err)
 
@@ -663,7 +662,7 @@ func TestUpdateTargetsHashDiverfeFromSnapshotMetaHash(t *testing.T) {
 	snapshot, err := modifySnapshotMetadata(modifyMetaLength)
 	assert.NoError(t, err)
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	err = updateAllBesidesTargets(trustedSet, allRoles[metadata.TIMESTAMP], snapshot)
 	assert.NoError(t, err)
 
@@ -681,7 +680,7 @@ func TestUpdateTargetsVersionDivergeSnapshotMetaVersion(t *testing.T) {
 	snapshot, err := modifySnapshotMetadata(modifyMeta)
 	assert.NoError(t, err)
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	err = updateAllBesidesTargets(trustedSet, allRoles[metadata.TIMESTAMP], snapshot)
 	assert.NoError(t, err)
 
@@ -692,7 +691,7 @@ func TestUpdateTargetsVersionDivergeSnapshotMetaVersion(t *testing.T) {
 
 func TestUpdateTargetsExpiredMewTarget(t *testing.T) {
 	trustedSet, err := New(allRoles[metadata.ROOT])
-	assert.NoError(t, err)
+	require.NoError(t, err)
 	err = updateAllBesidesTargets(trustedSet, allRoles[metadata.TIMESTAMP], allRoles[metadata.SNAPSHOT])
 	assert.NoError(t, err)