diff --git a/pom.xml b/pom.xml
index 19745da..1882300 100644
--- a/pom.xml
+++ b/pom.xml
@@ -119,6 +119,13 @@
jakarta.el
4.0.2
+
+
+ dev.sigstore
+ sigstore-java
+ 0.10.0
+
+
diff --git a/src/main/java/io/github/intoto/dsse/helpers/SimpleSigstoreSigner.java b/src/main/java/io/github/intoto/dsse/helpers/SimpleSigstoreSigner.java
new file mode 100644
index 0000000..6670f2d
--- /dev/null
+++ b/src/main/java/io/github/intoto/dsse/helpers/SimpleSigstoreSigner.java
@@ -0,0 +1,90 @@
+package io.github.intoto.dsse.helpers;
+
+import dev.sigstore.KeylessSigner;
+import dev.sigstore.KeylessSignerException;
+import dev.sigstore.bundle.Bundle;
+import io.github.intoto.dsse.models.Signer;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.*;
+import java.security.cert.CertificateException;
+import java.security.cert.CertificateParsingException;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.util.Optional;
+
+public class SimpleSigstoreSigner implements Signer {
+ private String keyId;
+ Optional messageSignature;
+ Bundle result;
+
+ public byte[] sign(byte[] payload) throws InvalidAlgorithmParameterException, CertificateException, IOException, NoSuchAlgorithmException, InvalidKeySpecException, InvalidKeyException, KeylessSignerException {
+ if (payload == null || payload.length == 0) {
+ throw new RuntimeException("payload cannot be null or empty");
+ }
+
+ // convert payload to SHA-256 Digest
+ MessageDigest messageDigest = MessageDigest.getInstance("SHA-256");
+ byte[] payloadDigest = messageDigest.digest(payload);
+
+ KeylessSigner functionary = new KeylessSigner.Builder().sigstorePublicDefaults().build();
+ this.result = functionary.sign(payloadDigest);
+
+ this.keyId = setKeyId(this.result);
+
+ this.messageSignature = this.result.getMessageSignature();
+ if (this.messageSignature.isPresent()) {
+ return this.messageSignature
+ .get()
+ .getSignature();
+ }
+ throw new RuntimeException("Cannot retrieve Message Signature");
+ }
+
+ private String setKeyId(Bundle bundle) throws CertificateParsingException {
+ if (!bundle.getCertPath().getCertificates().isEmpty()) {
+ X509Certificate certificate = (X509Certificate) (bundle.getCertPath().getCertificates().get(0));
+ String oid = "1.3.6.1.4.1.57264.1.8";
+ byte[] extensionValue = certificate.getExtensionValue(oid);
+ String issuer = new String(extensionValue, StandardCharsets.UTF_8);
+ String header = "https://";
+ String provider = issuer.substring(issuer.lastIndexOf("/") + 1);
+ issuer = header + provider;
+
+ this.keyId = "<" + issuer + ">:";
+ Object sanArray = certificate.getSubjectAlternativeNames().toArray()[0];
+ String san = sanArray.toString();
+ san = san.substring(4, san.length() - 1);
+ this.keyId = keyId.concat("<" + san + ">");
+ return this.keyId;
+ }
+ throw new RuntimeException("Cannot extract certificates from empty bundle");
+ }
+
+ @Override
+ public String getKeyId() {
+ if (this.keyId.isEmpty()) {
+ throw new RuntimeException("Sign the artifact to initialize keyId");
+ }
+ return this.keyId;
+ }
+
+ public byte[] getPayloadDigest() {
+ if (this.messageSignature.isEmpty()) {
+ throw new RuntimeException("Cannot retrieve and unsigned payload");
+ }
+ if (this.messageSignature.get().getMessageDigest().isPresent()) {
+ return this.messageSignature
+ .get()
+ .getMessageDigest()
+ .get()
+ .getDigest();
+ }
+ throw new RuntimeException("Cannot retrieve SHA-256 Message Digest");
+ }
+
+ public byte[] getBundleJsonBytes() {
+ return this.result.toJson().getBytes();
+ }
+}
\ No newline at end of file
diff --git a/src/main/java/io/github/intoto/dsse/models/Signer.java b/src/main/java/io/github/intoto/dsse/models/Signer.java
index 4928d9e..4566c0d 100644
--- a/src/main/java/io/github/intoto/dsse/models/Signer.java
+++ b/src/main/java/io/github/intoto/dsse/models/Signer.java
@@ -1,8 +1,14 @@
package io.github.intoto.dsse.models;
+import dev.sigstore.KeylessSignerException;
+
+import java.io.IOException;
+import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.spec.InvalidKeySpecException;
/** Interface for a DSSE Signer. */
public interface Signer {
@@ -13,7 +19,7 @@ public interface Signer {
* @param payload the message that you want to sign.
*/
byte[] sign(byte[] payload)
- throws NoSuchAlgorithmException, InvalidKeyException, SignatureException;
+ throws NoSuchAlgorithmException, InvalidKeyException, SignatureException, InvalidAlgorithmParameterException, CertificateException, IOException, InvalidKeySpecException, KeylessSignerException;
/** Returns the ID of this key, or null if not supported. */
String getKeyId();
diff --git a/src/main/java/io/github/intoto/helpers/IntotoHelper.java b/src/main/java/io/github/intoto/helpers/IntotoHelper.java
index f51487e..9f48313 100644
--- a/src/main/java/io/github/intoto/helpers/IntotoHelper.java
+++ b/src/main/java/io/github/intoto/helpers/IntotoHelper.java
@@ -4,15 +4,21 @@
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.databind.json.JsonMapper;
+import dev.sigstore.KeylessSignerException;
import io.github.intoto.dsse.models.IntotoEnvelope;
import io.github.intoto.dsse.models.Signature;
import io.github.intoto.dsse.models.Signer;
import io.github.intoto.exceptions.InvalidModelException;
import io.github.intoto.models.Statement;
+
+import java.io.IOException;
import java.nio.charset.StandardCharsets;
+import java.security.InvalidAlgorithmParameterException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
+import java.security.cert.CertificateException;
+import java.security.spec.InvalidKeySpecException;
import java.util.Base64;
import java.util.List;
import java.util.Set;
@@ -49,8 +55,8 @@ public class IntotoHelper {
*/
public static String produceIntotoEnvelopeAsJson(
Statement statement, Signer signer, boolean prettyPrint)
- throws InvalidModelException, JsonProcessingException, NoSuchAlgorithmException,
- SignatureException, InvalidKeyException {
+ throws InvalidModelException, IOException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException, InvalidAlgorithmParameterException, CertificateException, InvalidKeySpecException, KeylessSignerException {
IntotoEnvelope envelope = produceIntotoEnvelope(statement, signer);
if (prettyPrint) {
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(envelope);
@@ -74,8 +80,8 @@ public static String produceIntotoEnvelopeAsJson(
* algorithm
*/
public static IntotoEnvelope produceIntotoEnvelope(Statement statement, Signer signer)
- throws InvalidModelException, JsonProcessingException, NoSuchAlgorithmException,
- SignatureException, InvalidKeyException {
+ throws InvalidModelException, IOException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException, InvalidAlgorithmParameterException, CertificateException, InvalidKeySpecException, KeylessSignerException {
// Get the Base64 encoded Statement to use as the payload
String jsonStatement = validateAndTransformToJson(statement, false);
String base64EncodedStatement = Base64.getEncoder().encodeToString(jsonStatement.getBytes());
diff --git a/src/test/java/io/github/intoto/helpers/provenancev01/IntotoHelperTest.java b/src/test/java/io/github/intoto/helpers/provenancev01/IntotoHelperTest.java
index f2a97bd..1e3c260 100644
--- a/src/test/java/io/github/intoto/helpers/provenancev01/IntotoHelperTest.java
+++ b/src/test/java/io/github/intoto/helpers/provenancev01/IntotoHelperTest.java
@@ -9,6 +9,7 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.fasterxml.jackson.core.JsonProcessingException;
+import dev.sigstore.KeylessSignerException;
import io.github.intoto.dsse.helpers.SimpleECDSASigner;
import io.github.intoto.dsse.helpers.SimpleECDSAVerifier;
import io.github.intoto.dsse.models.IntotoEnvelope;
@@ -25,14 +26,11 @@
import io.github.intoto.slsa.models.v01.Recipe;
import io.github.intoto.utilities.provenancev01.IntotoStubFactory;
import java.io.File;
+import java.io.IOException;
import java.nio.charset.StandardCharsets;
-import java.security.InvalidKeyException;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.SignatureException;
+import java.security.*;
+import java.security.cert.CertificateException;
+import java.security.spec.InvalidKeySpecException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -566,8 +564,8 @@ public void createPreAuthenticationEncoding_shouldCorrectlyEncode_withUtfCharact
@DisplayName("Test creating envelope from Statement")
public void
produceIntotoEnvelopeAsJson_shouldCorrectlyCreateAnEnvelope_whenCompleteStatementIsPassed()
- throws InvalidModelException, JsonProcessingException, NoSuchAlgorithmException,
- SignatureException, InvalidKeyException {
+ throws InvalidModelException, IOException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException, InvalidAlgorithmParameterException, CertificateException, InvalidKeySpecException, KeylessSignerException {
// ** The subject **
Subject subject = new Subject();
subject.setName("curl-7.72.0.tar.bz2");
diff --git a/src/test/java/io/github/intoto/helpers/provenancev02/IntotoHelperTest.java b/src/test/java/io/github/intoto/helpers/provenancev02/IntotoHelperTest.java
index 2b32dbb..22d08d7 100644
--- a/src/test/java/io/github/intoto/helpers/provenancev02/IntotoHelperTest.java
+++ b/src/test/java/io/github/intoto/helpers/provenancev02/IntotoHelperTest.java
@@ -9,6 +9,7 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.fasterxml.jackson.core.JsonProcessingException;
+import dev.sigstore.KeylessSignerException;
import io.github.intoto.dsse.helpers.SimpleECDSASigner;
import io.github.intoto.dsse.helpers.SimpleECDSAVerifier;
import io.github.intoto.dsse.models.IntotoEnvelope;
@@ -22,14 +23,11 @@
import io.github.intoto.slsa.models.v02.*;
import io.github.intoto.utilities.provenancev02.IntotoStubFactory;
import java.io.File;
+import java.io.IOException;
import java.nio.charset.StandardCharsets;
-import java.security.InvalidKeyException;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.SignatureException;
+import java.security.*;
+import java.security.cert.CertificateException;
+import java.security.spec.InvalidKeySpecException;
import java.util.Collections;
import java.util.List;
import java.util.Map;
@@ -577,8 +575,8 @@ public void createPreAuthenticationEncoding_shouldCorrectlyEncode_withUtfCharact
@DisplayName("Test creating envelope from Statement")
public void
produceIntotoEnvelopeAsJson_shouldCorrectlyCreateAnEnvelope_whenCompleteStatementIsPassed()
- throws InvalidModelException, JsonProcessingException, NoSuchAlgorithmException,
- SignatureException, InvalidKeyException {
+ throws InvalidModelException, IOException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException, InvalidAlgorithmParameterException, CertificateException, InvalidKeySpecException, KeylessSignerException {
// ** The subject **
Subject subject = new Subject();
subject.setName("curl-7.72.0.tar.bz2");
diff --git a/src/test/java/io/github/intoto/helpers/provenancev1/IntotoHelperTest.java b/src/test/java/io/github/intoto/helpers/provenancev1/IntotoHelperTest.java
index 0252c48..0b10974 100644
--- a/src/test/java/io/github/intoto/helpers/provenancev1/IntotoHelperTest.java
+++ b/src/test/java/io/github/intoto/helpers/provenancev1/IntotoHelperTest.java
@@ -9,6 +9,7 @@
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.fasterxml.jackson.core.JsonProcessingException;
+import dev.sigstore.KeylessSignerException;
import io.github.intoto.dsse.helpers.SimpleECDSASigner;
import io.github.intoto.dsse.helpers.SimpleECDSAVerifier;
import io.github.intoto.dsse.models.IntotoEnvelope;
@@ -27,14 +28,11 @@
import io.github.intoto.slsa.models.v1.RunDetails;
import io.github.intoto.utilities.provenancev1.IntotoStubFactory;
import java.io.File;
+import java.io.IOException;
import java.nio.charset.StandardCharsets;
-import java.security.InvalidKeyException;
-import java.security.KeyPair;
-import java.security.NoSuchAlgorithmException;
-import java.security.PrivateKey;
-import java.security.PublicKey;
-import java.security.Security;
-import java.security.SignatureException;
+import java.security.*;
+import java.security.cert.CertificateException;
+import java.security.spec.InvalidKeySpecException;
import java.time.OffsetDateTime;
import java.util.ArrayList;
import java.util.Collections;
@@ -600,8 +598,8 @@ public void createPreAuthenticationEncoding_shouldCorrectlyEncode_withUtfCharact
@DisplayName("Test creating envelope from Statement")
public void
produceIntotoEnvelopeAsJson_shouldCorrectlyCreateAnEnvelope_whenCompleteStatementIsPassed()
- throws InvalidModelException, JsonProcessingException, NoSuchAlgorithmException,
- SignatureException, InvalidKeyException {
+ throws InvalidModelException, IOException, NoSuchAlgorithmException,
+ SignatureException, InvalidKeyException, InvalidAlgorithmParameterException, CertificateException, InvalidKeySpecException, KeylessSignerException {
// ** The subject **
Subject subject = new Subject();
subject.setName("curl-7.72.0.tar.bz2");