Skip to content

Commit b529335

Browse files
authored
Merge pull request #1185 from sigstore/set-verification
Re-add and enhance SET verification in KeylessVerifier
2 parents f6934e5 + 49c27f1 commit b529335

4 files changed

Lines changed: 48 additions & 6 deletions

File tree

sigstore-java/src/main/java/dev/sigstore/KeylessVerifier.java

Lines changed: 24 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,10 @@
6161
import java.security.cert.CertificateNotYetValidException;
6262
import java.security.cert.X509Certificate;
6363
import java.security.spec.InvalidKeySpecException;
64+
import java.time.Instant;
6465
import java.util.Arrays;
6566
import java.util.Base64;
67+
import java.util.Date;
6668
import java.util.List;
6769
import java.util.Objects;
6870
import java.util.stream.Collectors;
@@ -183,20 +185,37 @@ public void verify(byte[] artifactDigest, Bundle bundle, VerificationOptions opt
183185
signature = dsseEnvelope.getSignature();
184186
}
185187

186-
verifyTimestamps(leafCert, bundle.getTimestamps(), signature);
187-
188188
try {
189189
rekorVerifier.verifyEntry(rekorEntry);
190190
} catch (RekorVerificationException ex) {
191191
throw new KeylessVerificationException("Transparency log entry could not be verified", ex);
192192
}
193+
194+
// if entry was verified and has a SET, get time from it
195+
var set = rekorEntry.getVerification().getSignedEntryTimestamp();
196+
var entryTime = set != null ? rekorEntry.getIntegratedTimeInstant() : null;
197+
198+
verifyTimestamps(leafCert, bundle.getTimestamps(), entryTime, signature);
193199
}
194200

195201
private void verifyTimestamps(
196-
X509Certificate leafCert, List<Bundle.Timestamp> timestamps, byte[] signature)
202+
X509Certificate leafCert,
203+
List<Bundle.Timestamp> timestamps,
204+
Instant entryTime,
205+
byte[] signature)
197206
throws KeylessVerificationException {
198-
if (timestamps == null || timestamps.isEmpty()) {
199-
return;
207+
if (timestamps.isEmpty() && entryTime == null) {
208+
throw new KeylessVerificationException("No valid timestamps found in bundle");
209+
}
210+
if (entryTime != null) {
211+
var entryDate = Date.from(entryTime);
212+
try {
213+
leafCert.checkValidity(entryDate);
214+
} catch (CertificateNotYetValidException e) {
215+
throw new KeylessVerificationException("Signing time was before certificate validity", e);
216+
} catch (CertificateExpiredException e) {
217+
throw new KeylessVerificationException("Signing time was after certificate expiry", e);
218+
}
200219
}
201220
for (Bundle.Timestamp timestamp : timestamps) {
202221
byte[] tsBytes = timestamp.getRfc3161Timestamp();

sigstore-java/src/main/java/dev/sigstore/bundle/Bundle.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,8 @@ protected void checkOnlyOneSignature() {
7171
@Value.Check
7272
protected void checkAtLeastOneTimestamp() {
7373
for (var entry : getEntries()) {
74-
if (entry.getVerification().getSignedEntryTimestamp() != null) {
74+
if (entry.getVerification().getSignedEntryTimestamp() != null
75+
&& entry.getIntegratedTime() > 0) {
7576
return;
7677
}
7778
}

sigstore-java/src/test/java/dev/sigstore/KeylessVerifierTest.java

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -796,4 +796,25 @@ public void testVerify_invalidSet_validRfc3161Timestamp_rekorV1() throws Excepti
796796
private Bundle.Timestamp createTimestamp(byte[] rfc3161Bytes) {
797797
return () -> rfc3161Bytes;
798798
}
799+
800+
@Test
801+
public void testVerify_certificateExpired_rekorV1() throws Exception {
802+
var bundleFile =
803+
Resources.toString(
804+
Resources.getResource("dev/sigstore/samples/bundles/bundle-with-expired-cert.sigstore"),
805+
StandardCharsets.UTF_8);
806+
807+
var artifact = Resources.getResource("dev/sigstore/samples/bundles/artifact.txt").getPath();
808+
var verifier = KeylessVerifier.builder().sigstorePublicDefaults().build();
809+
810+
var ex =
811+
Assertions.assertThrows(
812+
KeylessVerificationException.class,
813+
() ->
814+
verifier.verify(
815+
Path.of(artifact),
816+
Bundle.from(new StringReader(bundleFile)),
817+
VerificationOptions.empty()));
818+
Assertions.assertEquals("Signing time was after certificate expiry", ex.getMessage());
819+
}
799820
}
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{"mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json", "verificationMaterial": {"tlogEntries": [{"logIndex": "1462192450", "logId": {"keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="}, "kindVersion": {"kind": "hashedrekord", "version": "0.0.1"}, "integratedTime": "1778168051", "inclusionPromise": {"signedEntryTimestamp": "MEYCIQCBfm+xmWXqWflrp2JgyfCY0qb++78Cra29Vs+SStt4FgIhAMjZC/86BZgLLWhhpKe1Wao+fVcWYejJ65VBTGNTjiYS"}, "inclusionProof": {"logIndex": "1340288188", "rootHash": "EWNmEJsW7QWRkOi23m4GlDd4MGoI0UjY9DAZohjXlWk=", "treeSize": "1340288195", "hashes": ["hH4RvIttV2homP8j6CrqITnNdpP2sRuzJLoZzc94ab8=", "1ik9sQEO0QDjE2BkNDCBA4Ihpjs5Zfvi0fpRHJT/LZQ=", "sna/tNh7sprFUkMFBljtqXV98UAZxuTU1Dk8/F9VQ3Y=", "FG9dQnr4T0WQWrQRhnnm4gaoSuJA2rOZfTm7VjT2H88=", "ZsCsat3c7j/YIv0CEPcVmrvoW4nhOLROGxyjcWCM9rc=", "GgxTuDesW2KFqhcqhqqfGRNAGoFJ1n4TRBm/O8X1Z4A=", "tjdjuFaotsCeZrmSN5T+ZcL4HPjPkECzyjryxZp808I=", "Oxm9RrDXSFUZVzkMFRJeWmfWEZD7zDQgPzEpLScg/hw=", "3qJjyVyIO5i7HR4EatErFW0PGAKkj9jMda2QUs1xJXE=", "GhuxYIqwbqeaCDLg0wUWtPJBmHEuOIXWLX4IRtDNEcM=", "jm4JDsxWzcPtPDLJMERMmbxmk/3hbBZSEE/+ZXLOtic=", "As2gQT6Bp2RVJmb8PLUxIA90apj9rGD/YZy7KqoTY7s=", "bWHK0MhK394gUhlUBrD9eMjgQjTUGjTlPNttup6RqCY=", "RzpCRhrNj8YZc5hzD6OEkrFdNXcvvaUat3mi5zBNuvo=", "8L3vyr7bSMi9mq+IegoJMElt7m/GWOdTH748bO2KbG0=", "hmhKI9LzXhjcM+YgtveRLC1MPH/odBQLXHuMkmmXxY0=", "U4/E+eMJYE5BMO0gMJAnUAgLXwvXxebDIvstqh7yb0I=", "MRhrtVor/Uf+hKlyhFWOk/9/Q2C3edC1EaJ+/VXSd0E=", "wa5W79zKcyNncVVFXx8PM8785J+n0U0qxiK2GXKz2Hk=", "7y22/OdvnNTJ3gzz57WEW6D/mmmrLXV0dVQyDwenx5A=", "DOCeoSMovIvLExkhIvisow9AuNXgeWs4ECkyR6EcqYU="], "checkpoint": {"envelope": "rekor.sigstore.dev - 1193050959916656506\n1340288195\nEWNmEJsW7QWRkOi23m4GlDd4MGoI0UjY9DAZohjXlWk=\n\n\u2014 rekor.sigstore.dev wNI9ajBGAiEA/2nZDMu2rSksOOoRaSv+0HstBFDKRAb6zu8mw/2Qw0cCIQDtnfKyX4/jfwhy3+wyZ7dPQYQSlNClMp0boLJJSouf2g==\n"}}, "canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJhMGNmYzcxMjcxZDZlMjc4ZTU3Y2QzMzJmZjk1N2MzZjcwNDNmZGRhMzU0YzRjYmIxOTBhMzBkNTZlZmEwMWJmIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FUUNJSGFkcm1xa0M1V0ZPSTVyNTBwY2p4eXE4SjZXanpsZUNvZ0k3aHdZT29BT0FpQVgwWUJQd09iYmxKaU16YVdmZzZlV0d1aWJocjQrRlJsNitzMmUxWmFVQ1E9PSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTTRha05EUVc1bFowRjNTVUpCWjBsVlVtdFRaMHh0WlNzMmRXd3ZWRzE2ZFd0MmNISm9aVW8xVVVWSmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFpkMDVVUVROTlZGVjRUMFJGZDFkb1kwNU5hbGwzVGxSQk0wMVVWWGxQUkVWM1YycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZCZUZoVFQwbHRRakJWWVd0NmVITkNZWEV2VWxOdFRsWmFPVmhKU2xoYWRWcGpkVUVLYzBZM1RsQnRZVUkzTlROTU9FVnNVUzl0TmxJd2JGSm9SbmREU2xVNFZXaE5iV05IVFhkemQwdDZlRkJQWmxFck4zRlBRMEZhV1hkblowZFRUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZQVTNGUENqVmFZMDFUZEdFMVdrVXJiMVZvY1ZSQkswWlJVbnBaZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDFKM1dVUldVakJTUVZGSUwwSkVNSGRQTkVVMVpGYzFNR051Vm5wa1IxWnJURmhPYUZGSVRuQmFNMDR3WWpOS2JFeFhUblppYlZwMlkyMHhhQXBpYlU1c1RHMXNhR0pUTlc1ak1sWjVaRzFzYWxwWFJtcFpNamt4WW01UmRWa3lPWFJOUTJ0SFEybHpSMEZSVVVKbk56aDNRVkZGUlVjeWFEQmtTRUo2Q2s5cE9IWlpWMDVxWWpOV2RXUklUWFZhTWpsMldqSjRiRXh0VG5aaVZFRnlRbWR2Y2tKblJVVkJXVTh2VFVGRlNVSkNNRTFITW1nd1pFaENlazlwT0hZS1dWZE9hbUl6Vm5Wa1NFMTFXakk1ZGxveWVHeE1iVTUyWWxSRFFtbFJXVXRMZDFsQ1FrRklWMlZSU1VWQloxSTNRa2hyUVdSM1FqRkJUakE1VFVkeVJ3cDRlRVY1V1hoclpVaEtiRzVPZDB0cFUydzJORE5xZVhRdk5HVkxZMjlCZGt0bE5rOUJRVUZDYm1kTlJXcDFiMEZCUVZGRVFVVlpkMUpCU1dkbFV6a3lDbGhPTjI5cUsxaDRiVWxZY0dkbGNqa3ZOM05xT1ZGd1EzWXlZamt5UWtZeGJGZE1Vak5hWTBOSlJuaDRSWFZZYlVKa00yRnRaMUZCV0VWdGFIRkdWRW9LZVRkbk9XSnNWVTUySzA5blNYQk9iV3B0WTB0TlFXOUhRME54UjFOTk5EbENRVTFFUVRKclFVMUhXVU5OVVVOcFZ6ZGtkekF5UlRodU5URlJOVmM0VndwWVZ6aHJUVlJ1YVRsVVQzYzNObXhaUmpWYVFuWXlhWFY1ZG1SNVZDOUVWWEF5Y2xGMU5XWTRjMVpaV0c5eVdVTk5VVVJKTlVWUU9VbEplV0ZJTDBwSENsTlVNV3RTT1NzclUxVk9TRTQwYkUxa2IyZEpjemxGVUdoSWVWUnZNamx5V0dGRGNHdDROMDlDYUhkU1NEVklTR1poUVQwS0xTMHRMUzFGVGtRZ1EwVlNWRWxHU1VOQlZFVXRMUzB0TFFvPSJ9fX19"}], "certificate": {"rawBytes": "MIIC8jCCAnegAwIBAgIURkSgLme+6ul/TmzukvprheJ5QEIwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjYwNTA3MTUxODEwWhcNMjYwNTA3MTUyODEwWjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEAxXSOImB0UakzxsBaq/RSmNVZ9XIJXZuZcuAsF7NPmaB753L8ElQ/m6R0lRhFwCJU8UhMmcGMwswKzxPOfQ+7qOCAZYwggGSMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUOSqO5ZcMSta5ZE+oUhqTA+FQRzYwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4YZD8wRwYDVR0RAQH/BD0wO4E5dW50cnVzdGVkLXNhQHNpZ3N0b3JlLWNvbmZvcm1hbmNlLmlhbS5nc2VydmljZWFjY291bnQuY29tMCkGCisGAQQBg78wAQEEG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTArBgorBgEEAYO/MAEIBB0MG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTCBiQYKKwYBBAHWeQIEAgR7BHkAdwB1AN09MGrGxxEyYxkeHJlnNwKiSl643jyt/4eKcoAvKe6OAAABngMEjuoAAAQDAEYwRAIgeS92XN7oj+XxmIXpger9/7sj9QpCv2b92BF1lWLR3ZcCIFxxEuXmBd3amgQAXEmhqFTJy7g9blUNv+OgIpNmjmcKMAoGCCqGSM49BAMDA2kAMGYCMQCiW7dw02E8n51Q5W8WXW8kMTni9TOw76lYF5ZBv2iuyvdyT/DUp2rQu5f8sVYXorYCMQDI5EP9IIyaH/JGST1kR9++SUNHN4lMdogIs9EPhHyTo29rXaCpkx7OBhwRH5HHfaA="}}, "messageSignature": {"messageDigest": {"algorithm": "SHA2_256", "digest": "oM/HEnHW4njlfNMy/5V8P3BD/do1TEy7GQow1W76Ab8="}, "signature": "MEQCIHadrmqkC5WFOI5r50pcjxyq8J6WjzleCogI7hwYOoAOAiAX0YBPwObblJiMzaWfg6eWGuibhr4+FRl6+s2e1ZaUCQ=="}}

0 commit comments

Comments
 (0)