Skip to content

Commit ef3f101

Browse files
authored
Merge pull request #1202 from sigstore/dsseXhashedrekord
use hashedrekord as only type in rekor v2 paths
2 parents 5412beb + 914397a commit ef3f101

16 files changed

Lines changed: 263 additions & 244 deletions

.github/workflows/conformance.yml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ jobs:
5454
distribution: 'temurin'
5555

5656
- name: Run Conformance Tests (production)
57-
uses: sigstore/sigstore-conformance@4d66ba3cb0c9c95f705c757c0f5e226d3f4d5151 # v0.0.27
57+
uses: sigstore/sigstore-conformance@21533cde107c734ebc153c3e3a24d75fc9811a36 # v0.0.29
5858
with:
5959
entrypoint: ${{ github.workspace }}/sigstore-cli/sigstore-cli-server
6060
environment: production
@@ -66,7 +66,7 @@ jobs:
6666
test_sign_verify_dsse
6767
6868
- name: Run Conformance Tests (staging)
69-
uses: sigstore/sigstore-conformance@4d66ba3cb0c9c95f705c757c0f5e226d3f4d5151 # v0.0.27
69+
uses: sigstore/sigstore-conformance@21533cde107c734ebc153c3e3a24d75fc9811a36 # v0.0.29
7070
with:
7171
entrypoint: ${{ github.workspace }}/sigstore-cli/sigstore-cli-server
7272
environment: staging

fuzzing/src/main/java/fuzzing/RekorTypesFuzzer.java

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -50,9 +50,6 @@ public static void fuzzerTestOneInput(FuzzedDataProvider data) {
5050
case 2:
5151
RekorTypes.getHashedRekordV002(entry);
5252
break;
53-
case 3:
54-
RekorTypes.getDsseV002(entry);
55-
break;
5653
}
5754
} catch (URISyntaxException | RekorTypeException | RekorParseException e) {
5855
// Known exception

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

Lines changed: 20 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,6 @@
4545
import dev.sigstore.oidc.client.OidcTokenMatcher;
4646
import dev.sigstore.proto.ProtoMutators;
4747
import dev.sigstore.proto.common.v1.X509Certificate;
48-
import dev.sigstore.proto.rekor.v2.DSSERequestV002;
4948
import dev.sigstore.proto.rekor.v2.HashedRekordRequestV002;
5049
import dev.sigstore.proto.rekor.v2.Signature;
5150
import dev.sigstore.proto.rekor.v2.Verifier;
@@ -69,7 +68,6 @@
6968
import dev.sigstore.trustroot.Service;
7069
import dev.sigstore.trustroot.SigstoreConfigurationException;
7170
import dev.sigstore.tuf.SigstoreTufClient;
72-
import io.intoto.EnvelopeOuterClass;
7371
import java.io.IOException;
7472
import java.nio.charset.StandardCharsets;
7573
import java.nio.file.Path;
@@ -765,37 +763,38 @@ public Bundle attest(String payload) throws KeylessSignerException {
765763
.build();
766764

767765
var pae = dsse.getPAE();
766+
var paeDigest = Hashers.from(signingAlgorithm).hashBytes(pae).asBytes();
767+
byte[] signature;
768768

769-
Bundle.DsseEnvelope dsseSigned;
770769
try {
771-
var sig = signer.sign(pae);
772-
dsseSigned =
773-
ImmutableDsseEnvelope.builder()
774-
.from(dsse)
775-
.addSignatures(ImmutableSignature.builder().sig(sig).build())
776-
.build();
770+
signature = signer.signDigest(paeDigest);
777771
} catch (NoSuchAlgorithmException | SignatureException | InvalidKeyException ex) {
778772
throw new KeylessSignerException("Failed to sign artifact", ex);
779773
}
780774

775+
Bundle.DsseEnvelope dsseSigned =
776+
ImmutableDsseEnvelope.builder()
777+
.from(dsse)
778+
.addSignatures(ImmutableSignature.builder().sig(signature).build())
779+
.build();
780+
781781
var verifier =
782782
Verifier.newBuilder()
783783
.setX509Certificate(
784784
X509Certificate.newBuilder().setRawBytes(ByteString.copyFrom(encodedCert)).build())
785785
.setKeyDetails(ProtoMutators.toPublicKeyDetails(signingAlgorithm))
786786
.build();
787787

788-
var dsseRequest =
789-
DSSERequestV002.newBuilder()
790-
.setEnvelope(
791-
EnvelopeOuterClass.Envelope.newBuilder()
792-
.setPayload(ByteString.copyFrom(dsseSigned.getPayload()))
793-
.setPayloadType(dsseSigned.getPayloadType())
794-
.addSignatures(
795-
EnvelopeOuterClass.Signature.newBuilder()
796-
.setSig(ByteString.copyFrom(dsseSigned.getSignature())))
797-
.build())
798-
.addVerifiers(verifier)
788+
var reqSignature =
789+
Signature.newBuilder()
790+
.setVerifier(verifier)
791+
.setContent(ByteString.copyFrom(dsseSigned.getSignature()))
792+
.build();
793+
794+
var hashedRekordRequest =
795+
HashedRekordRequestV002.newBuilder()
796+
.setSignature(reqSignature)
797+
.setDigest(ByteString.copyFrom(paeDigest))
799798
.build();
800799

801800
var hashFunction = Hashers.from(signingAlgorithm);
@@ -827,7 +826,7 @@ public Bundle attest(String payload) throws KeylessSignerException {
827826

828827
RekorEntry entry;
829828
try {
830-
entry = rekorV2Client.putEntry(dsseRequest);
829+
entry = rekorV2Client.putEntry(hashedRekordRequest);
831830
} catch (IOException | RekorParseException ex) {
832831
throw new KeylessSignerException("Failed to put entry in rekor", ex);
833832
}

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

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -31,11 +31,11 @@
3131
import dev.sigstore.fulcio.client.FulcioVerifier;
3232
import dev.sigstore.json.JsonParseException;
3333
import dev.sigstore.proto.ProtoMutators;
34-
import dev.sigstore.proto.rekor.v2.DSSELogEntryV002;
3534
import dev.sigstore.proto.rekor.v2.HashedRekordLogEntryV002;
3635
import dev.sigstore.proto.rekor.v2.Signature;
3736
import dev.sigstore.rekor.client.HashedRekordRequest;
3837
import dev.sigstore.rekor.client.RekorEntry;
38+
import dev.sigstore.rekor.client.RekorEntryBody;
3939
import dev.sigstore.rekor.client.RekorTypeException;
4040
import dev.sigstore.rekor.client.RekorTypes;
4141
import dev.sigstore.rekor.client.RekorVerificationException;
@@ -469,13 +469,15 @@ private void checkDsseEnvelope(
469469
throw new KeylessVerificationException("Signature could not be processed", se);
470470
}
471471

472-
String version;
472+
RekorEntryBody entryBody;
473473
try {
474-
version = rekorEntry.getBodyDecoded().getApiVersion();
474+
entryBody = rekorEntry.getBodyDecoded();
475475
} catch (JsonParseException ex) {
476476
throw new KeylessVerificationException("Could not extract body from log entry");
477477
}
478-
if ("0.0.1".equals(version)) {
478+
var kind = entryBody.getKind();
479+
var version = entryBody.getApiVersion();
480+
if ("0.0.1".equals(version) && "dsse".equals(kind)) {
479481
Dsse rekorDsse;
480482
try {
481483
rekorDsse = RekorTypes.getDsseV001(rekorEntry);
@@ -517,45 +519,30 @@ private void checkDsseEnvelope(
517519
throw new KeylessVerificationException(
518520
"Provided DSSE signature materials are inconsistent with DSSE log entry");
519521
}
520-
} else if ("0.0.2".equals(version)) {
521-
DSSELogEntryV002 logEntrySpec;
522+
} else if ("0.0.2".equals(version) && "hashedrekord".equals(kind)) {
523+
HashedRekordLogEntryV002 logEntrySpec;
522524
try {
523-
logEntrySpec = RekorTypes.getDsseV002(rekorEntry);
525+
logEntrySpec = RekorTypes.getHashedRekordV002(rekorEntry);
524526
} catch (RekorTypeException re) {
525527
throw new KeylessVerificationException("Could not parse DSSE from log entry body", re);
526528
}
527529

528-
try {
529-
ProtoMutators.toHashAlgorithm(logEntrySpec.getPayloadHash().getAlgorithm());
530-
} catch (UnsupportedAlgorithmException ex) {
531-
throw new KeylessVerificationException("Unsupported digest algorithm in log entry", ex);
532-
}
533-
534-
// check if the digest over the dsse payload matches the digest in the transparency log entry
535-
byte[] calculatedDigest = hashing.hashBytes(dsseEnvelope.getPayload()).asBytes();
536-
if (!Arrays.equals(
537-
logEntrySpec.getPayloadHash().getDigest().toByteArray(), calculatedDigest)) {
538-
throw new KeylessVerificationException(
539-
"Digest of DSSE payload in bundle does not match DSSE payload digest in log entry");
540-
}
541-
542-
// check if the signature over the dsse payload matches the signature in the rekorEntry
543-
if (logEntrySpec.getSignaturesCount() != 1) {
530+
// check if the digest over the dsse pae matches the digest in the transparency log entry
531+
byte[] calculatedDigest = hashing.hashBytes(dsseEnvelope.getPAE()).asBytes();
532+
if (!Arrays.equals(logEntrySpec.getData().getDigest().toByteArray(), calculatedDigest)) {
544533
throw new KeylessVerificationException(
545-
"Log entry spec must have exactly 1 signature, but found: "
546-
+ logEntrySpec.getSignaturesCount());
534+
"Digest of DSSE.pae in bundle does not match digest in log entry");
547535
}
548536

549-
Signature logSignature = logEntrySpec.getSignatures(0);
537+
Signature logSignature = logEntrySpec.getSignature();
550538
if (!Arrays.equals(dsseEnvelope.getSignature(), logSignature.getContent().toByteArray())) {
551539
throw new KeylessVerificationException(
552-
"Signature in DSSE envelope does not match signature in log entry spec");
540+
"Signature in DSSE envelope does not match signature in log entry");
553541
}
554542

555543
var verifier = logSignature.getVerifier();
556544
if (!verifier.hasX509Certificate()) {
557-
throw new KeylessVerificationException(
558-
"Rekor entry DSSE verifier is missing X.509 certificate");
545+
throw new KeylessVerificationException("Log entry is missing X.509 certificate");
559546
}
560547
try {
561548
byte[] certFromRekor = verifier.getX509Certificate().getRawBytes().toByteArray();
@@ -569,7 +556,8 @@ private void checkDsseEnvelope(
569556
"Could not encode leaf certificate for comparison", e);
570557
}
571558
} else {
572-
throw new KeylessVerificationException("Unsupported DSSE version: " + version);
559+
throw new KeylessVerificationException(
560+
"Unsupported entry type: '" + kind + ":" + version + "' for DSSE bundle");
573561
}
574562
}
575563
}

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

Lines changed: 0 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import com.google.protobuf.InvalidProtocolBufferException;
2121
import dev.sigstore.json.JsonParseException;
2222
import dev.sigstore.json.ProtoJson;
23-
import dev.sigstore.proto.rekor.v2.DSSELogEntryV002;
2423
import dev.sigstore.proto.rekor.v2.HashedRekordLogEntryV002;
2524
import dev.sigstore.rekor.dsse.v0_0_1.Dsse;
2625
import dev.sigstore.rekor.hashedRekord.v0_0_1.HashedRekord;
@@ -91,32 +90,6 @@ public static Dsse getDsseV001(RekorEntry entry) throws RekorTypeException {
9190
}
9291
}
9392

94-
/**
95-
* Parse a dsse from rekor at api version 0.0.2.
96-
*
97-
* @param entry the rekor entry obtained from rekor
98-
* @return the parsed proto
99-
* @throws RekorTypeException if the dsse:0.0.2 entry could not be parsed
100-
*/
101-
public static DSSELogEntryV002 getDsseV002(RekorEntry entry) throws RekorTypeException {
102-
expect(entry, "dsse", "0.0.2");
103-
104-
try {
105-
DSSELogEntryV002.Builder builder = DSSELogEntryV002.newBuilder();
106-
ProtoJson.parser()
107-
.ignoringUnknownFields()
108-
.merge(
109-
GSON.get().toJson(entry.getBodyDecoded().getSpec().getAsJsonObject().get("dsseV002")),
110-
builder);
111-
return builder.build();
112-
} catch (InvalidProtocolBufferException
113-
| JsonParseException
114-
| NullPointerException
115-
| IllegalStateException e) {
116-
throw new RekorTypeException("Could not parse dsse:0.0.2", e);
117-
}
118-
}
119-
12093
private static void expect(RekorEntry entry, String expectedKind, String expectedApiVersion)
12194
throws RekorTypeException {
12295
try {

sigstore-java/src/main/java/dev/sigstore/rekor/v2/client/RekorV2Client.java

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@
1515
*/
1616
package dev.sigstore.rekor.v2.client;
1717

18-
import dev.sigstore.proto.rekor.v2.DSSERequestV002;
1918
import dev.sigstore.proto.rekor.v2.HashedRekordRequestV002;
2019
import dev.sigstore.rekor.client.RekorEntry;
2120
import dev.sigstore.rekor.client.RekorParseException;
@@ -31,12 +30,4 @@ public interface RekorV2Client {
3130
*/
3231
RekorEntry putEntry(HashedRekordRequestV002 hashedRekordRequest)
3332
throws IOException, RekorParseException;
34-
35-
/**
36-
* Put a new dsse entry on the Rekor log.
37-
*
38-
* @param dsseRequest the request to send to rekor
39-
* @return a {@link RekorEntry} with information about the log entry
40-
*/
41-
RekorEntry putEntry(DSSERequestV002 dsseRequest) throws IOException, RekorParseException;
4233
}

sigstore-java/src/main/java/dev/sigstore/rekor/v2/client/RekorV2ClientHttp.java

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import dev.sigstore.http.ImmutableHttpParams;
2727
import dev.sigstore.http.URIFormat;
2828
import dev.sigstore.proto.rekor.v2.CreateEntryRequest;
29-
import dev.sigstore.proto.rekor.v2.DSSERequestV002;
3029
import dev.sigstore.proto.rekor.v2.HashedRekordRequestV002;
3130
import dev.sigstore.rekor.client.RekorEntry;
3231
import dev.sigstore.rekor.client.RekorParseException;
@@ -83,11 +82,6 @@ public RekorEntry putEntry(HashedRekordRequestV002 hashedRekordRequest)
8382
CreateEntryRequest.newBuilder().setHashedRekordRequestV002(hashedRekordRequest).build());
8483
}
8584

86-
@Override
87-
public RekorEntry putEntry(DSSERequestV002 dsseRequest) throws IOException, RekorParseException {
88-
return putEntry(CreateEntryRequest.newBuilder().setDsseRequestV002(dsseRequest).build());
89-
}
90-
9185
private RekorEntry putEntry(CreateEntryRequest request) throws IOException, RekorParseException {
9286
URI rekorPutEndpoint = URIFormat.appendPath(uri, REKOR_ENTRIES_PATH);
9387

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,6 +161,7 @@ public void attest_production() throws Exception {
161161
Assertions.assertNotNull(result.getDsseEnvelope().get());
162162
Assertions.assertEquals(payload, result.getDsseEnvelope().get().getPayloadAsString());
163163
Assertions.assertEquals(1, result.getEntries().size());
164+
Assertions.assertEquals("hashedrekord", result.getEntries().get(0).getBodyDecoded().getKind());
164165
Assertions.assertEquals("0.0.2", result.getEntries().get(0).getBodyDecoded().getApiVersion());
165166

166167
var verifier = KeylessVerifier.builder().sigstorePublicDefaults().build();
@@ -190,7 +191,7 @@ public void attest_staging() throws Exception {
190191
}
191192

192193
private void verifySigningResult(List<Bundle> results, boolean enableRekorV2)
193-
throws IOException, JsonParseException {
194+
throws JsonParseException {
194195

195196
Assertions.assertEquals(artifactDigests.size(), results.size());
196197

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

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -444,16 +444,19 @@ static Stream<Arguments> badDsseProvider() {
444444
Arguments.arguments(
445445
"bundle.dsse.rekor-v2.bad-signature.sigstore", "DSSE signature was not valid"),
446446
Arguments.arguments(
447-
"bundle.dsse.rekor-v2.mismatched-payload.sigstore",
448-
"Digest of DSSE payload in bundle does not match DSSE payload digest in log entry"),
447+
"bundle.dsse.rekor-v2.mismatched-envelope.sigstore",
448+
"Digest of DSSE.pae in bundle does not match digest in log entry"),
449449
Arguments.arguments(
450450
"bundle.dsse.rekor-v2.mismatched-signature.sigstore",
451-
"Signature in DSSE envelope does not match signature in log entry spec"));
451+
"Signature in DSSE envelope does not match signature in log entry"),
452+
Arguments.arguments(
453+
"bundle.dsse.rekor-v2.bad-entry-type.sigstore",
454+
"Unsupported entry type: 'dsse:0.0.2' for DSSE bundle"));
452455
}
453456

454457
@ParameterizedTest
455458
@MethodSource("badDsseProvider")
456-
public void testVerify_dsseBundleInvalid(String bundleName, String expectedError)
459+
public void testVerify_dsseBundleInvalid_rekor(String bundleName, String expectedError)
457460
throws Exception {
458461
var bundleFile =
459462
Resources.toString(
@@ -708,7 +711,7 @@ public void testVerify_dsseBundle_rekorV2() throws Exception {
708711
Resources.getResource("dev/sigstore/samples/bundles/bundle.dsse.rekor-v2.sigstore"),
709712
StandardCharsets.UTF_8);
710713

711-
var verifier = KeylessVerifier.builder().sigstoreStagingDefaults().build();
714+
var verifier = KeylessVerifier.builder().sigstorePublicDefaults().build();
712715
verifier.verify(
713716
Path.of(artifact), Bundle.from(new StringReader(bundleFile)), VerificationOptions.empty());
714717
}
@@ -721,7 +724,7 @@ public void testVerify_dsseBundleArtifactNotInSubjects_rekorV2() throws Exceptio
721724
StandardCharsets.UTF_8);
722725
var badArtifactDigest =
723726
Hashing.sha256().hashString("nonsense", StandardCharsets.UTF_8).asBytes();
724-
var verifier = KeylessVerifier.builder().sigstoreStagingDefaults().build();
727+
var verifier = KeylessVerifier.builder().sigstorePublicDefaults().build();
725728

726729
var ex =
727730
Assertions.assertThrows(

0 commit comments

Comments
 (0)