Skip to content

Commit 1dd557b

Browse files
committed
Rekor Entry should be reconstructued to match
Signed-off-by: Appu Goundan <[email protected]>
1 parent b440f06 commit 1dd557b

File tree

4 files changed

+89
-0
lines changed

4 files changed

+89
-0
lines changed

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,8 +63,10 @@
6363
import java.util.Collections;
6464
import java.util.List;
6565
import java.util.Map;
66+
import java.util.Objects;
6667
import java.util.concurrent.locks.ReentrantReadWriteLock;
6768
import javax.annotation.Nullable;
69+
import org.bouncycastle.util.encoders.Base64;
6870

6971
/**
7072
* A full sigstore keyless signing flow.
@@ -335,6 +337,12 @@ public List<Bundle> sign(List<byte[]> artifactDigests) throws KeylessSignerExcep
335337
throw new KeylessSignerException("Failed to put entry in rekor", ex);
336338
}
337339

340+
var calculatedHashedRekord =
341+
Base64.toBase64String(rekorRequest.toJsonPayload().getBytes(StandardCharsets.UTF_8));
342+
if (!Objects.equals(calculatedHashedRekord, rekorResponse.getEntry().getBody())) {
343+
throw new KeylessSignerException("Returned log entry was inconsistent with request");
344+
}
345+
338346
try {
339347
rekorVerifier.verifyEntry(rekorResponse.getEntry());
340348
} catch (RekorVerificationException ex) {

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,13 @@
2626
import dev.sigstore.encryption.signers.Verifiers;
2727
import dev.sigstore.fulcio.client.FulcioVerificationException;
2828
import dev.sigstore.fulcio.client.FulcioVerifier;
29+
import dev.sigstore.rekor.client.HashedRekordRequest;
2930
import dev.sigstore.rekor.client.RekorEntry;
3031
import dev.sigstore.rekor.client.RekorVerificationException;
3132
import dev.sigstore.rekor.client.RekorVerifier;
3233
import dev.sigstore.tuf.SigstoreTufClient;
3334
import java.io.IOException;
35+
import java.nio.charset.StandardCharsets;
3436
import java.nio.file.Path;
3537
import java.security.InvalidAlgorithmParameterException;
3638
import java.security.InvalidKeyException;
@@ -44,7 +46,9 @@
4446
import java.sql.Date;
4547
import java.util.Arrays;
4648
import java.util.List;
49+
import java.util.Objects;
4750
import java.util.stream.Collectors;
51+
import org.bouncycastle.util.encoders.Base64;
4852
import org.bouncycastle.util.encoders.Hex;
4953

5054
/** Verify hashrekords from rekor signed using the keyless signing flow with fulcio certificates. */
@@ -182,6 +186,23 @@ public void verify(byte[] artifactDigest, Bundle bundle, VerificationOptions opt
182186
throw new KeylessVerificationException("Rekor entry signature was not valid", ex);
183187
}
184188

189+
// verify the log entry is relevant to the provided verification materials
190+
try {
191+
var calculatedHashedRekord =
192+
Base64.toBase64String(
193+
HashedRekordRequest.newHashedRekordRequest(
194+
artifactDigest, Certificates.toPemBytes(leafCert), signature)
195+
.toJsonPayload()
196+
.getBytes(StandardCharsets.UTF_8));
197+
if (!Objects.equals(calculatedHashedRekord, rekorEntry.getBody())) {
198+
throw new KeylessVerificationException(
199+
"Provided verification materials are inconsistent with log entry");
200+
}
201+
} catch (IOException e) {
202+
// this should be unreachable, we know leafCert is a valid certificate at this point
203+
throw new RuntimeException("Unexpected IOException on valid leafCert", e);
204+
}
205+
185206
// check if the time of entry inclusion in the log (a stand-in for signing time) is within the
186207
// validity period for the certificate
187208
var entryTime = Date.from(rekorEntry.getIntegratedTimeInstant());

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,27 @@ public void testVerify_mismatchedSet() throws Exception {
6565
VerificationOptions.empty()));
6666
}
6767

68+
@Test
69+
public void testVerify_mismatchedArtifactHash() throws Exception {
70+
// a bundle file that uses the tlog entry from another artifact signed with the same
71+
// certificate. The Bundle is fully valid except that the artifact hash doesn't match
72+
var bundleFile =
73+
Resources.toString(
74+
Resources.getResource(
75+
"dev/sigstore/samples/bundles/bundle-with-wrong-tlog-entry.sigstore"),
76+
StandardCharsets.UTF_8);
77+
var artifact = Resources.getResource("dev/sigstore/samples/bundles/artifact.txt").getPath();
78+
79+
var verifier = KeylessVerifier.builder().sigstorePublicDefaults().build();
80+
Assertions.assertThrows(
81+
KeylessVerificationException.class,
82+
() ->
83+
verifier.verify(
84+
Path.of(artifact),
85+
Bundle.from(new StringReader(bundleFile)),
86+
VerificationOptions.empty()));
87+
}
88+
6889
@Test
6990
public void testVerify_errorsOnDSSEBundle() throws Exception {
7091
var bundleFile =
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
{
2+
"mediaType": "application/vnd.dev.sigstore.bundle.v0.3+json",
3+
"verificationMaterial": {
4+
"tlogEntries": [{
5+
"logIndex": "150603746",
6+
"logId": {
7+
"keyId": "wNI9atQGlz+VWfO6LRygH4QUfY/8W4RFwiT5i5WRgB0="
8+
},
9+
"kindVersion": {
10+
"kind": "hashedrekord",
11+
"version": "0.0.1"
12+
},
13+
"integratedTime": "1732221080",
14+
"inclusionPromise": {
15+
"signedEntryTimestamp": "MEUCIQDY5kN3WEDvMndKO5JImUGrtV5jW1cVGnEDylEKRk7ZsAIgZN1MIv+eILssoHtsqqk+b9Tda+2ZN3Lkz1Mw8GwTD9k="
16+
},
17+
"inclusionProof": {
18+
"logIndex": "28699484",
19+
"rootHash": "p+AbctDd928yM1oCzeJPou8nHME2Qyka0DMB1tOlqsI=",
20+
"treeSize": "28699488",
21+
"hashes": ["fcyRKy95RMsZh/HeRQaZK8jFhhrdqqA5iFs+wInZsaI=", "zl59JwaJVeTvAF5pCTPbaXXdXgsYidumj8TgjRvcZIA=", "4mck2Czn6tiBqOQYPlh3ATO9DaTvouT7biFAkCz4bWM=", "BipkUG/DzduS/XjrbEd3uC5odEYaC9OTJTYElA10POo=", "9yDO9YZftL6yDveO6bWY32s8D4y3+uWUKVLEPmRwbHk=", "GMMIMtm+cQ0ajPC1YWzZCJIZ517pDeYJ5+FnZinynQg=", "9henJICU+Lo3pa+Rrtnt8+5esX8hhksuDcqmaYvxLHA=", "aL2yyr/c5w5R72E6L+AagxQB/oMUftqB7fHIs625QR0=", "Fvp+S31pMTO9ts92nEBj6sYay8OFauXxYrevM73sg3U=", "tk7EpIXIblK0ktOJNY9T+WCMpW0loWy+GouFKk7me8k=", "Ky28cDNBQqCVLHhOLegW99yo/fkUTkjmWsr56fXTt+E=", "PTN8SB4uaeclDiwUlPK/FSmiK7voPpkD8GBfNeRCFnw=", "0C1qnoT2c+8KErA01/VosqRATcsPFXeswb8bk/eb/3g=", "5EVC7yaMdjhwDR6OLXLyveRuRrF8xvXTzlm+8+vzfxE=", "bulsENariUUsC4xiR1yFtqKzD8evI9p/s+YCpl8t9tE=", "E2rLOYPJFKiizYiyu07QLqkMVTVL7i2ZgXiQywdI9KQ=", "4lUF0YOu9XkIDXKXA0wMSzd6VeDY3TZAgmoOeWmS2+Y=", "gf+9m552B3PnkWnO0o4KdVvjcT3WVHLrCbf1DoVYKFw="],
22+
"checkpoint": {
23+
"envelope": "rekor.sigstore.dev - 1193050959916656506\n28699488\np+AbctDd928yM1oCzeJPou8nHME2Qyka0DMB1tOlqsI\u003d\n\n— rekor.sigstore.dev wNI9ajBFAiEA+50Xtrawp0K2slioi3f8lpCrZGu8k919PDoZ+Z80/WUCIDaUTds/GljSB8/Mu7DLj879oi/odHrPZ0OUeubKlBGd\n"
24+
}
25+
},
26+
"canonicalizedBody": "eyJhcGlWZXJzaW9uIjoiMC4wLjEiLCJraW5kIjoiaGFzaGVkcmVrb3JkIiwic3BlYyI6eyJkYXRhIjp7Imhhc2giOnsiYWxnb3JpdGhtIjoic2hhMjU2IiwidmFsdWUiOiJkNDBlYzNlZWJjYjI5OTE0OTRmMjI3MzZhM2Y1ZmE3YjJlNGI2OTcyZDdjMDQ2ZDVjNWQ3ZTUwNmFiZTlmNzUyIn19LCJzaWduYXR1cmUiOnsiY29udGVudCI6Ik1FUUNJRWhQanlEZXFCdDJyNnBkNTVTczVYdi9rTG54NXozb0hDOE42TCtWOW1MSUFpQktpQ2xLcTNPV2ttcHZUcXpyRDZ1a2RmdTQvRXhGVVVmdHoxcnMvL04ySnc9PSIsInB1YmxpY0tleSI6eyJjb250ZW50IjoiTFMwdExTMUNSVWRKVGlCRFJWSlVTVVpKUTBGVVJTMHRMUzB0Q2sxSlNVTjRla05EUVdzeVowRjNTVUpCWjBsVlJteERWeTlHUWtabFVrRmtkVU12Y1c0eGVrNTBOVWt2YlN0SmQwTm5XVWxMYjFwSmVtb3dSVUYzVFhjS1RucEZWazFDVFVkQk1WVkZRMmhOVFdNeWJHNWpNMUoyWTIxVmRWcEhWakpOVWpSM1NFRlpSRlpSVVVSRmVGWjZZVmRrZW1SSE9YbGFVekZ3WW01U2JBcGpiVEZzV2tkc2FHUkhWWGRJYUdOT1RXcFJlRTFVU1hoTmFrRjZUVlJGTlZkb1kwNU5hbEY0VFZSSmVFMXFRVEJOVkVVMVYycEJRVTFHYTNkRmQxbElDa3R2V2tsNmFqQkRRVkZaU1V0dldrbDZhakJFUVZGalJGRm5RVVZzWlhwUWFXeEtWVlZqTkV0cGJtWkVURTl0UTNobVRVNXpLMlJ4Ums5c2JYWkNZMnNLUW1aaWRHeHRXRWRpWTNKRGVtTkxNWGRuTm5SdVYzVklObmhHZUhKclJFUmxaMU5ITDBoYU1HcGpVekJMVUU0M1EyRlBRMEZYZDNkblowWnZUVUUwUndwQk1WVmtSSGRGUWk5M1VVVkJkMGxJWjBSQlZFSm5UbFpJVTFWRlJFUkJTMEpuWjNKQ1owVkdRbEZqUkVGNlFXUkNaMDVXU0ZFMFJVWm5VVlZ4TVZsQ0NteHZUbXg1VDFkU2FuUkZOREZtTVdkeU5GbEZiR2haZDBoM1dVUldVakJxUWtKbmQwWnZRVlV6T1ZCd2VqRlphMFZhWWpWeFRtcHdTMFpYYVhocE5Ga0tXa1E0ZDBoUldVUldVakJTUVZGSUwwSkNUWGRGV1VWUVdWaENkMlJWUW01aU1qbHVZa2RWZFZreU9YUk5RMnRIUTJselIwRlJVVUpuTnpoM1FWRkZSUXBITW1nd1pFaENlazlwT0haWlYwNXFZak5XZFdSSVRYVmFNamwyV2pKNGJFeHRUblppVkVGeVFtZHZja0puUlVWQldVOHZUVUZGU1VKQ01FMUhNbWd3Q21SSVFucFBhVGgyV1ZkT2FtSXpWblZrU0UxMVdqSTVkbG95ZUd4TWJVNTJZbFJEUW1sUldVdExkMWxDUWtGSVYyVlJTVVZCWjFJM1FraHJRV1IzUWpFS1FVNHdPVTFIY2tkNGVFVjVXWGhyWlVoS2JHNU9kMHRwVTJ3Mk5ETnFlWFF2TkdWTFkyOUJka3RsTms5QlFVRkNhekZDYzBWTU5FRkJRVkZFUVVWWmR3cFNRVWxuUkdkNE5tUkNNMHR2YlhoUGVVSXdaakY1SzNZMGJUYzNNWE4yY1dWMUszZHVjazFUVG14WWNHNVNXVU5KUkRkTlZVUjVRa1ZhVlhobmVUSmFDbFJWZDNnd1NUWnllR2hOTm5weU5qRXJNamc0YXpkQmVYQktMMlZOUVc5SFEwTnhSMU5OTkRsQ1FVMUVRVEpuUVUxSFZVTk5VVU16VGpaR05sUlZWVk1LYTA5bVNrSnRZMWhPV2psSFRGaEhWbFYzV2xaQ1IwWmtSSEF2VkZkT1ZrNVZTeTlyT1ZZNE1VcFFXbFF6TkRWcVVUVm5SMUEzVFVOTlJXWjNPVEZUV2dwV00zSllZVWd6VkdGRFZYZGFSM0pQY205RE5XSmFNMGRzYW1oQ05raEdSMk5OUjFSM1JXUlFObE0ySzNsNVNHOTBkbkpYVW5kSFEwOVJQVDBLTFMwdExTMUZUa1FnUTBWU1ZFbEdTVU5CVkVVdExTMHRMUW89In19fX0="
27+
}],
28+
"certificate": {
29+
"rawBytes": "MIICxzCCAk2gAwIBAgIUFlCW/FBFeRAduC/qn1zNt5I/m+IwCgYIKoZIzj0EAwMwNzEVMBMGA1UEChMMc2lnc3RvcmUuZGV2MR4wHAYDVQQDExVzaWdzdG9yZS1pbnRlcm1lZGlhdGUwHhcNMjQxMTIxMjAzMTE5WhcNMjQxMTIxMjA0MTE5WjAAMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAElezPilJUUc4KinfDLOmCxfMNs+dqFOlmvBckBfbtlmXGbcrCzcK1wg6tnWuH6xFxrkDDegSG/HZ0jcS0KPN7CaOCAWwwggFoMA4GA1UdDwEB/wQEAwIHgDATBgNVHSUEDDAKBggrBgEFBQcDAzAdBgNVHQ4EFgQUq1YBloNlyOWRjtE41f1gr4YElhYwHwYDVR0jBBgwFoAU39Ppz1YkEZb5qNjpKFWixi4YZD8wHQYDVR0RAQH/BBMwEYEPYXBwdUBnb29nbGUuY29tMCkGCisGAQQBg78wAQEEG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTArBgorBgEEAYO/MAEIBB0MG2h0dHBzOi8vYWNjb3VudHMuZ29vZ2xlLmNvbTCBiQYKKwYBBAHWeQIEAgR7BHkAdwB1AN09MGrGxxEyYxkeHJlnNwKiSl643jyt/4eKcoAvKe6OAAABk1BsEL4AAAQDAEYwRAIgDgx6dB3KomxOyB0f1y+v4m771svqeu+wnrMSNlXpnRYCID7MUDyBEZUxgy2ZTUwx0I6rxhM6zr61+288k7AypJ/eMAoGCCqGSM49BAMDA2gAMGUCMQC3N6F6TUUSkOfJBmcXNZ9GLXGVUwZVBGFdDp/TWNVNUK/k9V81JPZT345jQ5gGP7MCMEfw91SZV3rXaH3TaCUwZGrOroC5bZ3GljhB6HFGcMGTwEdP6S6+yyHotvrWRwGCOQ=="
30+
}
31+
},
32+
"messageSignature": {
33+
"messageDigest": {
34+
"algorithm": "SHA2_256",
35+
"digest": "oM/HEnHW4njlfNMy/5V8P3BD/do1TEy7GQow1W76Ab8="
36+
},
37+
"signature": "MEYCIQCGZcJ+4mTIMPAyIKV7XZjZ5KyvX1tz/glbin9vVF+9fwIhANUb5z/2Rb88vtvtABHAmQyBl4Yp8ipMLCnv36Ln8/Eb"
38+
}
39+
}

0 commit comments

Comments
 (0)