Skip to content

Commit 1eb33e1

Browse files
committed
update to conformance 0.8.0 and rework online mode
If no entry is provided during verification, one will always be requested from remote rekor If an entry is provided, one will only be requested from rekor if explicitly instructed to do so. And if a remote entry is requested, the provided entry is completely ignored. Signed-off-by: Appu Goundan <[email protected]>
1 parent 93681d9 commit 1eb33e1

File tree

7 files changed

+26
-87
lines changed

7 files changed

+26
-87
lines changed

.github/workflows/conformance.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,6 @@ jobs:
3131
- name: Unpack sigstore-java distribution
3232
run: tar -xvf ${{ github.workspace }}/sigstore-cli/build/distributions/sigstore-cli-*.tar --strip-components 1
3333

34-
- uses: sigstore/sigstore-conformance@1abc82cdefe80bd907855d8447f903ba8b4918e0 # v0.0.6
34+
- uses: sigstore/sigstore-conformance@00922385de455be5ec46288a947044aa44fb0981 # v0.0.8
3535
with:
3636
entrypoint: ${{ github.workspace }}/bin/sigstore-cli

sigstore-cli/src/main/java/dev/sigstore/cli/Sign.java

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,10 @@
2828
import picocli.CommandLine.Option;
2929
import picocli.CommandLine.Parameters;
3030

31-
@Command(name = "sign", description = "sign an artifacts")
31+
@Command(
32+
name = "sign",
33+
aliases = {"sign-bundle"},
34+
description = "sign an artifacts")
3235
public class Sign implements Callable<Integer> {
3336

3437
@Parameters(arity = "1", paramLabel = "<artifact>", description = "artifact to sign")

sigstore-cli/src/main/java/dev/sigstore/cli/Verify.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public Integer call() throws Exception {
8989
.subjectAlternativeName(policy.certificateSan)
9090
.build());
9191
}
92-
var verificationOptions = verificationOptionsBuilder.isOnline(true).build();
92+
var verificationOptions = verificationOptionsBuilder.alwaysUseRemoteRekorEntry(false).build();
9393

9494
var verifier = new KeylessVerifier.Builder().sigstorePublicDefaults().build();
9595
verifier.verify(

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

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,12 +26,18 @@ public interface KeylessVerificationRequest {
2626

2727
@Default
2828
default VerificationOptions getVerificationOptions() {
29-
return VerificationOptions.builder().isOnline(true).build();
29+
return VerificationOptions.builder().alwaysUseRemoteRekorEntry(false).build();
3030
}
3131

3232
@Immutable
3333
interface VerificationOptions {
34-
boolean isOnline();
34+
35+
/**
36+
* Connect to rekor to obtain a rekor entry for verification. This will ignore the provided
37+
* rekor entry in a {@link KeylessSignature}. Verifier may still connect to Rekor to obtain an
38+
* entry if no {@link KeylessSignature#getEntry()} is empty.
39+
*/
40+
boolean alwaysUseRemoteRekorEntry();
3541

3642
List<CertificateIdentity> getCertificateIdentities();
3743

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

Lines changed: 5 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
import com.google.api.client.util.Preconditions;
1919
import com.google.common.hash.Hashing;
2020
import com.google.common.io.Files;
21-
import dev.sigstore.KeylessVerificationRequest.VerificationOptions;
2221
import dev.sigstore.encryption.certificates.Certificates;
2322
import dev.sigstore.encryption.signers.Verifiers;
2423
import dev.sigstore.fulcio.client.FulcioCertificateVerifier;
@@ -90,35 +89,6 @@ public Builder sigstoreStagingDefaults() throws IOException {
9089
}
9190
}
9291

93-
/**
94-
* Verify that the inputs can attest to the validity of a signature using sigstore's keyless
95-
* infrastructure. If no exception is thrown, it should be assumed verification has passed.
96-
*
97-
* @param artifactDigest the sha256 digest of the artifact that was signed
98-
* @param certChain the certificate chain obtained from a fulcio instance
99-
* @param signature the signature on the artifact
100-
* @throws KeylessVerificationException if the signing information could not be verified
101-
*/
102-
@Deprecated
103-
public void verifyOnline(byte[] artifactDigest, byte[] certChain, byte[] signature)
104-
throws KeylessVerificationException {
105-
try {
106-
verify(
107-
artifactDigest,
108-
KeylessVerificationRequest.builder()
109-
.keylessSignature(
110-
KeylessSignature.builder()
111-
.signature(signature)
112-
.certPath(Certificates.fromPemChain(certChain))
113-
.digest(artifactDigest)
114-
.build())
115-
.verificationOptions(VerificationOptions.builder().isOnline(true).build())
116-
.build());
117-
} catch (CertificateException ex) {
118-
throw new KeylessVerificationException("Certificate was not valid: " + ex.getMessage(), ex);
119-
}
120-
}
121-
12292
/** Convenience wrapper around {@link #verify(byte[], KeylessVerificationRequest)}. */
12393
public void verify(Path artifact, KeylessVerificationRequest request)
12494
throws KeylessVerificationException {
@@ -181,34 +151,11 @@ public void verify(byte[] artifactDigest, KeylessVerificationRequest request)
181151

182152
var signature = request.getKeylessSignature().getSignature();
183153

184-
// Logic is a bit convoluted for obtaining rekor entry for further processing
185-
// 1. if we're in "online mode":
186-
// a. grab the entry from rekor remote to use for verification
187-
// b. if an entry was also provided directly to this library, verify it is valid and the
188-
// same signable content as the one we obtained from rekor. SETs will be different
189-
// because rekor can generate those using a non-idempotent signer, but all signatures
190-
// should still be valid
191-
// 2. if we're in offline mode, ensure an entry was provided
192-
193154
RekorEntry rekorEntry;
194-
195-
if (request.getVerificationOptions().isOnline()) {
155+
if (request.getVerificationOptions().alwaysUseRemoteRekorEntry()
156+
|| request.getKeylessSignature().getEntry().isEmpty()) {
157+
// this setting means we ignore any provided entry
196158
rekorEntry = getEntryFromRekor(artifactDigest, leafCert, signature);
197-
if (request.getKeylessSignature().getEntry().isPresent()) {
198-
var provided = request.getKeylessSignature().getEntry().get();
199-
if (!Arrays.equals(
200-
rekorEntry.getSignableContent(),
201-
request.getKeylessSignature().getEntry().get().getSignableContent())) {
202-
throw new KeylessVerificationException(
203-
"Entry obtained from rekor does not match provided entry");
204-
}
205-
// verify the provided rekor entry is valid even if we are in online mode
206-
try {
207-
rekorVerifier.verifyEntry(provided);
208-
} catch (RekorVerificationException ex) {
209-
throw new KeylessVerificationException("Rekor entry signature was not valid");
210-
}
211-
}
212159
} else {
213160
rekorEntry =
214161
request
@@ -234,8 +181,8 @@ public void verify(byte[] artifactDigest, KeylessVerificationRequest request)
234181
} catch (RekorVerificationException ex) {
235182
throw new KeylessVerificationException("Rekor entry inclusion proof was not valid");
236183
}
237-
} else if (request.getVerificationOptions().isOnline()) {
238-
throw new KeylessVerificationException("Fetched rekor entry did not contain inclusion proof");
184+
} else if (request.getVerificationOptions().alwaysUseRemoteRekorEntry()) {
185+
throw new KeylessVerificationException("Rekor entry did not contain inclusion proof");
239186
}
240187

241188
// check if the time of entry inclusion in the log (a stand-in for signing time) is within the

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

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,6 @@ public void sign_production() throws Exception {
6767
verifySigningResult(results);
6868

6969
var verifier = KeylessVerifier.builder().sigstorePublicDefaults().build();
70-
7170
for (int i = 0; i < results.size(); i++) {
7271
verifier.verify(
7372
artifactDigests.get(i),

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

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -22,29 +22,12 @@
2222
import java.nio.charset.StandardCharsets;
2323
import java.nio.file.Path;
2424
import org.junit.jupiter.api.Assertions;
25+
import org.junit.jupiter.api.Test;
2526
import org.junit.jupiter.params.ParameterizedTest;
2627
import org.junit.jupiter.params.provider.ValueSource;
2728

2829
public class KeylessVerifierTest {
2930

30-
@ParameterizedTest
31-
@ValueSource(booleans = {true, false})
32-
public void testVerify(boolean isOnline) throws Exception {
33-
var bundleFile =
34-
Resources.toString(
35-
Resources.getResource("dev/sigstore/samples/bundles/bundle.sigstore"),
36-
StandardCharsets.UTF_8);
37-
var artifact = Resources.getResource("dev/sigstore/samples/bundles/artifact.txt").getPath();
38-
39-
var verifier = KeylessVerifier.builder().sigstorePublicDefaults().build();
40-
var verificationReq =
41-
KeylessVerificationRequest.builder()
42-
.keylessSignature(BundleFactory.readBundle(new StringReader(bundleFile)))
43-
.verificationOptions(VerificationOptions.builder().isOnline(isOnline).build())
44-
.build();
45-
verifier.verify(Path.of(artifact), verificationReq);
46-
}
47-
4831
@ParameterizedTest
4932
@ValueSource(booleans = {true, false})
5033
public void testVerify_noDigestInBundle(boolean isOnline) throws Exception {
@@ -58,14 +41,14 @@ public void testVerify_noDigestInBundle(boolean isOnline) throws Exception {
5841
var verificationReq =
5942
KeylessVerificationRequest.builder()
6043
.keylessSignature(BundleFactory.readBundle(new StringReader(bundleFile)))
61-
.verificationOptions(VerificationOptions.builder().isOnline(isOnline).build())
44+
.verificationOptions(
45+
VerificationOptions.builder().alwaysUseRemoteRekorEntry(isOnline).build())
6246
.build();
6347
verifier.verify(Path.of(artifact), verificationReq);
6448
}
6549

66-
@ParameterizedTest
67-
@ValueSource(booleans = {true, false})
68-
public void testVerify_mismatchedSet(boolean isOnline) throws Exception {
50+
@Test
51+
public void testVerify_mismatchedSet() throws Exception {
6952
// a bundle file where the SET is replaced with a valid SET for another artifact
7053
var bundleFile =
7154
Resources.toString(
@@ -78,7 +61,8 @@ public void testVerify_mismatchedSet(boolean isOnline) throws Exception {
7861
var verificationReq =
7962
KeylessVerificationRequest.builder()
8063
.keylessSignature(BundleFactory.readBundle(new StringReader(bundleFile)))
81-
.verificationOptions(VerificationOptions.builder().isOnline(isOnline).build())
64+
.verificationOptions(
65+
VerificationOptions.builder().alwaysUseRemoteRekorEntry(false).build())
8266
.build();
8367
Assertions.assertThrows(
8468
KeylessVerificationException.class,

0 commit comments

Comments
 (0)