Skip to content

Commit 40c04c2

Browse files
committed
Inclusion proof is required
This makes inclusion proof on entry.verification not optional. Verification of an entry implies the inclusion proof will also be verified. Rework the code a bit to reflect this and update tests. Signed-off-by: Appu Goundan <[email protected]>
1 parent eefa7a2 commit 40c04c2

File tree

16 files changed

+38
-72
lines changed

16 files changed

+38
-72
lines changed

fuzzing/src/main/java/fuzzing/RekorVerifierFuzzer.java

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,6 @@ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
4040
RekorVerifier verifier = RekorVerifier.newRekorVerifier(tLogs);
4141

4242
verifier.verifyEntry(entry);
43-
verifier.verifyInclusionProof(entry);
4443
} catch (URISyntaxException | RekorParseException | RekorVerificationException e) {
4544
// Known exception
4645
}

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

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -180,17 +180,6 @@ public void verify(byte[] artifactDigest, KeylessVerificationRequest request)
180180
throw new KeylessVerificationException("Rekor entry signature was not valid");
181181
}
182182

183-
// verify any inclusion proof
184-
if (rekorEntry.getVerification().getInclusionProof().isPresent()) {
185-
try {
186-
rekorVerifier.verifyInclusionProof(rekorEntry);
187-
} catch (RekorVerificationException ex) {
188-
throw new KeylessVerificationException("Rekor entry inclusion proof was not valid");
189-
}
190-
} else if (request.getVerificationOptions().alwaysUseRemoteRekorEntry()) {
191-
throw new KeylessVerificationException("Rekor entry did not contain inclusion proof");
192-
}
193-
194183
// check if the time of entry inclusion in the log (a stand-in for signing time) is within the
195184
// validity period for the certificate
196185
var entryTime = Date.from(rekorEntry.getIntegratedTimeInstant());

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

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@
4343
import java.security.cert.CertificateException;
4444
import java.util.Base64;
4545
import java.util.List;
46-
import java.util.Optional;
4746
import java.util.stream.Collectors;
4847
import org.bouncycastle.util.encoders.Hex;
4948

@@ -127,14 +126,7 @@ private static TransparencyLogEntry.Builder buildTlogEntries(RekorEntry entry) {
127126

128127
private static void addInclusionProof(
129128
TransparencyLogEntry.Builder transparencyLogEntry, RekorEntry entry) {
130-
RekorEntry.InclusionProof inclusionProof =
131-
entry
132-
.getVerification()
133-
.getInclusionProof()
134-
.orElseThrow(
135-
() ->
136-
new IllegalArgumentException(
137-
"An inclusion proof must be present in the log entry in the signing result"));
129+
RekorEntry.InclusionProof inclusionProof = entry.getVerification().getInclusionProof();
138130
transparencyLogEntry.setInclusionProof(
139131
InclusionProof.newBuilder()
140132
.setLogIndex(inclusionProof.getLogIndex())
@@ -166,9 +158,8 @@ static KeylessSignature readBundle(Reader jsonReader) throws BundleParseExceptio
166158
var bundleEntry = bundle.getVerificationMaterial().getTlogEntries(0);
167159
RekorEntry.InclusionProof inclusionProof = null;
168160
if (!bundleEntry.hasInclusionProof()) {
169-
if (!bundle.getMediaType().equals(BUNDLE_V_0_1)) {
170-
throw new BundleParseException("Could not find an inclusion proof");
171-
}
161+
// all consumed bundles must have an inclusion proof
162+
throw new BundleParseException("Could not find an inclusion proof");
172163
} else {
173164
var bundleInclusionProof = bundleEntry.getInclusionProof();
174165

@@ -192,7 +183,7 @@ static KeylessSignature readBundle(Reader jsonReader) throws BundleParseExceptio
192183
Base64.getEncoder()
193184
.encodeToString(
194185
bundleEntry.getInclusionPromise().getSignedEntryTimestamp().toByteArray()))
195-
.inclusionProof(Optional.ofNullable(inclusionProof))
186+
.inclusionProof(inclusionProof)
196187
.build();
197188

198189
var rekorEntry =

sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorEntry.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,8 @@ interface Verification {
3737
/** Return the signed entry timestamp. */
3838
String getSignedEntryTimestamp();
3939

40-
Optional<InclusionProof> getInclusionProof();
40+
/** Return the inclusion proof. */
41+
InclusionProof getInclusionProof();
4142
}
4243

4344
/**

sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorVerifier.java

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -81,24 +81,15 @@ public void verifyEntry(RekorEntry entry) throws RekorVerificationException {
8181
} catch (NoSuchAlgorithmException nsae) {
8282
throw new AssertionError("Required verification algorithm 'SHA256withECDSA' not found.");
8383
}
84+
85+
// verify inclusion proof
86+
verifyInclusionProof(entry);
8487
}
8588

86-
/**
87-
* Verify that a Rekor Entry is in the log by checking inclusion proof.
88-
*
89-
* @param entry the entry to verify
90-
* @throws RekorVerificationException if the entry cannot be verified
91-
*/
92-
public void verifyInclusionProof(RekorEntry entry) throws RekorVerificationException {
89+
/** Verify that a Rekor Entry is in the log by checking inclusion proof. */
90+
private void verifyInclusionProof(RekorEntry entry) throws RekorVerificationException {
9391

94-
var inclusionProof =
95-
entry
96-
.getVerification()
97-
.getInclusionProof()
98-
.orElseThrow(
99-
() ->
100-
new RekorVerificationException(
101-
"No inclusion proof was found in the rekor entry"));
92+
var inclusionProof = entry.getVerification().getInclusionProof();
10293

10394
var leafHash =
10495
Hashing.sha256()

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,7 @@ public void testVerify_mismatchedSet() throws Exception {
6969

7070
@Test
7171
public void testVerify_canVerifyV01Bundle() throws Exception {
72+
// note that this v1 bundle contains an inclusion proof
7273
verifyBundle(
7374
"dev/sigstore/samples/bundles/artifact.txt",
7475
"dev/sigstore/samples/bundles/bundle.v1.sigstore");

sigstore-java/src/test/java/dev/sigstore/bundle/BundleFactoryTest.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,15 @@ public void readV1Bundle() throws Exception {
2929
readBundle("dev/sigstore/samples/bundles/bundle.v1.sigstore");
3030
}
3131

32+
@Test
33+
public void readV1Bundle_noInclusion() {
34+
var ex =
35+
Assertions.assertThrows(
36+
BundleParseException.class,
37+
() -> readBundle("dev/sigstore/samples/bundles/bundle.v1.no.inclusion.sigstore"));
38+
Assertions.assertEquals("Could not find an inclusion proof", ex.getMessage());
39+
}
40+
3241
@Test
3342
public void readV2Bundle() throws Exception {
3443
readBundle("dev/sigstore/samples/bundles/bundle.v2.sigstore");

sigstore-java/src/test/java/dev/sigstore/rekor/client/RekorClientTest.java

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -170,11 +170,10 @@ public void getEntry_hashedRekordRequest_byCalculatedUuid() throws Exception {
170170
private void assertEntry(RekorResponse resp, Optional<RekorEntry> entry) {
171171
assertTrue(entry.isPresent());
172172
assertEquals(resp.getEntry().getLogID(), entry.get().getLogID());
173-
assertTrue(entry.get().getVerification().getInclusionProof().isPresent());
174-
assertNotNull(entry.get().getVerification().getInclusionProof().get().getTreeSize());
175-
assertNotNull(entry.get().getVerification().getInclusionProof().get().getRootHash());
176-
assertNotNull(entry.get().getVerification().getInclusionProof().get().getLogIndex());
177-
assertTrue(entry.get().getVerification().getInclusionProof().get().getHashes().size() > 0);
173+
assertNotNull(entry.get().getVerification().getInclusionProof().getTreeSize());
174+
assertNotNull(entry.get().getVerification().getInclusionProof().getRootHash());
175+
assertNotNull(entry.get().getVerification().getInclusionProof().getLogIndex());
176+
assertTrue(entry.get().getVerification().getInclusionProof().getHashes().size() > 0);
178177
}
179178

180179
@Test

sigstore-java/src/test/java/dev/sigstore/rekor/client/RekorTypesTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,15 +32,15 @@ private RekorEntry fromResource(String path) throws Exception {
3232

3333
@Test
3434
public void getHashedRekord_pass() throws Exception {
35-
var entry = fromResource("dev/sigstore/samples/rekor-response/valid/response.json");
35+
var entry = fromResource("dev/sigstore/samples/rekor-response/valid/entry.json");
3636

3737
var hashedRekord = RekorTypes.getHashedRekord(entry);
3838
Assertions.assertNotNull(hashedRekord);
3939
}
4040

4141
@Test
4242
public void getHashedRekord_badType() throws Exception {
43-
var entry = fromResource("dev/sigstore/samples/rekor-response/valid/jar-response.json");
43+
var entry = fromResource("dev/sigstore/samples/rekor-response/valid/jar-entry.json");
4444

4545
var exception =
4646
Assertions.assertThrows(RekorTypeException.class, () -> RekorTypes.getHashedRekord(entry));

sigstore-java/src/test/java/dev/sigstore/rekor/client/RekorVerifierTest.java

Lines changed: 7 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@
4141

4242
public class RekorVerifierTest {
4343
public String rekorResponse;
44-
public String rekorQueryResponse;
4544
public byte[] rekorPub;
4645

4746
public static SigstoreTrustedRoot trustRoot;
@@ -50,15 +49,11 @@ public class RekorVerifierTest {
5049
public void loadResources() throws IOException {
5150
rekorResponse =
5251
Resources.toString(
53-
Resources.getResource("dev/sigstore/samples/rekor-response/valid/response.json"),
52+
Resources.getResource("dev/sigstore/samples/rekor-response/valid/entry.json"),
5453
StandardCharsets.UTF_8);
5554
rekorPub =
5655
Resources.toByteArray(
5756
Resources.getResource("dev/sigstore/samples/rekor-response/valid/rekor.pub"));
58-
rekorQueryResponse =
59-
Resources.toString(
60-
Resources.getResource("dev/sigstore/samples/rekor-response/valid/query-response.json"),
61-
StandardCharsets.UTF_8);
6257
}
6358

6459
@BeforeAll
@@ -73,18 +68,10 @@ public static void initTrustRoot() throws IOException, CertificateException {
7368
trustRoot = SigstoreTrustedRoot.from(builder.build());
7469
}
7570

76-
@Test
77-
public void verifyEntry_valid() throws Exception {
78-
var response = RekorResponse.newRekorResponse(new URI("https://somewhere"), rekorResponse);
79-
var verifier = RekorVerifier.newRekorVerifier(trustRoot);
80-
81-
verifier.verifyEntry(response.getEntry());
82-
}
83-
8471
@Test
8572
public void verifyEntry_invalid() throws Exception {
8673
// change the logindex
87-
var invalidResponse = rekorResponse.replace("79", "80");
74+
var invalidResponse = rekorResponse.replace("1688", "1700");
8875
var response = RekorResponse.newRekorResponse(new URI("https://somewhere"), invalidResponse);
8976
var verifier = RekorVerifier.newRekorVerifier(trustRoot);
9077

@@ -95,29 +82,27 @@ public void verifyEntry_invalid() throws Exception {
9582
}
9683

9784
@Test
98-
public void verifyEntry_withInclusionProof() throws Exception {
99-
var response = RekorResponse.newRekorResponse(new URI("https://somewhere"), rekorQueryResponse);
85+
public void verifyEntry() throws Exception {
86+
var response = RekorResponse.newRekorResponse(new URI("https://somewhere"), rekorResponse);
10087
var verifier = RekorVerifier.newRekorVerifier(trustRoot);
10188

10289
var entry = response.getEntry();
10390
verifier.verifyEntry(entry);
104-
verifier.verifyInclusionProof(entry);
10591
}
10692

10793
@Test
10894
public void verifyEntry_withInvalidInclusionProof() throws Exception {
10995
// replace a hash in the inclusion proof to make it bad
110-
var invalidResponse = rekorQueryResponse.replace("b4439e", "aaaaaa");
96+
var invalidResponse = rekorResponse.replace("b4439e", "aaaaaa");
11197

11298
var response = RekorResponse.newRekorResponse(new URI("https://somewhere"), invalidResponse);
11399
var verifier = RekorVerifier.newRekorVerifier(trustRoot);
114100

115101
var entry = response.getEntry();
116-
verifier.verifyEntry(entry);
117-
118102
var thrown =
119103
Assertions.assertThrows(
120-
RekorVerificationException.class, () -> verifier.verifyInclusionProof(entry));
104+
RekorVerificationException.class, () -> verifier.verifyEntry(entry));
105+
121106
MatcherAssert.assertThat(
122107
thrown.getMessage(),
123108
CoreMatchers.startsWith(

0 commit comments

Comments
 (0)