Skip to content

Flow 17 --- Rapid Revocation Lifecycle (Non-Streaming)

This scenario walks through an instant key-revocation cycle with an RSA-3072 key:

  1. Generate a new RSA-3072 key (kty="RSA", alg="RSA-3072").

  2. Sign a plaintext file → compact JWS (non-streaming helper).

  3. Revoke the key immediately.

  4. Attempt a second signature --- the SDK must raise AnkaSecureSdkException.

  5. 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&nbsp;=&nbsp;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&nbsp;17 – Rapid Revocation Lifecycle (Compact&nbsp;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&nbsp;JWS.</li>
 *   <li>Revoke the key.</li>
 *   <li>Attempt a second signature (should fail).</li>
 *   <li>Export the key metadata and confirm <code>status&nbsp;=&nbsp;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

mvn -q compile exec:java\
  -Dexec.mainClass="co.ankatech.ankasecure.sdk.examples.ExampleScenario17"

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.