Skip to content

Commit 55bb102

Browse files
lsd-catclaude
andauthored
Enforce observer timestamp in verifyDsse() (#26)
The observer-timestamp guard added in #25 lives only in verify(); callers that verify via verifyDsse() had no such check. A bundle with no integratedTime, no inclusion promise, and an empty timestampVerificationData ({}) therefore passed verifyDsse() with zero verified timestamps, leaving the signing certificate's validity window unanchored in time. Mirror the verify() guard in verifyDsse(): each tlog entry must be anchored by either integratedTime (the cert must be valid then) or a signed RFC3161 timestamp. This brings verifyDsse() in line with the observer-timestamp enforcement in the upstream sigstore-js and sigstore-go clients. Bump to 0.1.14 (0.1.13 was published before #25). Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent fd1ee6c commit 55bb102

2 files changed

Lines changed: 25 additions & 1 deletion

File tree

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@freedomofpress/sigstore-browser",
3-
"version": "0.1.12",
3+
"version": "0.1.14",
44
"description": "A minimal browser-only Sigstore verification library.",
55
"repository": {
66
"type": "git",

src/sigstore.ts

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -896,6 +896,30 @@ public async verifyArtifact(
896896
}
897897
}
898898

899+
// Every tlog entry must be anchored in time by at least one observer
900+
// timestamp, matching the observer-timestamp enforcement in the upstream
901+
// sigstore-js and sigstore-go clients. A v1 entry carries integratedTime
902+
// (the signing certificate must be valid at that instant); a v2 entry omits
903+
// it and must instead carry a signed RFC3161 timestamp. Without either, the
904+
// certificate's validity window is never anchored — a crafted bundle that
905+
// strips integratedTime + the inclusion promise and supplies an empty
906+
// timestampVerificationData ({}) would otherwise pass. This mirrors the
907+
// guard in verify(), which callers verifying via verifyDsse() would miss.
908+
for (const entry of bundle.verificationMaterial.tlogEntries) {
909+
if (entry.integratedTime) {
910+
const integratedDate = new Date(Number(entry.integratedTime) * 1000);
911+
if (!signingCert.validForDate(integratedDate)) {
912+
throw new Error(
913+
"Artifact signing was logged outside of the certificate validity.",
914+
);
915+
}
916+
} else {
917+
assertRekorV2Timestamp(
918+
bundle.verificationMaterial.timestampVerificationData,
919+
);
920+
}
921+
}
922+
899923
// (7) Verify the DSSE envelope signature
900924
const payloadBytes = base64ToUint8Array(bundle.dsseEnvelope.payload);
901925
const pae = preAuthEncoding(bundle.dsseEnvelope.payloadType, payloadBytes);

0 commit comments

Comments
 (0)