Flow 17 --- Rapid Revocation Lifecycle (Non-Streaming)
This scenario walks through an instant key-revocation cycle with an RSA-3072 key:
-
Generate a new RSA-3072 key (
kty="RSA"
,alg="RSA-3072"
). -
Sign a plaintext file → compact JWS (non-streaming helper).
-
Revoke the key immediately.
-
Attempt a second signature --- the SDK must raise
AnkaSecureSdkException
. -
Export the key metadata and verify the flag
status = REVOKED
.
Key points
Illustrates how to invalidate a compromised key in real time.
Demonstrates that post-revocation crypto operations are blocked by the platform.
Shows how to prove revocation via a metadata export.
Keeps all artefacts inside
temp_files/
so your workspace stays clean.
When to use it
-
Incident response drills -- rehearse the immediate kill-switch procedure for leaked signing keys.
-
Compliance evidence -- provide auditors with a repeatable test that revocation is enforced.
-
Operational monitoring -- integrate into CI to ensure revoked keys cannot be reused accidentally.
Shared helper – this code imports the utility class from
example_util.md (configuration, authentication, JSON).
Complete Java implementation
src/main/java/co/ankatech/ankasecure/sdk/examples/ExampleScenario17.java
/* *****************************************************************************
* FILE: ExampleScenario17.java
* Copyright © 2025 Anka Technologies.
* SPDX-License-Identifier: MIT
* ---------------------------------------------------------------------------
* Scenario 17 – Rapid-Revocation Lifecycle (Non-Streaming)
* ---------------------------------------------------------------------------
* Demonstrates how to:
* * Generate an RSA-3072 key.
* * Sign a file (compact JWS).
* * Revoke the key.
* * Attempt a second signature (expected failure).
* * Export the key metadata and confirm <code>status = REVOKED</code>.
*
* All transient artefacts are written under <kbd>temp_files/</kbd>.
* ****************************************************************************/
package co.ankatech.ankasecure.sdk.examples;
import co.ankatech.ankasecure.sdk.AnkaSecureSdk;
import co.ankatech.ankasecure.sdk.exception.AnkaSecureSdkException;
import co.ankatech.ankasecure.sdk.model.ExportedKeySpec;
import co.ankatech.ankasecure.sdk.model.GenerateKeySpec;
import co.ankatech.ankasecure.sdk.model.SignResult;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.text.MessageFormat;
import java.util.List;
import java.util.Properties;
/**
* <h2>Scenario 17 – Rapid Revocation Lifecycle (Compact JWS)</h2>
*
* <p>This scenario validates that once an RSA-3072 key is revoked, subsequent
* signing requests with the same <code>kid</code> are rejected:</p>
* <ol>
* <li>Generate an RSA-3072 key.</li>
* <li>Create a first compact JWS.</li>
* <li>Revoke the key.</li>
* <li>Attempt a second signature (should fail).</li>
* <li>Export the key metadata and confirm <code>status = REVOKED</code>.</li>
* </ol>
*
* @author ANKATech – Security Engineering
*/
public final class ExampleScenario17 {
/** Working directory for scenario artefacts. */
private static final Path TEMP_DIR = Path.of("temp_files");
/* ====================================================================== */
/** Entry-point. */
public static void main(final String[] args) {
System.out.println("===== SCENARIO 17 START =====");
System.out.println("""
Purpose :
* Generate RSA-3072, sign once, revoke, then confirm blocking.
Steps :
1) Generate RSA-3072 key
2) Sign a file (compact JWS)
3) Revoke key
4) Attempt second sign (should fail)
5) Export and verify status = REVOKED
--------------------------------------------------------------""");
try {
ensureTempDir(TEMP_DIR);
Properties props = ExampleUtil.loadProperties();
AnkaSecureSdk sdk = ExampleUtil.authenticate(props);
runScenario(sdk);
} catch (Exception ex) {
fatal("Scenario 17 failed", ex);
}
System.out.println("===== SCENARIO 17 END =====");
}
/* ====================================================================== */
/** Executes the scenario logic. */
private static void runScenario(final AnkaSecureSdk sdk) throws Exception {
/* 0 ── prepare sample file -------------------------------------- */
Path data = TEMP_DIR.resolve("scenario17_data.txt");
Files.writeString(
data,
"Scenario 17 – RSA-3072 rapid revocation demo.",
StandardCharsets.UTF_8);
System.out.println("[0] Data file prepared -> " + data.toAbsolutePath());
/* 1 ── generate RSA-3072 key ----------------------------------- */
String kid = "sc17_rsa3072_" + System.currentTimeMillis();
sdk.generateKey(new GenerateKeySpec()
.setKid(kid)
.setKty("RSA")
.setAlg("RSA-3072"));
System.out.println("[1] Key generated -> kid = " + kid);
/* 2 ── sign file successfully ---------------------------------- */
Path sig1 = TEMP_DIR.resolve("scenario17_sig1.jws");
SignResult meta1 = sdk.signFile(kid, data, sig1);
System.out.println("[2] First signature created -> " + sig1.toAbsolutePath());
printSignMeta(meta1);
/* 3 ── revoke key ---------------------------------------------- */
sdk.revokeKey(kid);
System.out.println("[3] Key revoked -> kid = " + kid);
/* 4 ── attempt second sign (expect failure) -------------------- */
try {
Path sig2 = TEMP_DIR.resolve("scenario17_sig2.jws");
sdk.signFile(kid, data, sig2);
System.err.println("[4] ERROR – signing succeeded after revocation!");
} catch (AnkaSecureSdkException ex) {
System.out.println(MessageFormat.format(
"[4] Expected failure -> HTTP={0}, message={1}",
ex.getStatusCode(), ex.getMessage()));
}
/* 5 ── export metadata and confirm status ---------------------- */
ExportedKeySpec exported = sdk.exportKey(kid);
System.out.println("[5] Exported key status -> " + exported.getStatus());
}
/* ====================================================================== */
/** Pretty-prints signing metadata. */
private static void printSignMeta(final SignResult r) {
System.out.println(" * Key requested : " + nullSafe(r.getKeyRequested()));
System.out.println(" * Key used : " + nullSafe(r.getActualKeyUsed()));
System.out.println(" * Algorithm : " + nullSafe(r.getAlgorithmUsed()));
printWarnings(r.getWarnings());
}
/** Prints warnings in a consistent layout. */
private static void printWarnings(final List<String> warnings) {
if (warnings != null && !warnings.isEmpty()) {
System.out.println(" * Warnings:");
warnings.forEach(w -> System.out.println(" * " + w));
}
}
/* ====================================================================== */
/** Substitutes <code>(none)</code> for null / blank strings. */
private static String nullSafe(final String s) {
return (s == null || s.isBlank()) ? "(none)" : s;
}
/** Ensures the temporary directory exists. */
private static void ensureTempDir(final Path dir) throws Exception {
if (!Files.exists(dir)) {
Files.createDirectories(dir);
}
}
/** Logs an unrecoverable error and terminates. */
private static void fatal(final String msg, final Throwable t) {
System.err.println(msg);
if (t != null) {
t.printStackTrace(System.err);
}
System.exit(1);
}
/**
* Private constructor prevents instantiation.
*/
private ExampleScenario17() {
/* utility class – no instantiation */
}
}
How to run
Console milestones
-
RSA-3072 key generation
-
First compact-JWS signature
-
Key revocation
-
Expected failure on second sign (
AnkaSecureSdkException
) -
Export shows
status = REVOKED
Where next?
© 2025 Anka Technologies. All rights reserved.