26
26
import dev .sigstore .bundle .Bundle .HashAlgorithm ;
27
27
import dev .sigstore .bundle .Bundle .MessageSignature ;
28
28
import dev .sigstore .bundle .ImmutableBundle ;
29
+ import dev .sigstore .bundle .ImmutableTimestamp ;
29
30
import dev .sigstore .encryption .certificates .Certificates ;
30
31
import dev .sigstore .encryption .signers .Signer ;
31
32
import dev .sigstore .encryption .signers .Signers ;
46
47
import dev .sigstore .rekor .client .RekorResponse ;
47
48
import dev .sigstore .rekor .client .RekorVerificationException ;
48
49
import dev .sigstore .rekor .client .RekorVerifier ;
50
+ import dev .sigstore .timestamp .client .ImmutableTimestampRequest ;
51
+ import dev .sigstore .timestamp .client .TimestampClient ;
52
+ import dev .sigstore .timestamp .client .TimestampClientHttp ;
53
+ import dev .sigstore .timestamp .client .TimestampException ;
54
+ import dev .sigstore .timestamp .client .TimestampResponse ;
55
+ import dev .sigstore .timestamp .client .TimestampVerificationException ;
56
+ import dev .sigstore .timestamp .client .TimestampVerifier ;
49
57
import dev .sigstore .trustroot .SigstoreConfigurationException ;
50
58
import dev .sigstore .tuf .SigstoreTufClient ;
51
59
import java .io .IOException ;
@@ -89,6 +97,8 @@ public class KeylessSigner implements AutoCloseable {
89
97
private final FulcioVerifier fulcioVerifier ;
90
98
private final RekorClient rekorClient ;
91
99
private final RekorVerifier rekorVerifier ;
100
+ private final TimestampClient timestampClient ;
101
+ private final TimestampVerifier timestampVerifier ;
92
102
private final OidcClients oidcClients ;
93
103
private final List <OidcTokenMatcher > oidcIdentities ;
94
104
private final Signer signer ;
@@ -114,6 +124,8 @@ private KeylessSigner(
114
124
FulcioVerifier fulcioVerifier ,
115
125
RekorClient rekorClient ,
116
126
RekorVerifier rekorVerifier ,
127
+ TimestampClient timestampClient ,
128
+ TimestampVerifier timestampVerifier ,
117
129
OidcClients oidcClients ,
118
130
List <OidcTokenMatcher > oidcIdentities ,
119
131
Signer signer ,
@@ -122,6 +134,8 @@ private KeylessSigner(
122
134
this .fulcioVerifier = fulcioVerifier ;
123
135
this .rekorClient = rekorClient ;
124
136
this .rekorVerifier = rekorVerifier ;
137
+ this .timestampClient = timestampClient ;
138
+ this .timestampVerifier = timestampVerifier ;
125
139
this .oidcClients = oidcClients ;
126
140
this .oidcIdentities = oidcIdentities ;
127
141
this .signer = signer ;
@@ -152,6 +166,7 @@ public static class Builder {
152
166
private Duration minSigningCertificateLifetime = DEFAULT_MIN_SIGNING_CERTIFICATE_LIFETIME ;
153
167
private URI fulcioUri ;
154
168
private URI rekorUri ;
169
+ private URI timestampUri ;
155
170
156
171
@ CanIgnoreReturnValue
157
172
public Builder fulcioUrl (URI uri ) {
@@ -165,6 +180,12 @@ public Builder rekorUrl(URI uri) {
165
180
return this ;
166
181
}
167
182
183
+ @ CanIgnoreReturnValue
184
+ public Builder timestampUrl (URI uri ) {
185
+ this .timestampUri = uri ;
186
+ return this ;
187
+ }
188
+
168
189
@ CanIgnoreReturnValue
169
190
public Builder trustedRootProvider (TrustedRootProvider trustedRootProvider ) {
170
191
this .trustedRootProvider = trustedRootProvider ;
@@ -233,11 +254,19 @@ public KeylessSigner build()
233
254
var fulcioVerifier = FulcioVerifier .newFulcioVerifier (trustedRoot );
234
255
var rekorClient = RekorClientHttp .builder ().setUri (rekorUri ).build ();
235
256
var rekorVerifier = RekorVerifier .newRekorVerifier (trustedRoot );
257
+ TimestampClient timestampClient = null ;
258
+ TimestampVerifier timestampVerifier = null ;
259
+ if (timestampUri != null ) { // Building with staging defaults
260
+ timestampClient = TimestampClientHttp .builder ().setUri (timestampUri ).build ();
261
+ timestampVerifier = TimestampVerifier .newTimestampVerifier (trustedRoot );
262
+ }
236
263
return new KeylessSigner (
237
264
fulcioClient ,
238
265
fulcioVerifier ,
239
266
rekorClient ,
240
267
rekorVerifier ,
268
+ timestampClient ,
269
+ timestampVerifier ,
241
270
oidcClients ,
242
271
oidcIdentities ,
243
272
signer ,
@@ -270,6 +299,7 @@ public Builder sigstoreStagingDefaults() {
270
299
trustedRootProvider = TrustedRootProvider .from (sigstoreTufClientBuilder );
271
300
fulcioUri = FulcioClient .STAGING_URI ;
272
301
rekorUri = RekorClient .STAGING_URI ;
302
+ timestampUri = TimestampClient .STAGING_URI ;
273
303
oidcClients (OidcClients .STAGING );
274
304
signer (Signers .newEcdsaSigner ());
275
305
minSigningCertificateLifetime (DEFAULT_MIN_SIGNING_CERTIFICATE_LIFETIME );
@@ -355,13 +385,43 @@ public List<Bundle> sign(List<byte[]> artifactDigests) throws KeylessSignerExcep
355
385
throw new KeylessSignerException ("Failed to validate rekor response after signing" , ex );
356
386
}
357
387
358
- result . add (
388
+ var bundleBuilder =
359
389
ImmutableBundle .builder ()
360
390
.certPath (signingCert )
361
391
.addEntries (rekorResponse .getEntry ())
362
392
.messageSignature (
363
- MessageSignature .of (HashAlgorithm .SHA2_256 , artifactDigest , signature ))
364
- .build ());
393
+ MessageSignature .of (HashAlgorithm .SHA2_256 , artifactDigest , signature ));
394
+
395
+ // Timestamp functionality only enabled if timestampUri is provided
396
+ if (timestampClient != null && timestampVerifier != null ) {
397
+ var signatureDigest = Hashing .sha256 ().hashBytes (signature ).asBytes ();
398
+
399
+ var tsReq =
400
+ ImmutableTimestampRequest .builder ()
401
+ .hashAlgorithm (dev .sigstore .timestamp .client .HashAlgorithm .SHA256 )
402
+ .hash (signatureDigest )
403
+ .build ();
404
+
405
+ TimestampResponse tsResp ;
406
+ try {
407
+ tsResp = timestampClient .timestamp (tsReq );
408
+ } catch (TimestampException ex ) {
409
+ throw new KeylessSignerException ("Failed to generate timestamp" , ex );
410
+ }
411
+
412
+ try {
413
+ timestampVerifier .verify (tsResp , signature );
414
+ } catch (TimestampVerificationException ex ) {
415
+ throw new KeylessSignerException ("Returned timestamp was invalid" , ex );
416
+ }
417
+
418
+ Bundle .Timestamp timestamp =
419
+ ImmutableTimestamp .builder ().rfc3161Timestamp (tsResp .getEncoded ()).build ();
420
+
421
+ bundleBuilder .addTimestamps (timestamp );
422
+ }
423
+
424
+ result .add (bundleBuilder .build ());
365
425
}
366
426
return result .build ();
367
427
}
0 commit comments