Java

sigstore-java is a Java client for signing and verifying artifacts with Sigstore. It supports keyless signing — signing without managing long-lived private keys, using short-lived certificates tied to an OIDC (OpenID Connect) identity — via build plugins for Maven and Gradle, and a direct Java API.

Features

  • Maven and Gradle signing plugins
  • Keyless signing and verification
  • Java API (Javadoc)
  • DSSE (Dead Simple Signing Envelope) attestation verification, plus attestation signing on staging (testing only)
  • TUF (The Update Framework) integration for trusted root management
  • GitHub Actions OIDC support for CI/CD pipelines
  • Verification of bundles without a transparency log entry, using RFC 3161 timestamps (for private deployments)

Requirements

  • Java 11 or higher
  • Gradle 7.5 or higher (for the Gradle plugin)

Installation

Release information is available on the releases page. Use the latest version for your install.

Maven

<plugin>
  <groupId>dev.sigstore</groupId>
  <artifactId>sigstore-maven-plugin</artifactId>
  <version>2.4.0</version>
  <executions>
    <execution>
      <id>sign</id>
      <goals>
        <goal>sign</goal>
      </goals>
    </execution>
  </executions>
</plugin>

More information on the Maven plugin is available in the project repository. Each published file gets a matching <filename>.sigstore.json bundle. If you also GPG-sign for Maven Central, use maven-gpg-plugin 3.2.5 or higher so the .sigstore.json files aren’t GPG-signed.

Gradle

plugins {
    id("dev.sigstore.sign") version "2.4.0"
}

This automatically signs all Maven publications, generating a <filename>.sigstore.json bundle for each file. More information is available in the project repository.

Signing individual files

Use the sign-base plugin to sign individual files without tying into Maven publication:

plugins {
    id("dev.sigstore.sign-base") version "2.4.0"
}

val helloProps by tasks.registering(WriteProperties::class) {
    outputFile = file("build/helloProps.txt")
    property("helloProps", "world")
}

val signHelloProps by tasks.registering(dev.sigstore.sign.tasks.SigstoreSignFilesTask::class) {
    signFile(helloProps.map { it.outputFile })
    // Alternatives: sign(File), sign(Provider<RegularFile>)
}
    signFile(/* Provider<File>; use sign(...) for a File or Provider<RegularFile> */)
}

GitHub Actions

To use keyless signing in a GitHub Actions workflow, the workflow must request an OIDC token. Grant the necessary permissions on the job or workflow:

permissions:
  id-token: write
  contents: read

See GitHub’s documentation on OIDC permissions for details.

API Usage

The stable public API consists of KeylessSigner and KeylessVerifier and the classes exposed by those APIs. Other library classes may change between releases without notice.

Signing

import dev.sigstore.KeylessSigner;
import dev.sigstore.bundle.Bundle;
import java.nio.file.Path;
import java.nio.file.Paths;

Path artifact = Paths.get("path/to/my/file.jar");

var signer = KeylessSigner.builder().sigstorePublicDefaults().build();
Bundle bundle = signer.signFile(artifact);

// serialized as <artifact>.sigstore.json
String bundleJson = bundle.toJson();

Verifying

Get artifact and bundle

import dev.sigstore.bundle.Bundle;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.nio.file.Paths;

Path artifact = Paths.get("path/to/my-artifact");
Path bundleFile = Paths.get("path/to/my-artifact.sigstore.json");
Bundle bundle = Bundle.from(bundleFile, StandardCharsets.UTF_8);

Configure verification options

import dev.sigstore.VerificationOptions;
import dev.sigstore.strings.StringMatcher;

VerificationOptions verificationOptions = VerificationOptions.builder()
  .addCertificateMatchers(
    VerificationOptions.CertificateMatcher.fulcio()
      .subjectAlternativeName(StringMatcher.string("test@example.com"))
      .issuer(StringMatcher.string("https://accounts.example.com"))
      .build())
  .build();

Do verification

import dev.sigstore.KeylessVerifier;
import dev.sigstore.KeylessVerificationException;

try {
  var verifier = KeylessVerifier.builder().sigstorePublicDefaults().build();
  verifier.verify(artifact, bundle, verificationOptions);
  // verification passed
} catch (KeylessVerificationException e) {
  // verification failed
}

DSSE Attestation Signing (staging only)

DSSE attestation signing is currently only available for testing on the staging instance, which uses Rekor V2, Sigstore’s append-only transparency log:

DSSE attestation signing requires Rekor V2, Sigstore’s append-only transparency log. The following example uses the staging instance, which has Rekor V2 enabled:

import dev.sigstore.KeylessSigner;
import dev.sigstore.bundle.Bundle;

String payload = "<some https://in-toto.io/Statement/v1 statement>";
var signer = KeylessSigner.builder().sigstoreStagingDefaults().enableRekorV2(true).build();
Bundle bundle = signer.attest(payload);
String bundleJson = bundle.toJson();

KeylessVerifier can verify DSSE bundles using the same workflow as above. It checks that the artifact is a subject of the in-toto statement but makes no further assertions about the payload, so inspect the payload with a tool like slsa-verifier.

Additional examples are available in the project repository.

Known Limitations

  • Offline signing is not supported.
  • Offline verification is not supported by default, since the client checks the TUF repository for trusted root updates. For restricted environments, configure KeylessVerifier with a cached or custom SigstoreTrustedRoot.
  • Maven plugin, multi-module builds: each module requires its own OIDC authentication.
  • Maven plugin, long-running builds: the signing session lasts 10 minutes. Longer builds require a new OIDC authentication every 10 minutes.
  • Long-running builds: the OIDC token has a 10-minute validity window. Builds that take longer than 10 minutes may require re-authentication partway through.