diff --git a/fuzzing/src/main/java/fuzzing/RekorTypesFuzzer.java b/fuzzing/src/main/java/fuzzing/RekorTypesFuzzer.java index 0299fac5..17fcfb9f 100644 --- a/fuzzing/src/main/java/fuzzing/RekorTypesFuzzer.java +++ b/fuzzing/src/main/java/fuzzing/RekorTypesFuzzer.java @@ -29,12 +29,17 @@ public class RekorTypesFuzzer { public static void fuzzerTestOneInput(FuzzedDataProvider data) { try { + int type = data.pickValue(new int[] {0, 1}); String string = data.consumeRemainingAsString(); URI uri = new URI(URL); RekorEntry entry = RekorResponse.newRekorResponse(uri, string).getEntry(); - RekorTypes.getHashedRekord(entry); + if (type == 0) { + RekorTypes.getHashedRekord(entry); + } else { + RekorTypes.getDsse(entry); + } } catch (URISyntaxException | RekorTypeException | RekorParseException e) { // Known exception } diff --git a/sigstore-java/src/main/java/dev/sigstore/rekor/client/HashedRekordRequest.java b/sigstore-java/src/main/java/dev/sigstore/rekor/client/HashedRekordRequest.java index 3b982513..a00021f2 100644 --- a/sigstore-java/src/main/java/dev/sigstore/rekor/client/HashedRekordRequest.java +++ b/sigstore-java/src/main/java/dev/sigstore/rekor/client/HashedRekordRequest.java @@ -19,7 +19,7 @@ import com.google.common.hash.Hashing; import com.google.common.primitives.Bytes; -import dev.sigstore.rekor.*; +import dev.sigstore.rekor.hashedRekord.v0_0_1.*; import java.io.IOException; import java.nio.charset.StandardCharsets; import java.util.Base64; diff --git a/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorTypeException.java b/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorTypeException.java index 8b28a67c..fc85dd07 100644 --- a/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorTypeException.java +++ b/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorTypeException.java @@ -19,4 +19,8 @@ public class RekorTypeException extends Exception { public RekorTypeException(String message) { super(message); } + + public RekorTypeException(String message, Throwable reason) { + super(message, reason); + } } diff --git a/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorTypes.java b/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorTypes.java index c82a938b..0f3d650e 100644 --- a/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorTypes.java +++ b/sigstore-java/src/main/java/dev/sigstore/rekor/client/RekorTypes.java @@ -17,7 +17,9 @@ import static dev.sigstore.json.GsonSupplier.GSON; -import dev.sigstore.rekor.HashedRekord; +import com.google.gson.JsonParseException; +import dev.sigstore.rekor.dsse.v0_0_1.Dsse; +import dev.sigstore.rekor.hashedRekord.v0_0_1.HashedRekord; /** Parser for the body.spec element of {@link RekorEntry}. */ public class RekorTypes { @@ -27,12 +29,33 @@ public class RekorTypes { * * @param entry the rekor entry obtained from rekor * @return the parsed pojo - * @throws RekorTypeException if the kind != hashedrekord or apiVersion != 0.0.1 + * @throws RekorTypeException if the hashrekord:0.0.1 entry could not be parsed */ public static HashedRekord getHashedRekord(RekorEntry entry) throws RekorTypeException { expect(entry, "hashedrekord", "0.0.1"); - return GSON.get().fromJson(entry.getBodyDecoded().getSpec(), HashedRekord.class); + try { + return GSON.get().fromJson(entry.getBodyDecoded().getSpec(), HashedRekord.class); + } catch (JsonParseException jpe) { + throw new RekorTypeException("Could not parse hashrekord:0.0.1", jpe); + } + } + + /** + * Parse a dsse from rekor at api version 0.0.1. + * + * @param entry the rekor entry obtained from rekor + * @return the parsed pojo + * @throws RekorTypeException if the dsse:0.0.1 entry could not be parsed + */ + public static Dsse getDsse(RekorEntry entry) throws RekorTypeException { + expect(entry, "dsse", "0.0.1"); + + try { + return GSON.get().fromJson(entry.getBodyDecoded().getSpec(), Dsse.class); + } catch (JsonParseException jpe) { + throw new RekorTypeException("Could not parse dsse:0.0.1", jpe); + } } private static void expect(RekorEntry entry, String expectedKind, String expectedApiVersion) diff --git a/sigstore-java/src/main/resources/rekor/model/dsse/v0.0.1/dsse.json b/sigstore-java/src/main/resources/rekor/model/dsse/v0.0.1/dsse.json new file mode 100644 index 00000000..51ebe399 --- /dev/null +++ b/sigstore-java/src/main/resources/rekor/model/dsse/v0.0.1/dsse.json @@ -0,0 +1,96 @@ +{ + "$schema": "http://json-schema.org/draft-07/schema#", + "$id": "http://rekor.sigstore.dev/types/dsse/dsse_v0_0_1_schema.json", + "title": "DSSE v0.0.1 Schema", + "description": "Schema for DSSE envelopes", + "type": "object", + "properties": { + "proposedContent": { + "type": "object", + "properties": { + "envelope": { + "description": "DSSE envelope specified as a stringified JSON object", + "type": "string", + "writeOnly": true + }, + "verifiers": { + "description": "collection of all verification material (e.g. public keys or certificates) used to verify signatures over envelope's payload, specified as base64-encoded strings", + "type": "array", + "minItems": 1, + "items": { + "type": "string", + "format": "byte" + }, + "writeOnly": true + } + }, + "writeOnly": true, + "required": [ "envelope", "verifiers" ] + }, + "signatures": { + "description": "extracted collection of all signatures of the envelope's payload; elements will be sorted by lexicographical order of the base64 encoded signature strings", + "type": "array", + "minItems": 1, + "items": { + "description": "a signature of the envelope's payload along with the verification material for the signature", + "type": "object", + "properties": { + "signature": { + "description": "base64 encoded signature of the payload", + "type": "string", + "pattern": "^(?:[A-Za-z0-9+\\/]{4})*(?:[A-Za-z0-9+\\/]{2}==|[A-Za-z0-9+\\/]{3}=|[A-Za-z0-9+\\/]{4})$" + }, + "verifier": { + "description": "verification material that was used to verify the corresponding signature, specified as a base64 encoded string", + "type": "string", + "format": "byte" + } + }, + "required": [ "signature", "verifier" ] + }, + "readOnly": true + }, + "envelopeHash": { + "description": "Specifies the hash algorithm and value encompassing the entire envelope sent to Rekor", + "type": "object", + "properties": { + "algorithm": { + "description": "The hashing function used to compute the hash value", + "type": "string", + "enum": [ "sha256" ] + }, + "value": { + "description": "The value of the computed digest over the entire envelope", + "type": "string" + } + }, + "required": [ "algorithm", "value" ], + "readOnly": true + }, + "payloadHash": { + "description": "Specifies the hash algorithm and value covering the payload within the DSSE envelope", + "type": "object", + "properties": { + "algorithm": { + "description": "The hashing function used to compute the hash value", + "type": "string", + "enum": [ "sha256" ] + }, + "value": { + "description": "The value of the computed digest over the payload within the envelope", + "type": "string" + } + }, + "required": [ "algorithm", "value" ], + "readOnly": true + } + }, + "oneOf": [ + { + "required": [ "proposedContent" ] + }, + { + "required": [ "signatures", "envelopeHash", "payloadHash" ] + } + ] +} diff --git a/sigstore-java/src/main/resources/rekor/model/hashedRekord.json b/sigstore-java/src/main/resources/rekor/model/hashedRekord/v0.0.1/hashedRekord.json similarity index 82% rename from sigstore-java/src/main/resources/rekor/model/hashedRekord.json rename to sigstore-java/src/main/resources/rekor/model/hashedRekord/v0.0.1/hashedRekord.json index b1ef6505..3d536eb4 100644 --- a/sigstore-java/src/main/resources/rekor/model/hashedRekord.json +++ b/sigstore-java/src/main/resources/rekor/model/hashedRekord/v0.0.1/hashedRekord.json @@ -1,6 +1,6 @@ { "$schema": "http://json-schema.org/draft-07/schema#", - "$id": "http://rekor.sigstore.dev/types/rekord/rekord_v0_0_1_schema.json", + "$id": "http://rekor.sigstore.dev/types/rekord/hashedrekord_v0_0_1_schema.json", "title": "Hashed Rekor v0.0.1 Schema", "description": "Schema for Hashed Rekord object", "type": "object", @@ -15,11 +15,11 @@ "format": "byte" }, "publicKey" : { - "description": "The public key that can verify the signature", + "description": "The public key that can verify the signature; this can also be an X509 code signing certificate that contains the raw public key information", "type": "object", "properties": { "content": { - "description": "Specifies the content of the public key inline within the document", + "description": "Specifies the content of the public key or code signing certificate inline within the document", "type": "string", "format": "byte" } @@ -38,16 +38,16 @@ "algorithm": { "description": "The hashing function used to compute the hash value", "type": "string", - "enum": [ "sha256" ] + "enum": [ "sha256", "sha384", "sha512" ] }, "value": { - "description": "The hash value for the content", + "description": "The hash value for the content, as represented by a lower case hexadecimal string", "type": "string" } }, "required": [ "algorithm", "value" ] } - } + } } }, "required": [ "signature", "data" ]