11/*
2- Copyright 2023 The Sigstore Authors.
2+ Copyright 2025 The Sigstore Authors.
33
44Licensed under the Apache License, Version 2.0 (the "License");
55you may not use this file except in compliance with the License.
@@ -16,9 +16,10 @@ limitations under the License.
1616import { BundleWithDsseEnvelope , bundleFromJSON } from '@sigstore/bundle' ;
1717import { signatureContent } from '../../bundle' ;
1818import { VerificationError } from '../../error' ;
19- import { verifyDSSETLogBody } from '../../tlog/dsse' ;
19+ import { verifyDSSETLogBody , verifyDSSETLogBodyV2 } from '../../tlog/dsse' ;
2020import * as bundles from '../__fixtures__/bundles' ;
2121
22+ import { Entry } from '@sigstore/protobuf-specs/rekor/v2' ;
2223import type { ProposedDSSEEntry } from '@sigstore/rekor-types' ;
2324
2425describe ( 'verifyDSSETLogBody' , ( ) => {
@@ -158,3 +159,118 @@ describe('verifyDSSETLogBody', () => {
158159 } ) ;
159160 } ) ;
160161} ) ;
162+
163+ describe ( 'verifyDSSETLogBodyV2' , ( ) => {
164+ const bundle = bundleFromJSON (
165+ bundles . V3 . DSSE . WITH_SIGNING_CERT . TLOG_DSSEV002
166+ ) ;
167+ const tlogEntry = bundle . verificationMaterial . tlogEntries [ 0 ] ;
168+ const content = signatureContent ( bundle ) ;
169+
170+ describe ( 'when everything is valid' , ( ) => {
171+ const body = Entry . fromJSON (
172+ JSON . parse ( tlogEntry . canonicalizedBody . toString ( 'utf8' ) )
173+ ) ;
174+
175+ it ( 'does NOT throw an error' , ( ) => {
176+ expect ( verifyDSSETLogBodyV2 ( body , content ) ) . toBeUndefined ( ) ;
177+ } ) ;
178+ } ) ;
179+
180+ describe ( 'when the spec is missing' , ( ) => {
181+ const body = Entry . fromJSON (
182+ JSON . parse ( tlogEntry . canonicalizedBody . toString ( 'utf8' ) )
183+ ) ;
184+
185+ body . spec = undefined ;
186+
187+ it ( 'throws an error' , ( ) => {
188+ expect ( ( ) => verifyDSSETLogBodyV2 ( body , content ) ) . toThrowWithCode (
189+ VerificationError ,
190+ 'TLOG_BODY_ERROR'
191+ ) ;
192+ } ) ;
193+ } ) ;
194+
195+ describe ( 'when the spec is unsupported' , ( ) => {
196+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
197+ const body : any = Entry . fromJSON (
198+ JSON . parse ( tlogEntry . canonicalizedBody . toString ( 'utf8' ) )
199+ ) ;
200+
201+ body . spec = { spec : { $case : 'unknownSpec' , unknownSpec : { } } } ;
202+
203+ it ( 'throws an error' , ( ) => {
204+ expect ( ( ) => verifyDSSETLogBodyV2 ( body , content ) ) . toThrowWithCode (
205+ VerificationError ,
206+ 'TLOG_BODY_ERROR'
207+ ) ;
208+ } ) ;
209+ } ) ;
210+
211+ describe ( 'when the signature is missing in the dsse entry' , ( ) => {
212+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
213+ const body : any = Entry . fromJSON (
214+ JSON . parse ( tlogEntry . canonicalizedBody . toString ( 'utf8' ) )
215+ ) ;
216+
217+ body . spec ! . spec . dsseV002 . signatures ! . push (
218+ body . spec ! . spec . dsseV002 . signatures ! [ 0 ]
219+ ) ;
220+
221+ it ( 'throws an error' , ( ) => {
222+ expect ( ( ) => verifyDSSETLogBodyV2 ( body , content ) ) . toThrowWithCode (
223+ VerificationError ,
224+ 'TLOG_BODY_ERROR'
225+ ) ;
226+ } ) ;
227+ } ) ;
228+
229+ describe ( 'when the signature does NOT match the value in the dsse entry' , ( ) => {
230+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
231+ const body : any = Entry . fromJSON (
232+ JSON . parse ( tlogEntry . canonicalizedBody . toString ( 'utf8' ) )
233+ ) ;
234+
235+ body . spec . spec . dsseV002 . signatures [ 0 ] = { content : Buffer . from ( 'oops' ) } ;
236+
237+ it ( 'throws an error' , ( ) => {
238+ expect ( ( ) => verifyDSSETLogBodyV2 ( body , content ) ) . toThrowWithCode (
239+ VerificationError ,
240+ 'TLOG_BODY_ERROR'
241+ ) ;
242+ } ) ;
243+ } ) ;
244+
245+ describe ( 'when the payload hash does NOT match the value in the dsse entry' , ( ) => {
246+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
247+ const body : any = Entry . fromJSON (
248+ JSON . parse ( tlogEntry . canonicalizedBody . toString ( 'utf8' ) )
249+ ) ;
250+
251+ body . spec . spec . dsseV002 . payloadHash . digest = Buffer . from ( 'oops' ) ;
252+
253+ it ( 'throws an error' , ( ) => {
254+ expect ( ( ) => verifyDSSETLogBodyV2 ( body , content ) ) . toThrowWithCode (
255+ VerificationError ,
256+ 'TLOG_BODY_ERROR'
257+ ) ;
258+ } ) ;
259+ } ) ;
260+
261+ describe ( 'when the digest is missing in the dsse entry' , ( ) => {
262+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
263+ const body : any = Entry . fromJSON (
264+ JSON . parse ( tlogEntry . canonicalizedBody . toString ( 'utf8' ) )
265+ ) ;
266+
267+ delete body . spec . spec . dsseV002 . payloadHash . digest ;
268+
269+ it ( 'throws an error' , ( ) => {
270+ expect ( ( ) => verifyDSSETLogBodyV2 ( body , content ) ) . toThrowWithCode (
271+ VerificationError ,
272+ 'TLOG_BODY_ERROR'
273+ ) ;
274+ } ) ;
275+ } ) ;
276+ } ) ;
0 commit comments