Compare commits
9 Commits
impl-hybri
...
impl-pki
| Author | SHA1 | Date | |
|---|---|---|---|
|
adfa0b4b51
|
|||
|
e01d95f48e
|
|||
|
969a846d95
|
|||
|
d2ec77b8e3
|
|||
|
0346c5b30f
|
|||
|
cab1eeefe7
|
|||
|
7673e7d82f
|
|||
|
276ac91eb4
|
|||
|
e82e0e57fb
|
@@ -132,17 +132,17 @@ public final class CovertCommand {
|
|||||||
* @throws ParseException if the arguments are invalid or incomplete
|
* @throws ParseException if the arguments are invalid or incomplete
|
||||||
*/
|
*/
|
||||||
public static int main(String[] args, Options options) throws ParseException {
|
public static int main(String[] args, Options options) throws ParseException {
|
||||||
final Option EMBED_OPTION = Option.builder().longOpt("embed").desc("Embed a payload into a JPEG").build();
|
final Option EMBED_OPTION = Option.builder().longOpt("embed").desc("Embed a payload into a JPEG").get();
|
||||||
final Option EXTRACT_OPTION = Option.builder().longOpt("extract").desc("Extract a payload from a JPEG").build();
|
final Option EXTRACT_OPTION = Option.builder().longOpt("extract").desc("Extract a payload from a JPEG").get();
|
||||||
final Option JPEG_OPTION = Option.builder().longOpt("jpeg").hasArg().argName("input.jpg")
|
final Option JPEG_OPTION = Option.builder().longOpt("jpeg").hasArg().argName("input.jpg")
|
||||||
.desc("Input JPEG file").required().build();
|
.desc("Input JPEG file").required().get();
|
||||||
final Option PAYLOAD_OPTION = Option.builder().longOpt("payload").hasArg().argName("payload.dat")
|
final Option PAYLOAD_OPTION = Option.builder().longOpt("payload").hasArg().argName("payload.dat")
|
||||||
.desc("Binary payload file to embed").build();
|
.desc("Binary payload file to embed").get();
|
||||||
final Option OUTPUT_OPTION = Option.builder().longOpt("output").hasArg().argName("outputFile")
|
final Option OUTPUT_OPTION = Option.builder().longOpt("output").hasArg().argName("outputFile")
|
||||||
.desc("Output JPEG or payload file").required().build();
|
.desc("Output JPEG or payload file").required().get();
|
||||||
final Option SLOTS_OPTION = Option.builder().longOpt("slots").hasArgs().valueSeparator(';')
|
final Option SLOTS_OPTION = Option.builder().longOpt("slots").hasArgs().valueSeparator(';')
|
||||||
.argName("slot1;slot2;...")
|
.argName("slot1;slot2;...")
|
||||||
.desc("Custom EXIF slots (e.g. Exif.UserComment:4096;Exif.Custom/tag=700,ascii,64,exif:1024)").build();
|
.desc("Custom EXIF slots (e.g. Exif.UserComment:4096;Exif.Custom/tag=700,ascii,64,exif:1024)").get();
|
||||||
|
|
||||||
OptionGroup modeGroup = new OptionGroup();
|
OptionGroup modeGroup = new OptionGroup();
|
||||||
modeGroup.addOption(EMBED_OPTION);
|
modeGroup.addOption(EMBED_OPTION);
|
||||||
|
|||||||
@@ -128,71 +128,71 @@ public final class Guard {
|
|||||||
|
|
||||||
// ---- operation selection
|
// ---- operation selection
|
||||||
final Option OPT_ENCRYPT = Option.builder("e").longOpt("encrypt").hasArg().argName("in-file")
|
final Option OPT_ENCRYPT = Option.builder("e").longOpt("encrypt").hasArg().argName("in-file")
|
||||||
.desc("Encrypt the given file").build();
|
.desc("Encrypt the given file").get();
|
||||||
final Option OPT_DECRYPT = Option.builder("d").longOpt("decrypt").hasArg().argName("in-file")
|
final Option OPT_DECRYPT = Option.builder("d").longOpt("decrypt").hasArg().argName("in-file")
|
||||||
.desc("Decrypt the given file").build();
|
.desc("Decrypt the given file").get();
|
||||||
final OptionGroup OP = new OptionGroup().addOption(OPT_ENCRYPT).addOption(OPT_DECRYPT);
|
final OptionGroup OP = new OptionGroup().addOption(OPT_ENCRYPT).addOption(OPT_DECRYPT);
|
||||||
OP.setRequired(true);
|
OP.setRequired(true);
|
||||||
|
|
||||||
// ---- common I/O
|
// ---- common I/O
|
||||||
final Option OPT_OUT = Option.builder("o").longOpt("output").hasArg().argName("out-file")
|
final Option OPT_OUT = Option.builder("o").longOpt("output").hasArg().argName("out-file")
|
||||||
.desc("Output file (default: <in>.enc for encrypt, <in>.dec for decrypt)").build();
|
.desc("Output file (default: <in>.enc for encrypt, <in>.dec for decrypt)").get();
|
||||||
final Option OPT_KEYRING = Option.builder().longOpt("keyring").hasArg().argName("keyring.txt")
|
final Option OPT_KEYRING = Option.builder().longOpt("keyring").hasArg().argName("keyring.txt")
|
||||||
.desc("KeyringStore file for aliases (required when aliases are used)").build();
|
.desc("KeyringStore file for aliases (required when aliases are used)").get();
|
||||||
|
|
||||||
// ---- payload selection and parameters
|
// ---- payload selection and parameters
|
||||||
final Option OPT_ALG = Option.builder().longOpt("alg").hasArg().argName("name")
|
final Option OPT_ALG = Option.builder().longOpt("alg").hasArg().argName("name")
|
||||||
.desc("Payload: aes-gcm | aes-ctr | aes-cbc-pkcs7 | aes-cbc-nopad | chacha-aead | chacha-stream "
|
.desc("Payload: aes-gcm | aes-ctr | aes-cbc-pkcs7 | aes-cbc-nopad | chacha-aead | chacha-stream "
|
||||||
+ "(default: aes-gcm)")
|
+ "(default: aes-gcm)")
|
||||||
.build();
|
.get();
|
||||||
final Option OPT_AAD_HEX = Option.builder("a").longOpt("aad-hex").hasArg().argName("hex")
|
final Option OPT_AAD_HEX = Option.builder("a").longOpt("aad-hex").hasArg().argName("hex")
|
||||||
.desc("Additional authenticated data as hex (AEAD modes)").build();
|
.desc("Additional authenticated data as hex (AEAD modes)").get();
|
||||||
final Option OPT_TAG_BITS = Option.builder().longOpt("tag-bits").hasArg().argName("96..128")
|
final Option OPT_TAG_BITS = Option.builder().longOpt("tag-bits").hasArg().argName("96..128")
|
||||||
.desc("AES-GCM tag length in bits (default 128)").build();
|
.desc("AES-GCM tag length in bits (default 128)").get();
|
||||||
final Option OPT_NONCE_HEX = Option.builder().longOpt("nonce-hex").hasArg().argName("hex")
|
final Option OPT_NONCE_HEX = Option.builder().longOpt("nonce-hex").hasArg().argName("hex")
|
||||||
.desc("ChaCha nonce (12-byte hex)").build();
|
.desc("ChaCha nonce (12-byte hex)").get();
|
||||||
final Option OPT_INIT_CTR = Option.builder().longOpt("init-ctr").hasArg().argName("int")
|
final Option OPT_INIT_CTR = Option.builder().longOpt("init-ctr").hasArg().argName("int")
|
||||||
.desc("ChaCha stream initial counter (default 1)").build();
|
.desc("ChaCha stream initial counter (default 1)").get();
|
||||||
final Option OPT_CTR = Option.builder().longOpt("ctr").hasArg().argName("int")
|
final Option OPT_CTR = Option.builder().longOpt("ctr").hasArg().argName("int")
|
||||||
.desc("ChaCha stream counter override (propagated via context)").build();
|
.desc("ChaCha stream counter override (propagated via context)").get();
|
||||||
final Option OPT_NO_HDR = Option.builder().longOpt("no-header")
|
final Option OPT_NO_HDR = Option.builder().longOpt("no-header")
|
||||||
.desc("Do not write or expect a symmetric header").build();
|
.desc("Do not write or expect a symmetric header").get();
|
||||||
|
|
||||||
// ---- envelope parameters
|
// ---- envelope parameters
|
||||||
final Option OPT_CEK_BYTES = Option.builder().longOpt("cek-bytes").hasArg().argName("len")
|
final Option OPT_CEK_BYTES = Option.builder().longOpt("cek-bytes").hasArg().argName("len")
|
||||||
.desc("Payload key (CEK) length in bytes (default 32)").build();
|
.desc("Payload key (CEK) length in bytes (default 32)").get();
|
||||||
final Option OPT_MAX_RECIPS = Option.builder().longOpt("max-recipients").hasArg().argName("n")
|
final Option OPT_MAX_RECIPS = Option.builder().longOpt("max-recipients").hasArg().argName("n")
|
||||||
.desc("Max recipients in the envelope header (default 64)").build();
|
.desc("Max recipients in the envelope header (default 64)").get();
|
||||||
final Option OPT_MAX_ENTRY = Option.builder().longOpt("max-entry-len").hasArg().argName("bytes")
|
final Option OPT_MAX_ENTRY = Option.builder().longOpt("max-entry-len").hasArg().argName("bytes")
|
||||||
.desc("Max single recipient-entry length (default 1048576)").build();
|
.desc("Max single recipient-entry length (default 1048576)").get();
|
||||||
final Option OPT_NO_SHUFFLE = Option.builder().longOpt("no-shuffle")
|
final Option OPT_NO_SHUFFLE = Option.builder().longOpt("no-shuffle")
|
||||||
.desc("Disable shuffling of recipients (enabled by default)").build();
|
.desc("Disable shuffling of recipients (enabled by default)").get();
|
||||||
|
|
||||||
// ---- recipients (real)
|
// ---- recipients (real)
|
||||||
final Option OPT_TO_ALIAS = Option.builder().longOpt("to-alias").hasArg().argName("alias")
|
final Option OPT_TO_ALIAS = Option.builder().longOpt("to-alias").hasArg().argName("alias")
|
||||||
.desc("Add recipient by alias from keyring (repeatable)").build();
|
.desc("Add recipient by alias from keyring (repeatable)").get();
|
||||||
final Option OPT_TO_PSW = Option.builder().longOpt("to-psw").hasArg().argName("password")
|
final Option OPT_TO_PSW = Option.builder().longOpt("to-psw").hasArg().argName("password")
|
||||||
.desc("Add password recipient (repeatable)").build();
|
.desc("Add password recipient (repeatable)").get();
|
||||||
final Option OPT_PSW_ITER = Option.builder().longOpt("to-iter").hasArg().argName("n")
|
final Option OPT_PSW_ITER = Option.builder().longOpt("to-iter").hasArg().argName("n")
|
||||||
.desc("PBKDF2 iterations for password recipients (default 200000)").build();
|
.desc("PBKDF2 iterations for password recipients (default 200000)").get();
|
||||||
final Option OPT_PSW_SALT = Option.builder().longOpt("to-salt-len").hasArg().argName("bytes")
|
final Option OPT_PSW_SALT = Option.builder().longOpt("to-salt-len").hasArg().argName("bytes")
|
||||||
.desc("PBKDF2 salt length for password recipients (default 16)").build();
|
.desc("PBKDF2 salt length for password recipients (default 16)").get();
|
||||||
final Option OPT_PSW_KEK = Option.builder().longOpt("to-kek-bytes").hasArg().argName("bytes")
|
final Option OPT_PSW_KEK = Option.builder().longOpt("to-kek-bytes").hasArg().argName("bytes")
|
||||||
.desc("Derived KEK length for password recipients (default 32)").build();
|
.desc("Derived KEK length for password recipients (default 32)").get();
|
||||||
|
|
||||||
// ---- decoys (all types)
|
// ---- decoys (all types)
|
||||||
final Option OPT_DECOY_ALIAS = Option.builder().longOpt("decoy-alias").hasArg().argName("alias")
|
final Option OPT_DECOY_ALIAS = Option.builder().longOpt("decoy-alias").hasArg().argName("alias")
|
||||||
.desc("Add a decoy recipient from keyring (repeatable)").build();
|
.desc("Add a decoy recipient from keyring (repeatable)").get();
|
||||||
final Option OPT_DECOY_PSW = Option.builder().longOpt("decoy-psw").hasArg().argName("password")
|
final Option OPT_DECOY_PSW = Option.builder().longOpt("decoy-psw").hasArg().argName("password")
|
||||||
.desc("Add a decoy password recipient (repeatable)").build();
|
.desc("Add a decoy password recipient (repeatable)").get();
|
||||||
final Option OPT_DECOY_PSW_RAND = Option.builder().longOpt("decoy-psw-rand").hasArg().argName("n")
|
final Option OPT_DECOY_PSW_RAND = Option.builder().longOpt("decoy-psw-rand").hasArg().argName("n")
|
||||||
.desc("Add N random decoy password recipients").build();
|
.desc("Add N random decoy password recipients").get();
|
||||||
|
|
||||||
// ---- unlock (decrypt)
|
// ---- unlock (decrypt)
|
||||||
final Option OPT_PRIV_ALIAS = Option.builder().longOpt("priv-alias").hasArg().argName("alias")
|
final Option OPT_PRIV_ALIAS = Option.builder().longOpt("priv-alias").hasArg().argName("alias")
|
||||||
.desc("Unlock with private key from keyring").build();
|
.desc("Unlock with private key from keyring").get();
|
||||||
final Option OPT_PASSWORD = Option.builder("p").longOpt("password").hasArg().argName("password")
|
final Option OPT_PASSWORD = Option.builder("p").longOpt("password").hasArg().argName("password")
|
||||||
.desc("Unlock with password").build();
|
.desc("Unlock with password").get();
|
||||||
|
|
||||||
options.addOptionGroup(OP);
|
options.addOptionGroup(OP);
|
||||||
options.addOption(OPT_OUT);
|
options.addOption(OPT_OUT);
|
||||||
|
|||||||
@@ -113,91 +113,91 @@ public final class Kem { // NOPMD
|
|||||||
|
|
||||||
/** Encrypt mode: -e|--encrypt <input> */
|
/** Encrypt mode: -e|--encrypt <input> */
|
||||||
public static final Option OPT_ENCRYPT = Option.builder("e").longOpt("encrypt").hasArg().argName("input")
|
public static final Option OPT_ENCRYPT = Option.builder("e").longOpt("encrypt").hasArg().argName("input")
|
||||||
.desc("Encrypt the input file").build();
|
.desc("Encrypt the input file").get();
|
||||||
|
|
||||||
/** Decrypt mode: -d|--decrypt <input> */
|
/** Decrypt mode: -d|--decrypt <input> */
|
||||||
public static final Option OPT_DECRYPT = Option.builder("d").longOpt("decrypt").hasArg().argName("input")
|
public static final Option OPT_DECRYPT = Option.builder("d").longOpt("decrypt").hasArg().argName("input")
|
||||||
.desc("Decrypt the input file").build();
|
.desc("Decrypt the input file").get();
|
||||||
|
|
||||||
/** Output path: -o|--output <file> */
|
/** Output path: -o|--output <file> */
|
||||||
public static final Option OPT_OUTPUT = Option.builder("o").longOpt("output").hasArg().argName("file")
|
public static final Option OPT_OUTPUT = Option.builder("o").longOpt("output").hasArg().argName("file")
|
||||||
.desc("Output file path (default: <input>.enc for encrypt, <input>.dec for decrypt)").build();
|
.desc("Output file path (default: <input>.enc for encrypt, <input>.dec for decrypt)").get();
|
||||||
|
|
||||||
/** Keyring path: -K|--keyring <file> */
|
/** Keyring path: -K|--keyring <file> */
|
||||||
public static final Option OPT_KEYRING = Option.builder("K").longOpt("keyring").hasArg().argName("file")
|
public static final Option OPT_KEYRING = Option.builder("K").longOpt("keyring").hasArg().argName("file")
|
||||||
.desc("Path to KeyringStore file").build();
|
.desc("Path to KeyringStore file").get();
|
||||||
|
|
||||||
/** Recipient public alias (encrypt): --pub <alias> */
|
/** Recipient public alias (encrypt): --pub <alias> */
|
||||||
public static final Option OPT_PUB = Option.builder().longOpt("pub").hasArg().argName("alias")
|
public static final Option OPT_PUB = Option.builder().longOpt("pub").hasArg().argName("alias")
|
||||||
.desc("Recipient public key alias (encryption)").build();
|
.desc("Recipient public key alias (encryption)").get();
|
||||||
|
|
||||||
/** Recipient private alias (decrypt): --priv <alias> */
|
/** Recipient private alias (decrypt): --priv <alias> */
|
||||||
public static final Option OPT_PRIV = Option.builder().longOpt("priv").hasArg().argName("alias")
|
public static final Option OPT_PRIV = Option.builder().longOpt("priv").hasArg().argName("alias")
|
||||||
.desc("Recipient private key alias (decryption)").build();
|
.desc("Recipient private key alias (decryption)").get();
|
||||||
|
|
||||||
/** KEM id: --kem <id> */
|
/** KEM id: --kem <id> */
|
||||||
public static final Option OPT_KEM = Option.builder().longOpt("kem").hasArg().argName("id")
|
public static final Option OPT_KEM = Option.builder().longOpt("kem").hasArg().argName("id")
|
||||||
.desc("KEM algorithm id (see --list-kems)").build();
|
.desc("KEM algorithm id (see --list-kems)").get();
|
||||||
|
|
||||||
/** Discovery: --list-kems */
|
/** Discovery: --list-kems */
|
||||||
public static final Option OPT_LIST_KEMS = Option.builder().longOpt("list-kems")
|
public static final Option OPT_LIST_KEMS = Option.builder().longOpt("list-kems")
|
||||||
.desc("List KEM algorithms that support ENCAPSULATE and DECAPSULATE and exit").build();
|
.desc("List KEM algorithms that support ENCAPSULATE and DECAPSULATE and exit").get();
|
||||||
|
|
||||||
/** Payload switch: --aes */
|
/** Payload switch: --aes */
|
||||||
public static final Option OPT_AES = Option.builder().longOpt("aes")
|
public static final Option OPT_AES = Option.builder().longOpt("aes")
|
||||||
.desc("Use AES payload (select mode via --aes-cipher)").build();
|
.desc("Use AES payload (select mode via --aes-cipher)").get();
|
||||||
|
|
||||||
/** Payload switch: --chacha */
|
/** Payload switch: --chacha */
|
||||||
public static final Option OPT_CHACHA = Option.builder().longOpt("chacha")
|
public static final Option OPT_CHACHA = Option.builder().longOpt("chacha")
|
||||||
.desc("Use ChaCha payload (AEAD if --aad is provided, otherwise stream)").build();
|
.desc("Use ChaCha payload (AEAD if --aad is provided, otherwise stream)").get();
|
||||||
|
|
||||||
/** AAD (hex): --aad <hex> */
|
/** AAD (hex): --aad <hex> */
|
||||||
public static final Option OPT_AAD = Option.builder().longOpt("aad").hasArg().argName("hex")
|
public static final Option OPT_AAD = Option.builder().longOpt("aad").hasArg().argName("hex")
|
||||||
.desc("Additional Authenticated Data (hex)").build();
|
.desc("Additional Authenticated Data (hex)").get();
|
||||||
|
|
||||||
/** Header toggle: --header */
|
/** Header toggle: --header */
|
||||||
public static final Option OPT_HEADER = Option.builder().longOpt("header")
|
public static final Option OPT_HEADER = Option.builder().longOpt("header")
|
||||||
.desc("Write/read a compact symmetric header (IV/AAD/params) when supported").build();
|
.desc("Write/read a compact symmetric header (IV/AAD/params) when supported").get();
|
||||||
|
|
||||||
/** HKDF: --hkdf [infoHex] */
|
/** HKDF: --hkdf [infoHex] */
|
||||||
public static final Option OPT_HKDF = Option.builder().longOpt("hkdf").optionalArg(true).hasArg().argName("infoHex")
|
public static final Option OPT_HKDF = Option.builder().longOpt("hkdf").optionalArg(true).hasArg().argName("infoHex")
|
||||||
.desc("Use HKDF-SHA256 for KEM secret; optional info as hex (default internal info)").build();
|
.desc("Use HKDF-SHA256 for KEM secret; optional info as hex (default internal info)").get();
|
||||||
|
|
||||||
/** Direct secret: --direct */
|
/** Direct secret: --direct */
|
||||||
public static final Option OPT_DIRECT = Option.builder().longOpt("direct")
|
public static final Option OPT_DIRECT = Option.builder().longOpt("direct")
|
||||||
.desc("Use the raw KEM shared secret directly (disable HKDF)").build();
|
.desc("Use the raw KEM shared secret directly (disable HKDF)").get();
|
||||||
|
|
||||||
/** Derived key bytes: --key-bytes <int> */
|
/** Derived key bytes: --key-bytes <int> */
|
||||||
public static final Option OPT_KEY_BYTES = Option.builder().longOpt("key-bytes").hasArg().argName("int")
|
public static final Option OPT_KEY_BYTES = Option.builder().longOpt("key-bytes").hasArg().argName("int")
|
||||||
.type(Number.class).desc("Derived symmetric key length in bytes (default 32)").build();
|
.type(Number.class).desc("Derived symmetric key length in bytes (default 32)").get();
|
||||||
|
|
||||||
/** Max KEM ciphertext len: --max-kem-ct <int> */
|
/** Max KEM ciphertext len: --max-kem-ct <int> */
|
||||||
public static final Option OPT_MAX_KEM_CT = Option.builder().longOpt("max-kem-ct").hasArg().argName("int")
|
public static final Option OPT_MAX_KEM_CT = Option.builder().longOpt("max-kem-ct").hasArg().argName("int")
|
||||||
.type(Number.class).desc("Maximum accepted KEM ciphertext length in bytes (default 65536)").build();
|
.type(Number.class).desc("Maximum accepted KEM ciphertext length in bytes (default 65536)").get();
|
||||||
|
|
||||||
/** AES mode: --aes-cipher gcm|ctr|cbc */
|
/** AES mode: --aes-cipher gcm|ctr|cbc */
|
||||||
public static final Option OPT_AES_CIPHER = Option.builder().longOpt("aes-cipher").hasArg().argName("gcm|ctr|cbc")
|
public static final Option OPT_AES_CIPHER = Option.builder().longOpt("aes-cipher").hasArg().argName("gcm|ctr|cbc")
|
||||||
.desc("AES cipher variant for payload (default gcm)").build();
|
.desc("AES cipher variant for payload (default gcm)").get();
|
||||||
|
|
||||||
/** AES IV: --aes-iv <hex> */
|
/** AES IV: --aes-iv <hex> */
|
||||||
public static final Option OPT_AES_IV = Option.builder().longOpt("aes-iv").hasArg().argName("hex")
|
public static final Option OPT_AES_IV = Option.builder().longOpt("aes-iv").hasArg().argName("hex")
|
||||||
.desc("AES IV/nonce (hex)").build();
|
.desc("AES IV/nonce (hex)").get();
|
||||||
|
|
||||||
/** AES tag bits: --aes-tag-bits <int> */
|
/** AES tag bits: --aes-tag-bits <int> */
|
||||||
public static final Option OPT_AES_TAG_BITS = Option.builder().longOpt("aes-tag-bits").hasArg().argName("int")
|
public static final Option OPT_AES_TAG_BITS = Option.builder().longOpt("aes-tag-bits").hasArg().argName("int")
|
||||||
.type(Number.class).desc("AES-GCM authentication tag length in bits (default 128)").build();
|
.type(Number.class).desc("AES-GCM authentication tag length in bits (default 128)").get();
|
||||||
|
|
||||||
/** ChaCha nonce: --chacha-nonce <hex> */
|
/** ChaCha nonce: --chacha-nonce <hex> */
|
||||||
public static final Option OPT_CHACHA_NONCE = Option.builder().longOpt("chacha-nonce").hasArg().argName("hex")
|
public static final Option OPT_CHACHA_NONCE = Option.builder().longOpt("chacha-nonce").hasArg().argName("hex")
|
||||||
.desc("ChaCha nonce (hex, usually 12 bytes)").build();
|
.desc("ChaCha nonce (hex, usually 12 bytes)").get();
|
||||||
|
|
||||||
/** ChaCha counter value: --chacha-counter <int> */
|
/** ChaCha counter value: --chacha-counter <int> */
|
||||||
public static final Option OPT_CHACHA_COUNTER = Option.builder().longOpt("chacha-counter").hasArg().argName("int")
|
public static final Option OPT_CHACHA_COUNTER = Option.builder().longOpt("chacha-counter").hasArg().argName("int")
|
||||||
.type(Number.class).desc("ChaCha counter value for stream mode (integer)").build();
|
.type(Number.class).desc("ChaCha counter value for stream mode (integer)").get();
|
||||||
|
|
||||||
/** ChaCha initial counter: --chacha-initial <int> */
|
/** ChaCha initial counter: --chacha-initial <int> */
|
||||||
public static final Option OPT_CHACHA_INITIAL = Option.builder().longOpt("chacha-initial").hasArg().argName("int")
|
public static final Option OPT_CHACHA_INITIAL = Option.builder().longOpt("chacha-initial").hasArg().argName("int")
|
||||||
.type(Number.class).desc("ChaCha initial counter (integer)").build();
|
.type(Number.class).desc("ChaCha initial counter (integer)").get();
|
||||||
|
|
||||||
private Kem() {
|
private Kem() {
|
||||||
// no instances
|
// no instances
|
||||||
|
|||||||
@@ -167,49 +167,49 @@ public final class KeyStoreManagement { // NOPMD
|
|||||||
// ---------------------------------------------------------------------
|
// ---------------------------------------------------------------------
|
||||||
|
|
||||||
private static final Option KEYSTORE_OPTION = Option.builder("k").longOpt("keystore").hasArg().argName("file")
|
private static final Option KEYSTORE_OPTION = Option.builder("k").longOpt("keystore").hasArg().argName("file")
|
||||||
.desc("Path to keyring store").build();
|
.desc("Path to keyring store").get();
|
||||||
|
|
||||||
private static final Option LIST_ALGORITHMS_OPTION = Option.builder().longOpt("list-algorithms")
|
private static final Option LIST_ALGORITHMS_OPTION = Option.builder().longOpt("list-algorithms")
|
||||||
.desc("List catalog algorithms with symmetric/asymmetric support").build();
|
.desc("List catalog algorithms with symmetric/asymmetric support").get();
|
||||||
|
|
||||||
private static final Option LIST_ALIASES_OPTION = Option.builder().longOpt("list-aliases")
|
private static final Option LIST_ALIASES_OPTION = Option.builder().longOpt("list-aliases")
|
||||||
.desc("List aliases present in the keyring").build();
|
.desc("List aliases present in the keyring").get();
|
||||||
|
|
||||||
private static final Option GENERATE_OPTION = Option.builder().longOpt("generate")
|
private static final Option GENERATE_OPTION = Option.builder().longOpt("generate")
|
||||||
.desc("Generate a keypair or a secret").build();
|
.desc("Generate a keypair or a secret").get();
|
||||||
|
|
||||||
private static final Option ALG_OPTION = Option.builder().longOpt("alg").hasArg().argName("id")
|
private static final Option ALG_OPTION = Option.builder().longOpt("alg").hasArg().argName("id")
|
||||||
.desc("Algorithm id (e.g., RSA, Ed25519, AES, Frodo)").build();
|
.desc("Algorithm id (e.g., RSA, Ed25519, AES, Frodo)").get();
|
||||||
|
|
||||||
private static final Option ALIAS_OPTION = Option.builder().longOpt("alias").hasArg().argName("name")
|
private static final Option ALIAS_OPTION = Option.builder().longOpt("alias").hasArg().argName("name")
|
||||||
.desc("Alias base; for asymmetric, two entries will be written").build();
|
.desc("Alias base; for asymmetric, two entries will be written").get();
|
||||||
|
|
||||||
private static final Option KIND_OPTION = Option.builder().longOpt("kind").hasArg().argName("sym|asym")
|
private static final Option KIND_OPTION = Option.builder().longOpt("kind").hasArg().argName("sym|asym")
|
||||||
.desc("Force symmetric or asymmetric when algorithm supports both").build();
|
.desc("Force symmetric or asymmetric when algorithm supports both").get();
|
||||||
|
|
||||||
private static final Option PUB_SUFFIX_OPTION = Option.builder().longOpt("pub-suffix").hasArg().argName("sfx")
|
private static final Option PUB_SUFFIX_OPTION = Option.builder().longOpt("pub-suffix").hasArg().argName("sfx")
|
||||||
.desc("Suffix for public alias (default .pub)").build();
|
.desc("Suffix for public alias (default .pub)").get();
|
||||||
|
|
||||||
private static final Option PRV_SUFFIX_OPTION = Option.builder().longOpt("prv-suffix").hasArg().argName("sfx")
|
private static final Option PRV_SUFFIX_OPTION = Option.builder().longOpt("prv-suffix").hasArg().argName("sfx")
|
||||||
.desc("Suffix for private alias (default .prv)").build();
|
.desc("Suffix for private alias (default .prv)").get();
|
||||||
|
|
||||||
private static final Option OVERWRITE_OPTION = Option.builder().longOpt("overwrite")
|
private static final Option OVERWRITE_OPTION = Option.builder().longOpt("overwrite")
|
||||||
.desc("Overwrite existing aliases on conflict").build();
|
.desc("Overwrite existing aliases on conflict").get();
|
||||||
|
|
||||||
private static final Option EXPORT_OPTION = Option.builder().longOpt("export")
|
private static final Option EXPORT_OPTION = Option.builder().longOpt("export")
|
||||||
.desc("Export selected aliases as a versioned text snippet").build();
|
.desc("Export selected aliases as a versioned text snippet").get();
|
||||||
|
|
||||||
private static final Option IMPORT_OPTION = Option.builder().longOpt("import")
|
private static final Option IMPORT_OPTION = Option.builder().longOpt("import")
|
||||||
.desc("Import a versioned text snippet into the keyring").build();
|
.desc("Import a versioned text snippet into the keyring").get();
|
||||||
|
|
||||||
private static final Option ALIASES_OPTION = Option.builder().longOpt("aliases").hasArg().argName("a,b,c")
|
private static final Option ALIASES_OPTION = Option.builder().longOpt("aliases").hasArg().argName("a,b,c")
|
||||||
.desc("Comma-separated aliases to export; empty means all").build();
|
.desc("Comma-separated aliases to export; empty means all").get();
|
||||||
|
|
||||||
private static final Option OUTFILE_OPTION = Option.builder().longOpt("out").hasArg().argName("file|-")
|
private static final Option OUTFILE_OPTION = Option.builder().longOpt("out").hasArg().argName("file|-")
|
||||||
.desc("Output file for export (default '-' for stdout)").build();
|
.desc("Output file for export (default '-' for stdout)").get();
|
||||||
|
|
||||||
private static final Option INFILE_OPTION = Option.builder().longOpt("in").hasArg().argName("file|-")
|
private static final Option INFILE_OPTION = Option.builder().longOpt("in").hasArg().argName("file|-")
|
||||||
.desc("Input file for import (default '-' for stdin)").build();
|
.desc("Input file for import (default '-' for stdin)").get();
|
||||||
|
|
||||||
/** Prevents instantiation. */
|
/** Prevents instantiation. */
|
||||||
private KeyStoreManagement() {
|
private KeyStoreManagement() {
|
||||||
|
|||||||
@@ -48,10 +48,10 @@ import java.util.Objects;
|
|||||||
|
|
||||||
import org.apache.commons.cli.CommandLine;
|
import org.apache.commons.cli.CommandLine;
|
||||||
import org.apache.commons.cli.DefaultParser;
|
import org.apache.commons.cli.DefaultParser;
|
||||||
import org.apache.commons.cli.HelpFormatter;
|
|
||||||
import org.apache.commons.cli.Option;
|
import org.apache.commons.cli.Option;
|
||||||
import org.apache.commons.cli.Options;
|
import org.apache.commons.cli.Options;
|
||||||
import org.apache.commons.cli.ParseException;
|
import org.apache.commons.cli.ParseException;
|
||||||
|
import org.apache.commons.cli.help.HelpFormatter;
|
||||||
|
|
||||||
import zeroecho.core.alg.digest.DigestSpec;
|
import zeroecho.core.alg.digest.DigestSpec;
|
||||||
import zeroecho.core.err.VerificationException;
|
import zeroecho.core.err.VerificationException;
|
||||||
@@ -103,28 +103,28 @@ public final class Tag { // NOPMD
|
|||||||
|
|
||||||
// ---- All options as constants
|
// ---- All options as constants
|
||||||
private static final Option TYPE_OPT = Option.builder().longOpt("type").hasArg().argName("signature|digest")
|
private static final Option TYPE_OPT = Option.builder().longOpt("type").hasArg().argName("signature|digest")
|
||||||
.desc("tag primitive type").build();
|
.desc("tag primitive type").get();
|
||||||
|
|
||||||
private static final Option MODE_OPT = Option.builder().longOpt("mode").hasArg().argName("produce|verify")
|
private static final Option MODE_OPT = Option.builder().longOpt("mode").hasArg().argName("produce|verify")
|
||||||
.desc("operation mode").build();
|
.desc("operation mode").get();
|
||||||
|
|
||||||
private static final Option ALG_OPT = Option.builder().longOpt("alg").hasArg().argName("id")
|
private static final Option ALG_OPT = Option.builder().longOpt("alg").hasArg().argName("id")
|
||||||
.desc("algorithm id (signature: Ed25519/Ed448/ECDSA/RSA; digest: SHA-256/.../SHAKE256:N)").build();
|
.desc("algorithm id (signature: Ed25519/Ed448/ECDSA/RSA; digest: SHA-256/.../SHAKE256:N)").get();
|
||||||
|
|
||||||
private static final Option KS_OPT = Option.builder().longOpt("ks").hasArg().argName("file")
|
private static final Option KS_OPT = Option.builder().longOpt("ks").hasArg().argName("file")
|
||||||
.desc("keyring file (required for signature)").build();
|
.desc("keyring file (required for signature)").get();
|
||||||
|
|
||||||
private static final Option PRIV_OPT = Option.builder().longOpt("priv").hasArg().argName("alias")
|
private static final Option PRIV_OPT = Option.builder().longOpt("priv").hasArg().argName("alias")
|
||||||
.desc("private key alias (signature + produce)").build();
|
.desc("private key alias (signature + produce)").get();
|
||||||
|
|
||||||
private static final Option PUB_OPT = Option.builder().longOpt("pub").hasArg().argName("alias")
|
private static final Option PUB_OPT = Option.builder().longOpt("pub").hasArg().argName("alias")
|
||||||
.desc("public key alias (signature + verify)").build();
|
.desc("public key alias (signature + verify)").get();
|
||||||
|
|
||||||
private static final Option IN_OPT = Option.builder().longOpt("in").hasArg().argName("file|-")
|
private static final Option IN_OPT = Option.builder().longOpt("in").hasArg().argName("file|-")
|
||||||
.desc("input file or - for STDIN").build();
|
.desc("input file or - for STDIN").get();
|
||||||
|
|
||||||
private static final Option OUT_OPT = Option.builder().longOpt("out").hasArg().argName("file|-")
|
private static final Option OUT_OPT = Option.builder().longOpt("out").hasArg().argName("file|-")
|
||||||
.desc("output file or - for STDOUT").build();
|
.desc("output file or - for STDOUT").get();
|
||||||
|
|
||||||
// ---- Allowed values and defaults (no enums)
|
// ---- Allowed values and defaults (no enums)
|
||||||
private static final String TYPE_SIGNATURE = "signature";
|
private static final String TYPE_SIGNATURE = "signature";
|
||||||
@@ -172,7 +172,7 @@ public final class Tag { // NOPMD
|
|||||||
|
|
||||||
if (!has(cli, TYPE_OPT) || !has(cli, MODE_OPT) || !has(cli, ALG_OPT) || !has(cli, IN_OPT)
|
if (!has(cli, TYPE_OPT) || !has(cli, MODE_OPT) || !has(cli, ALG_OPT) || !has(cli, IN_OPT)
|
||||||
|| !has(cli, OUT_OPT)) {
|
|| !has(cli, OUT_OPT)) {
|
||||||
new HelpFormatter().printHelp("zeroecho -T [options]", opts);
|
HelpFormatter.builder().get().printHelp("zeroecho -T [options]", "", opts, "", false);
|
||||||
return 2;
|
return 2;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -41,12 +41,12 @@ import java.util.logging.Logger;
|
|||||||
|
|
||||||
import org.apache.commons.cli.CommandLineParser;
|
import org.apache.commons.cli.CommandLineParser;
|
||||||
import org.apache.commons.cli.DefaultParser;
|
import org.apache.commons.cli.DefaultParser;
|
||||||
import org.apache.commons.cli.HelpFormatter;
|
|
||||||
import org.apache.commons.cli.MissingOptionException;
|
import org.apache.commons.cli.MissingOptionException;
|
||||||
import org.apache.commons.cli.Option;
|
import org.apache.commons.cli.Option;
|
||||||
import org.apache.commons.cli.OptionGroup;
|
import org.apache.commons.cli.OptionGroup;
|
||||||
import org.apache.commons.cli.Options;
|
import org.apache.commons.cli.Options;
|
||||||
import org.apache.commons.cli.ParseException;
|
import org.apache.commons.cli.ParseException;
|
||||||
|
import org.apache.commons.cli.help.HelpFormatter;
|
||||||
|
|
||||||
import zeroecho.sdk.util.BouncyCastleActivator;
|
import zeroecho.sdk.util.BouncyCastleActivator;
|
||||||
|
|
||||||
@@ -98,8 +98,9 @@ public final class ZeroEcho {
|
|||||||
* prints the help message.
|
* prints the help message.
|
||||||
*
|
*
|
||||||
* @param args command-line arguments passed to the program
|
* @param args command-line arguments passed to the program
|
||||||
|
* @throws IOException If the output could not be written
|
||||||
*/
|
*/
|
||||||
public static void main(final String[] args) {
|
public static void main(final String[] args) throws IOException {
|
||||||
final int errorCode = mainProcess(args);
|
final int errorCode = mainProcess(args);
|
||||||
|
|
||||||
if (errorCode == 0) {
|
if (errorCode == 0) {
|
||||||
@@ -116,15 +117,16 @@ public final class ZeroEcho {
|
|||||||
*
|
*
|
||||||
* @param args command-line arguments passed to the program
|
* @param args command-line arguments passed to the program
|
||||||
* @return error-code
|
* @return error-code
|
||||||
|
* @throws IOException If the output could not be written
|
||||||
*/
|
*/
|
||||||
public static int mainProcess(final String... args) {
|
public static int mainProcess(final String... args) throws IOException {
|
||||||
final Option KEM_OPTION = Option.builder("E").longOpt("kem").desc("KEM encryption/decryption").build();
|
final Option KEM_OPTION = Option.builder("E").longOpt("kem").desc("KEM encryption/decryption").get();
|
||||||
final Option GUARD_OPTION = Option.builder("G").longOpt("guard")
|
final Option GUARD_OPTION = Option.builder("G").longOpt("guard")
|
||||||
.desc("multi-recipient encryption/decryption (keys+passwords), AES/ChaCha").build();
|
.desc("multi-recipient encryption/decryption (keys+passwords), AES/ChaCha").get();
|
||||||
final Option KEYSTORE_OPTION = Option.builder("K").longOpt("ksm").desc("key store management").build();
|
final Option KEYSTORE_OPTION = Option.builder("K").longOpt("ksm").desc("key store management").get();
|
||||||
final Option COVERT_OPTION = Option.builder("C").longOpt("covert").desc("covert channel processing").build();
|
final Option COVERT_OPTION = Option.builder("C").longOpt("covert").desc("covert channel processing").get();
|
||||||
final Option TAG_OPTION = Option.builder("T").longOpt("tag")
|
final Option TAG_OPTION = Option.builder("T").longOpt("tag")
|
||||||
.desc("tag subcommand (signature/digest; produce/verify)").build();
|
.desc("tag subcommand (signature/digest; produce/verify)").get();
|
||||||
|
|
||||||
final OptionGroup OPERATION_GROUP = new OptionGroup();
|
final OptionGroup OPERATION_GROUP = new OptionGroup();
|
||||||
OPERATION_GROUP.addOption(GUARD_OPTION);
|
OPERATION_GROUP.addOption(GUARD_OPTION);
|
||||||
@@ -186,12 +188,12 @@ public final class ZeroEcho {
|
|||||||
* @param options The {@link Options} instance defining the available
|
* @param options The {@link Options} instance defining the available
|
||||||
* command-line options.
|
* command-line options.
|
||||||
* @return always {@code 1}
|
* @return always {@code 1}
|
||||||
|
* @throws IOException If the output could not be written
|
||||||
*/
|
*/
|
||||||
private static int help(final Options options) {
|
private static int help(final Options options) throws IOException {
|
||||||
// automatically generate the help statement
|
// automatically generate the help statement
|
||||||
final HelpFormatter formatter = new HelpFormatter();
|
final HelpFormatter formatter = HelpFormatter.builder().get();
|
||||||
formatter.setWidth(80);
|
formatter.printHelp(ZeroEcho.class.getName(), "", options, "", false);
|
||||||
formatter.printHelp(ZeroEcho.class.getName(), options);
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -36,12 +36,14 @@ package zeroecho;
|
|||||||
|
|
||||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
import org.junit.jupiter.api.Test;
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
class ZeroEchoTest {
|
class ZeroEchoTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAsymetricOptionWithoutParamsReturnsOne() {
|
void testAsymetricOptionWithoutParamsReturnsOne() throws IOException {
|
||||||
System.out.println("testAsymetricOptionWithoutParamsReturnsOne");
|
System.out.println("testAsymetricOptionWithoutParamsReturnsOne");
|
||||||
int result = ZeroEcho.mainProcess(new String[] { "-A" });
|
int result = ZeroEcho.mainProcess(new String[] { "-A" });
|
||||||
assertEquals(1, result, "Asymetric option without parameters should return 1 (error/help)");
|
assertEquals(1, result, "Asymetric option without parameters should return 1 (error/help)");
|
||||||
@@ -49,7 +51,7 @@ class ZeroEchoTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testAesPswOptionWithoutParamsReturnsOne() {
|
void testAesPswOptionWithoutParamsReturnsOne() throws IOException {
|
||||||
System.out.println("testAesPswOptionWithoutParamsReturnsOne");
|
System.out.println("testAesPswOptionWithoutParamsReturnsOne");
|
||||||
int result = ZeroEcho.mainProcess(new String[] { "-P" });
|
int result = ZeroEcho.mainProcess(new String[] { "-P" });
|
||||||
assertEquals(1, result, "AES-PSW option without parameters should return 1 (error/help)");
|
assertEquals(1, result, "AES-PSW option without parameters should return 1 (error/help)");
|
||||||
@@ -57,7 +59,7 @@ class ZeroEchoTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testNoOptionReturnsOne() {
|
void testNoOptionReturnsOne() throws IOException {
|
||||||
System.out.println("testNoOptionReturnsOne");
|
System.out.println("testNoOptionReturnsOne");
|
||||||
int result = ZeroEcho.mainProcess(new String[] {});
|
int result = ZeroEcho.mainProcess(new String[] {});
|
||||||
assertEquals(1, result, "No options should return 1 (error/help)");
|
assertEquals(1, result, "No options should return 1 (error/help)");
|
||||||
@@ -65,7 +67,7 @@ class ZeroEchoTest {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
void testInvalidOptionReturnsOne() {
|
void testInvalidOptionReturnsOne() throws IOException {
|
||||||
System.out.println("testInvalidOptionReturnsOne");
|
System.out.println("testInvalidOptionReturnsOne");
|
||||||
int result = ZeroEcho.mainProcess(new String[] { "-X" });
|
int result = ZeroEcho.mainProcess(new String[] { "-X" });
|
||||||
assertEquals(1, result, "Invalid option should return 1 (error/help)");
|
assertEquals(1, result, "Invalid option should return 1 (error/help)");
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ dependencies {
|
|||||||
|
|
||||||
pmd {
|
pmd {
|
||||||
consoleOutput = true
|
consoleOutput = true
|
||||||
toolVersion = '7.19.0'
|
toolVersion = '7.20.0'
|
||||||
sourceSets = [sourceSets.main]
|
sourceSets = [sourceSets.main]
|
||||||
ruleSetFiles = files(rootProject.file(".ruleset"))
|
ruleSetFiles = files(rootProject.file(".ruleset"))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -48,10 +48,9 @@ import zeroecho.core.spi.AsymmetricKeyBuilder;
|
|||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
* This builder maps {@link SlhDsaKeyGenSpec} to the appropriate
|
* This builder maps {@link SlhDsaKeyGenSpec} to the appropriate
|
||||||
* {@code org.bouncycastle.jcajce.spec.SLHDSAParameterSpec} constant.
|
* {@code org.bouncycastle.jcajce.spec.SLHDSAParameterSpec} constant. Reflection
|
||||||
* :contentReference[oaicite:3]{index=3} Reflection is used to avoid a hard
|
* is used to avoid a hard dependency on any particular set of parameter
|
||||||
* dependency on any particular set of parameter constants across provider
|
* constants across provider versions.
|
||||||
* versions.
|
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @since 1.0
|
* @since 1.0
|
||||||
@@ -103,7 +102,6 @@ public final class SlhDsaKeyGenBuilder implements AsymmetricKeyBuilder<SlhDsaKey
|
|||||||
|
|
||||||
// Optional pre-hash suffix used by BC:
|
// Optional pre-hash suffix used by BC:
|
||||||
// _with_sha256/_with_sha512/_with_shake128/_with_shake256
|
// _with_sha256/_with_sha512/_with_shake128/_with_shake256
|
||||||
// :contentReference[oaicite:4]{index=4}
|
|
||||||
String suffix = "";
|
String suffix = "";
|
||||||
if (spec.preHash() != SlhDsaKeyGenSpec.PreHash.NONE) {
|
if (spec.preHash() != SlhDsaKeyGenSpec.PreHash.NONE) {
|
||||||
suffix = "_with_" + spec.preHash().name().toLowerCase(Locale.ROOT);
|
suffix = "_with_" + spec.preHash().name().toLowerCase(Locale.ROOT);
|
||||||
|
|||||||
@@ -106,7 +106,6 @@ public final class SlhDsaKeyGenSpec implements AlgorithmKeySpec {
|
|||||||
* <p>
|
* <p>
|
||||||
* Bouncy Castle exposes "with hash" variants as distinct parameter specs, for
|
* Bouncy Castle exposes "with hash" variants as distinct parameter specs, for
|
||||||
* example {@code slh_dsa_sha2_128s_with_sha256}.
|
* example {@code slh_dsa_sha2_128s_with_sha256}.
|
||||||
* :contentReference[oaicite:1]{index=1}
|
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* <p>
|
* <p>
|
||||||
@@ -183,7 +182,6 @@ public final class SlhDsaKeyGenSpec implements AlgorithmKeySpec {
|
|||||||
* <p>
|
* <p>
|
||||||
* This bypasses automatic mapping. The name must match a static field in
|
* This bypasses automatic mapping. The name must match a static field in
|
||||||
* {@code org.bouncycastle.jcajce.spec.SLHDSAParameterSpec}.
|
* {@code org.bouncycastle.jcajce.spec.SLHDSAParameterSpec}.
|
||||||
* :contentReference[oaicite:2]{index=2}
|
|
||||||
* </p>
|
* </p>
|
||||||
*
|
*
|
||||||
* @param name field name in {@code SLHDSAParameterSpec}
|
* @param name field name in {@code SLHDSAParameterSpec}
|
||||||
|
|||||||
@@ -103,10 +103,10 @@ public class ByteVerificationStrategy extends VerificationBiPredicate<byte[]> {
|
|||||||
|
|
||||||
if (LOG.isLoggable(Level.FINE)) {
|
if (LOG.isLoggable(Level.FINE)) {
|
||||||
if (r == 0) {
|
if (r == 0) {
|
||||||
LOG.log(Level.FINE, "PASS {0} == {1}", // NOPMD
|
LOG.log(Level.FINE, "PASS {0} == {1}",
|
||||||
new Object[] { Strings.toShortString(a), Strings.toShortString(b) });
|
new Object[] { Strings.toShortString(a), Strings.toShortString(b) });
|
||||||
} else {
|
} else {
|
||||||
LOG.log(Level.FINE, "FAIL {0} != {1}", // NOPMD
|
LOG.log(Level.FINE, "FAIL {0} != {1}",
|
||||||
new Object[] { Strings.toShortString(a), Strings.toShortString(b) });
|
new Object[] { Strings.toShortString(a), Strings.toShortString(b) });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -103,9 +103,9 @@ public class SignatureVerificationStrategy extends VerificationBiPredicate<Signa
|
|||||||
|
|
||||||
if (LOG.isLoggable(Level.FINE)) {
|
if (LOG.isLoggable(Level.FINE)) {
|
||||||
if (result) {
|
if (result) {
|
||||||
LOG.log(Level.FINE, "PASS {0}", Strings.toShortString(b)); // NOPMD
|
LOG.log(Level.FINE, "PASS {0}", Strings.toShortString(b));
|
||||||
} else {
|
} else {
|
||||||
LOG.log(Level.FINE, "FAIL {0}", Strings.toShortString(b)); // NOPMD
|
LOG.log(Level.FINE, "FAIL {0}", Strings.toShortString(b));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -120,16 +120,7 @@ public final class MldsaLargeDataTest {
|
|||||||
|
|
||||||
KeyPair kp = CryptoAlgorithms.keyPair("ML-DSA", spec);
|
KeyPair kp = CryptoAlgorithms.keyPair("ML-DSA", spec);
|
||||||
|
|
||||||
SignatureContext verifierCtx = CryptoAlgorithms.create("ML-DSA", KeyUsage.VERIFY, kp.getPublic());
|
SignatureContext mldsaVerifier = CryptoAlgorithms.create("ML-DSA", KeyUsage.VERIFY, kp.getPublic());
|
||||||
if (!(verifierCtx instanceof MldsaSignatureContext mldsaVerifier)) {
|
|
||||||
try {
|
|
||||||
verifierCtx.close();
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
}
|
|
||||||
throw new AssertionError(
|
|
||||||
"VERIFY context must be MldsaSignatureContext, got: " + verifierCtx.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
int expectedSigLen = mldsaVerifier.tagLength();
|
int expectedSigLen = mldsaVerifier.tagLength();
|
||||||
System.out.println(INDENT + " expectedSigLen=" + expectedSigLen);
|
System.out.println(INDENT + " expectedSigLen=" + expectedSigLen);
|
||||||
|
|
||||||
@@ -188,15 +179,7 @@ public final class MldsaLargeDataTest {
|
|||||||
byte[] badSig = Arrays.copyOf(signature, signature.length);
|
byte[] badSig = Arrays.copyOf(signature, signature.length);
|
||||||
badSig[0] = (byte) (badSig[0] ^ 0x01);
|
badSig[0] = (byte) (badSig[0] ^ 0x01);
|
||||||
|
|
||||||
SignatureContext badVerifierCtx = CryptoAlgorithms.create("ML-DSA", KeyUsage.VERIFY, kp.getPublic());
|
SignatureContext badVerifier = CryptoAlgorithms.create("ML-DSA", KeyUsage.VERIFY, kp.getPublic());
|
||||||
if (!(badVerifierCtx instanceof MldsaSignatureContext badVerifier)) {
|
|
||||||
try {
|
|
||||||
badVerifierCtx.close();
|
|
||||||
} catch (Exception ignore) {
|
|
||||||
}
|
|
||||||
throw new AssertionError("VERIFY context must be MldsaSignatureContext (negative), got: "
|
|
||||||
+ badVerifierCtx.getClass().getName());
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
badVerifier.setExpectedTag(badSig);
|
badVerifier.setExpectedTag(badSig);
|
||||||
|
|||||||
32
pki/.classpath
Normal file
32
pki/.classpath
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<classpath>
|
||||||
|
<classpathentry kind="src" output="bin/main" path="src/main/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="gradle_scope" value="main"/>
|
||||||
|
<attribute name="gradle_used_by_scope" value="main,test"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="src" output="bin/main" path="src/main/resources">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="gradle_scope" value="main"/>
|
||||||
|
<attribute name="gradle_used_by_scope" value="main,test"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="src" output="bin/test" path="src/test/java">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="gradle_scope" value="test"/>
|
||||||
|
<attribute name="gradle_used_by_scope" value="test"/>
|
||||||
|
<attribute name="test" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="src" output="bin/test" path="src/test/resources">
|
||||||
|
<attributes>
|
||||||
|
<attribute name="gradle_scope" value="test"/>
|
||||||
|
<attribute name="gradle_used_by_scope" value="test"/>
|
||||||
|
<attribute name="test" value="true"/>
|
||||||
|
</attributes>
|
||||||
|
</classpathentry>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-21/"/>
|
||||||
|
<classpathentry kind="con" path="org.eclipse.buildship.core.gradleclasspathcontainer"/>
|
||||||
|
<classpathentry kind="output" path="bin/default"/>
|
||||||
|
</classpath>
|
||||||
23
pki/.project
Normal file
23
pki/.project
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<projectDescription>
|
||||||
|
<name>pki</name>
|
||||||
|
<comment>Project pki created by Buildship.</comment>
|
||||||
|
<projects>
|
||||||
|
</projects>
|
||||||
|
<buildSpec>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.jdt.core.javabuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
<buildCommand>
|
||||||
|
<name>org.eclipse.buildship.core.gradleprojectbuilder</name>
|
||||||
|
<arguments>
|
||||||
|
</arguments>
|
||||||
|
</buildCommand>
|
||||||
|
</buildSpec>
|
||||||
|
<natures>
|
||||||
|
<nature>org.eclipse.jdt.core.javanature</nature>
|
||||||
|
<nature>org.eclipse.buildship.core.gradleprojectnature</nature>
|
||||||
|
</natures>
|
||||||
|
</projectDescription>
|
||||||
31
pki/LICENSE
Normal file
31
pki/LICENSE
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
Copyright (C) 2025, Leo Galambos
|
||||||
|
All rights reserved.
|
||||||
|
|
||||||
|
Redistribution and use in source and binary forms, with or without modification,
|
||||||
|
are permitted provided that the following conditions are met:
|
||||||
|
|
||||||
|
1. Redistributions of source code must retain the above copyright notice, this
|
||||||
|
list of conditions and the following disclaimer.
|
||||||
|
|
||||||
|
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
this list of conditions and the following disclaimer in the documentation
|
||||||
|
and/or other materials provided with the distribution.
|
||||||
|
|
||||||
|
3. All advertising materials mentioning features or use of this software must
|
||||||
|
display the following acknowledgement:
|
||||||
|
This product includes software developed by the Egothor project.
|
||||||
|
|
||||||
|
4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
may be used to endorse or promote products derived from this software without
|
||||||
|
specific prior written permission.
|
||||||
|
|
||||||
|
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
|
||||||
|
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
|
||||||
|
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
||||||
|
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR
|
||||||
|
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
|
||||||
|
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||||
|
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
|
||||||
|
ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||||
|
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
|
||||||
|
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
57
pki/build.gradle
Normal file
57
pki/build.gradle
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
plugins {
|
||||||
|
id 'buildlogic.java-application-conventions'
|
||||||
|
id 'com.palantir.git-version'
|
||||||
|
}
|
||||||
|
|
||||||
|
group 'org.egothor'
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation 'org.apache.commons:commons-text'
|
||||||
|
implementation 'commons-cli:commons-cli'
|
||||||
|
implementation project(':lib')
|
||||||
|
}
|
||||||
|
|
||||||
|
application {
|
||||||
|
// Define the main class for the application.
|
||||||
|
mainClass = 'zeroecho.pki.PkiApplication'
|
||||||
|
}
|
||||||
|
|
||||||
|
jar {
|
||||||
|
manifest {
|
||||||
|
attributes(
|
||||||
|
'Main-Class': application.mainClass,
|
||||||
|
'Implementation-Title': rootProject.name,
|
||||||
|
'Implementation-Version': "${version}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
from sourceSets.main.output
|
||||||
|
|
||||||
|
dependsOn configurations.runtimeClasspath
|
||||||
|
|
||||||
|
// Include each JAR dependency
|
||||||
|
configurations.runtimeClasspath.findAll { it.exists() && it.name.endsWith('.jar') }.each { jarFile ->
|
||||||
|
def jarName = jarFile.name.replaceAll(/\.jar$/, '')
|
||||||
|
|
||||||
|
from(zipTree(jarFile)) {
|
||||||
|
// Exclude signature-related files
|
||||||
|
exclude 'META-INF/*.SF', 'META-INF/*.DSA', 'META-INF/*.RSA'
|
||||||
|
|
||||||
|
// Rename license/notice files to avoid conflicts
|
||||||
|
eachFile { file ->
|
||||||
|
if (file.path ==~ /META-INF\/(LICENSE|NOTICE)(\..*)?/) {
|
||||||
|
file.path = "META-INF/licenses-from-${jarName}/${file.name}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
includeEmptyDirs = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
duplicatesStrategy = DuplicatesStrategy.EXCLUDE
|
||||||
|
}
|
||||||
|
|
||||||
|
javadoc {
|
||||||
|
options.links("https://www.egothor.org/javadoc/zeroecho/lib")
|
||||||
|
}
|
||||||
|
|
||||||
309
pki/src/main/java/zeroecho/pki/PkiApplication.java
Normal file
309
pki/src/main/java/zeroecho/pki/PkiApplication.java
Normal file
@@ -0,0 +1,309 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
|
import java.util.concurrent.Executors;
|
||||||
|
import java.util.concurrent.ScheduledExecutorService;
|
||||||
|
import java.util.concurrent.ThreadFactory;
|
||||||
|
import java.util.concurrent.TimeUnit;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.audit.Principal;
|
||||||
|
import zeroecho.pki.spi.bootstrap.PkiBootstrap;
|
||||||
|
import zeroecho.pki.util.async.AsyncBus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Minimal bootstrap entry point for the {@code pki} module.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This class is intentionally limited to process bootstrap and hosting
|
||||||
|
* concerns:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>initializes JUL logging conventions (without leaking secrets),</li>
|
||||||
|
* <li>installs an uncaught-exception handler,</li>
|
||||||
|
* <li>composes PKI runtime components using {@link PkiBootstrap},</li>
|
||||||
|
* <li>hosts the async-bus maintenance loop via periodic
|
||||||
|
* {@code sweep(...)},</li>
|
||||||
|
* <li>waits until process termination (Ctrl+C) and performs orderly
|
||||||
|
* shutdown.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <h2>Async bus sweep</h2>
|
||||||
|
* <p>
|
||||||
|
* The async bus requires periodic {@link AsyncBus#sweep(Instant)} calls to:
|
||||||
|
* expire operations past their deadline and re-synchronize open operations
|
||||||
|
* after restart (depending on the bus implementation).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Security</h2>
|
||||||
|
* <p>
|
||||||
|
* Command-line arguments and configuration values are never logged because they
|
||||||
|
* can contain sensitive material (paths, tokens, passphrases).
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("PMD.DoNotUseThreads")
|
||||||
|
public final class PkiApplication {
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger(PkiApplication.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* System property controlling the async sweep interval in milliseconds.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* If missing or invalid, a safe default is used.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
private static final String PROP_ASYNC_SWEEP_INTERVAL_MS = "zeroecho.pki.async.sweepIntervalMs";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Default async sweep interval used when not configured.
|
||||||
|
*/
|
||||||
|
private static final Duration DEFAULT_ASYNC_SWEEP_INTERVAL = Duration.ofSeconds(2L);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shutdown grace time for the sweep executor.
|
||||||
|
*/
|
||||||
|
private static final Duration SWEEP_SHUTDOWN_GRACE = Duration.ofSeconds(10L);
|
||||||
|
|
||||||
|
private PkiApplication() {
|
||||||
|
throw new AssertionError("No instances.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts the PKI process.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Security note: command-line arguments are not logged because they can contain
|
||||||
|
* sensitive material (paths, tokens, passphrases).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param args command-line arguments (never logged)
|
||||||
|
*/
|
||||||
|
public static void main(String[] args) {
|
||||||
|
Objects.requireNonNull(args, "args");
|
||||||
|
|
||||||
|
PkiLogging.configureIfPresent();
|
||||||
|
PkiLogging.installUncaughtExceptionHandler();
|
||||||
|
|
||||||
|
LOG.info("ZeroEcho PKI starting.");
|
||||||
|
|
||||||
|
CountDownLatch shutdownLatch = new CountDownLatch(1);
|
||||||
|
|
||||||
|
// closed in the shutdown routine
|
||||||
|
ScheduledExecutorService sweepExecutor = Executors.newSingleThreadScheduledExecutor(new SweepThreadFactory()); // NOPMD
|
||||||
|
|
||||||
|
Runtime.getRuntime()
|
||||||
|
.addShutdownHook(new Thread(new ShutdownHook(sweepExecutor, shutdownLatch), "zeroecho-pki-shutdown"));
|
||||||
|
|
||||||
|
try {
|
||||||
|
AsyncBus<PkiId, Principal, String, Object> asyncBus = PkiBootstrap.openAsyncBus();
|
||||||
|
|
||||||
|
Duration sweepInterval = readSweepInterval(DEFAULT_ASYNC_SWEEP_INTERVAL);
|
||||||
|
|
||||||
|
if (LOG.isLoggable(Level.INFO)) {
|
||||||
|
LOG.log(Level.INFO, "Async bus sweep enabled; intervalMs={0}", sweepInterval.toMillis());
|
||||||
|
}
|
||||||
|
|
||||||
|
sweepExecutor.scheduleWithFixedDelay(new SweepTask(asyncBus), 0L, sweepInterval.toMillis(),
|
||||||
|
TimeUnit.MILLISECONDS);
|
||||||
|
|
||||||
|
LOG.info("ZeroEcho PKI started.");
|
||||||
|
|
||||||
|
// Keep process alive until Ctrl+C (or other shutdown signal).
|
||||||
|
awaitShutdown(shutdownLatch);
|
||||||
|
} catch (RuntimeException ex) { // NOPMD
|
||||||
|
// Do not include user-provided inputs in the message; log the exception object.
|
||||||
|
LOG.log(Level.SEVERE, "Fatal error during PKI bootstrap.", ex);
|
||||||
|
throw ex;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void awaitShutdown(CountDownLatch latch) {
|
||||||
|
try {
|
||||||
|
latch.await();
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
if (LOG.isLoggable(Level.WARNING)) {
|
||||||
|
LOG.log(Level.WARNING, "Interrupted while awaiting shutdown.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Duration readSweepInterval(Duration defaultValue) {
|
||||||
|
String raw = System.getProperty(PROP_ASYNC_SWEEP_INTERVAL_MS);
|
||||||
|
if (raw == null || raw.isBlank()) {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
long ms = Long.parseLong(raw);
|
||||||
|
if (ms <= 0L) { // NOPMD
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return Duration.ofMillis(ms);
|
||||||
|
} catch (NumberFormatException ex) {
|
||||||
|
if (LOG.isLoggable(Level.WARNING)) {
|
||||||
|
LOG.log(Level.WARNING, "Invalid async sweep interval system property; using default.", ex);
|
||||||
|
}
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Periodic maintenance task for asynchronous PKI infrastructure.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* {@code SweepTask} represents a resilient, repeatable unit of work that
|
||||||
|
* invokes time-based maintenance logic on an {@link AsyncBus} instance. It is
|
||||||
|
* intended to be scheduled at a fixed rate by a background executor and must
|
||||||
|
* tolerate partial failures without disrupting the surrounding runtime
|
||||||
|
* environment.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The task uses the current wall-clock time as a reference for sweep operations
|
||||||
|
* and deliberately suppresses runtime failures, logging them for diagnostic
|
||||||
|
* purposes while allowing future executions to proceed.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This class is internal to the PKI bootstrap and lifecycle management logic
|
||||||
|
* and is not part of the public API surface.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
private static final class SweepTask implements Runnable {
|
||||||
|
|
||||||
|
private final AsyncBus<PkiId, Principal, String, Object> asyncBus;
|
||||||
|
|
||||||
|
private SweepTask(AsyncBus<PkiId, Principal, String, Object> asyncBus) {
|
||||||
|
this.asyncBus = Objects.requireNonNull(asyncBus, "asyncBus");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Instant now = Instant.now();
|
||||||
|
try {
|
||||||
|
asyncBus.sweep(now);
|
||||||
|
} catch (RuntimeException ex) { // NOPMD
|
||||||
|
// Sweep must be resilient; log and continue.
|
||||||
|
if (LOG.isLoggable(Level.WARNING)) {
|
||||||
|
LOG.log(Level.WARNING, "Async sweep failed.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JVM shutdown hook coordinating termination of asynchronous sweep services.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* {@code ShutdownHook} is responsible for orchestrating an orderly shutdown of
|
||||||
|
* background sweep execution during JVM termination. It emits a structured
|
||||||
|
* shutdown message, initiates executor shutdown, and enforces a bounded grace
|
||||||
|
* period for task completion.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The hook guarantees that shutdown coordination always completes by
|
||||||
|
* decrementing the associated {@link CountDownLatch}, regardless of whether
|
||||||
|
* shutdown is graceful, forced, or interrupted.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This class must never throw exceptions or prevent JVM termination. All
|
||||||
|
* failure modes are handled internally.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
private static final class ShutdownHook implements Runnable {
|
||||||
|
|
||||||
|
private final ScheduledExecutorService sweepExecutor;
|
||||||
|
private final CountDownLatch latch;
|
||||||
|
|
||||||
|
private ShutdownHook(ScheduledExecutorService sweepExecutor, CountDownLatch latch) {
|
||||||
|
this.sweepExecutor = Objects.requireNonNull(sweepExecutor, "sweepExecutor");
|
||||||
|
this.latch = Objects.requireNonNull(latch, "latch");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
Logger shutdownLogger = Logger.getLogger(PkiApplication.class.getName());
|
||||||
|
PkiLogging.emitShutdownMessage(shutdownLogger, "ZeroEcho PKI stopping.");
|
||||||
|
|
||||||
|
sweepExecutor.shutdown();
|
||||||
|
try {
|
||||||
|
boolean ok = sweepExecutor.awaitTermination(SWEEP_SHUTDOWN_GRACE.toMillis(), TimeUnit.MILLISECONDS);
|
||||||
|
if (!ok) {
|
||||||
|
sweepExecutor.shutdownNow();
|
||||||
|
}
|
||||||
|
} catch (InterruptedException ex) {
|
||||||
|
Thread.currentThread().interrupt();
|
||||||
|
sweepExecutor.shutdownNow();
|
||||||
|
} finally {
|
||||||
|
latch.countDown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Thread factory for asynchronous sweep execution.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* {@code SweepThreadFactory} creates daemon threads with a stable and
|
||||||
|
* descriptive naming convention suitable for operational diagnostics and log
|
||||||
|
* correlation. Threads produced by this factory are intentionally marked as
|
||||||
|
* daemon threads so that they do not prolong JVM lifetime.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The factory performs no additional customization such as priority changes or
|
||||||
|
* uncaught-exception handlers, relying instead on executor-level policies.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
private static final class SweepThreadFactory implements ThreadFactory {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Thread newThread(Runnable r) {
|
||||||
|
Thread t = new Thread(r, "zeroecho-pki-async-sweep");
|
||||||
|
t.setDaemon(true);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
178
pki/src/main/java/zeroecho/pki/PkiLogging.java
Normal file
178
pki/src/main/java/zeroecho/pki/PkiLogging.java
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.lang.Thread.UncaughtExceptionHandler;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.atomic.AtomicBoolean;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.LogManager;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal bootstrap utilities for JUL configuration in the {@code pki} module.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This helper intentionally avoids logging any potentially sensitive material.
|
||||||
|
* In particular, it never logs:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>command-line arguments,</li>
|
||||||
|
* <li>key material, seeds, shared secrets,</li>
|
||||||
|
* <li>private configuration values (tokens, passphrases).</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Configuration strategy:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>If a {@code /zeroecho-pki-logging.properties} resource is present on the
|
||||||
|
* classpath, it will be loaded via
|
||||||
|
* {@link LogManager#readConfiguration(InputStream)}.</li>
|
||||||
|
* <li>If not present, JUL defaults remain in place (minimal bootstrap
|
||||||
|
* behavior).</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
final class PkiLogging {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional classpath resource for JUL configuration.
|
||||||
|
*/
|
||||||
|
private static final String LOGGING_PROPERTIES_RESOURCE = "/zeroecho-pki-logging.properties";
|
||||||
|
|
||||||
|
private static final Logger LOG = Logger.getLogger(PkiLogging.class.getName());
|
||||||
|
|
||||||
|
/**
|
||||||
|
* One-shot guard ensuring JUL configuration is attempted at most once.
|
||||||
|
*/
|
||||||
|
private static final AtomicBoolean CONFIGURED = new AtomicBoolean(false);
|
||||||
|
|
||||||
|
private PkiLogging() {
|
||||||
|
throw new AssertionError("No instances.");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Configures JUL from an optional classpath resource, if present.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This method is idempotent and safe to call multiple times.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
/* default */ static void configureIfPresent() {
|
||||||
|
// Fast-path: already configured
|
||||||
|
if (!CONFIGURED.compareAndSet(false, true)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// getResourceAsStream() may return null; try-with-resources handles null safely
|
||||||
|
try (InputStream is = PkiLogging.class.getResourceAsStream(LOGGING_PROPERTIES_RESOURCE)) {
|
||||||
|
if (is == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
LogManager.getLogManager().readConfiguration(is);
|
||||||
|
LOG.info("JUL configured from classpath resource.");
|
||||||
|
} catch (IOException ex) {
|
||||||
|
// Keep message generic; do not leak environment specifics.
|
||||||
|
LOG.log(Level.WARNING, "Failed to load JUL configuration; continuing with defaults.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Installs a process-wide uncaught exception handler that logs failures via
|
||||||
|
* JUL.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The handler emits a generic message and includes the throwable. It
|
||||||
|
* deliberately does not serialize additional contextual data that might contain
|
||||||
|
* secrets.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
/* default */ static void installUncaughtExceptionHandler() {
|
||||||
|
UncaughtExceptionHandler handler = (Thread thread, Throwable throwable) -> { // NOPMD
|
||||||
|
Objects.requireNonNull(thread, "thread");
|
||||||
|
Objects.requireNonNull(throwable, "throwable");
|
||||||
|
Logger logger = Logger.getLogger(PkiApplication.class.getName());
|
||||||
|
if (logger.isLoggable(Level.SEVERE)) {
|
||||||
|
logger.log(Level.SEVERE, "Uncaught exception in thread: " + thread.getName(), throwable);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler(handler); // NOPMD
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Emits a shutdown message in a way that remains visible even during late JVM
|
||||||
|
* teardown.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The primary path is JUL. As a fallback, a constant message is written to
|
||||||
|
* {@code System.err}. This avoids logging any secrets and improves reliability
|
||||||
|
* in environments where JUL output may be lost during shutdown.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param logger logger to use for the primary JUL emission
|
||||||
|
* @param message message to emit; must not contain secrets
|
||||||
|
* @throws NullPointerException if {@code logger} or {@code message} is
|
||||||
|
* {@code null}
|
||||||
|
*/
|
||||||
|
/* default */ static void emitShutdownMessage(Logger logger, String message) {
|
||||||
|
Objects.requireNonNull(logger, "logger");
|
||||||
|
Objects.requireNonNull(message, "message");
|
||||||
|
|
||||||
|
// Primary path: JUL
|
||||||
|
logger.info(message);
|
||||||
|
|
||||||
|
// Flush root handlers (covers parent-handler delegation).
|
||||||
|
Logger root = Logger.getLogger("");
|
||||||
|
for (java.util.logging.Handler handler : root.getHandlers()) {
|
||||||
|
try {
|
||||||
|
handler.flush();
|
||||||
|
} catch (RuntimeException ignored) { // NOPMD
|
||||||
|
// Never throw during shutdown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback: direct stderr write
|
||||||
|
try {
|
||||||
|
System.err.println(message);
|
||||||
|
System.err.flush();
|
||||||
|
} catch (RuntimeException ignored) { // NOPMD
|
||||||
|
// Never throw during shutdown
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
83
pki/src/main/java/zeroecho/pki/api/BackupService.java
Normal file
83
pki/src/main/java/zeroecho/pki/api/BackupService.java
Normal file
@@ -0,0 +1,83 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.backup.BackupArtifact;
|
||||||
|
import zeroecho.pki.api.backup.BackupRequest;
|
||||||
|
import zeroecho.pki.api.backup.BackupVerificationReport;
|
||||||
|
import zeroecho.pki.api.backup.RestoreReport;
|
||||||
|
import zeroecho.pki.api.backup.RestoreRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Backup/restore operations for PKI state.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Backups must not implicitly include private keys. Private keys are referenced
|
||||||
|
* via {@link KeyRef} and may be managed by separate components.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface BackupService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a backup of PKI state.
|
||||||
|
*
|
||||||
|
* @param request backup request
|
||||||
|
* @return backup artifact
|
||||||
|
* @throws IllegalArgumentException if {@code request} is invalid
|
||||||
|
* @throws PkiException if backup creation fails
|
||||||
|
*/
|
||||||
|
BackupArtifact createBackup(BackupRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Restores PKI state from a backup artifact.
|
||||||
|
*
|
||||||
|
* @param request restore request
|
||||||
|
* @return restore report
|
||||||
|
* @throws IllegalArgumentException if {@code request} is invalid
|
||||||
|
* @throws PkiException if restore fails
|
||||||
|
*/
|
||||||
|
RestoreReport restoreBackup(RestoreRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies a backup artifact for structural validity and integrity.
|
||||||
|
*
|
||||||
|
* @param artifact backup artifact
|
||||||
|
* @return verification report
|
||||||
|
* @throws IllegalArgumentException if {@code artifact} is null
|
||||||
|
* @throws PkiException if verification fails due to IO/backend
|
||||||
|
* errors
|
||||||
|
*/
|
||||||
|
BackupVerificationReport verifyBackup(BackupArtifact artifact);
|
||||||
|
}
|
||||||
172
pki/src/main/java/zeroecho/pki/api/CaService.java
Normal file
172
pki/src/main/java/zeroecho/pki/api/CaService.java
Normal file
@@ -0,0 +1,172 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.ca.CaCreateCommand;
|
||||||
|
import zeroecho.pki.api.ca.CaImportCommand;
|
||||||
|
import zeroecho.pki.api.ca.CaKeyRotationCommand;
|
||||||
|
import zeroecho.pki.api.ca.CaQuery;
|
||||||
|
import zeroecho.pki.api.ca.CaRecord;
|
||||||
|
import zeroecho.pki.api.ca.CaRolloverCommand;
|
||||||
|
import zeroecho.pki.api.ca.CaState;
|
||||||
|
import zeroecho.pki.api.ca.IntermediateCertIssueCommand;
|
||||||
|
import zeroecho.pki.api.ca.IntermediateCreateCommand;
|
||||||
|
import zeroecho.pki.api.credential.Credential;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Manages Certificate Authority (CA) entities and their lifecycle.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* A CA entity represents an administrative unit capable of issuing credentials.
|
||||||
|
* A CA entity may own multiple CA credentials over time to support
|
||||||
|
* cross-signing, rollover, and key rotation.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Private key material is never handled directly by the PKI module; the CA key
|
||||||
|
* is referenced by {@link KeyRef} and resolved by runtime wiring.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface CaService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new root CA entity and issues its initial CA credential.
|
||||||
|
*
|
||||||
|
* @param command create command defining subject/profile and optional key
|
||||||
|
* reference
|
||||||
|
* @return created CA identifier
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if creation fails due to policy, storage, or
|
||||||
|
* framework backend error
|
||||||
|
*/
|
||||||
|
PkiId createRoot(CaCreateCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports an existing root CA into the PKI inventory.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This registers a CA entity, associates it with a {@link KeyRef}, and persists
|
||||||
|
* the existing CA credential. Import does not automatically imply trust; trust
|
||||||
|
* anchor selection is a consumer decision.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param command import command including CA credential payload and key
|
||||||
|
* reference
|
||||||
|
* @return imported CA identifier
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if import fails (e.g., inconsistent
|
||||||
|
* metadata, storage failure)
|
||||||
|
*/
|
||||||
|
PkiId importRoot(CaImportCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a new intermediate CA entity and issues its initial intermediate CA
|
||||||
|
* credential.
|
||||||
|
*
|
||||||
|
* @param command intermediate creation command
|
||||||
|
* @return created intermediate CA identifier
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if creation fails
|
||||||
|
*/
|
||||||
|
PkiId createIntermediate(IntermediateCreateCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issues a new CA credential for an existing intermediate CA entity.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This operation enables cross-signing and renewal scenarios.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param command issuance command specifying issuer and subject CA entity
|
||||||
|
* @return newly issued CA credential
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if issuance fails due to policy or backend
|
||||||
|
* errors
|
||||||
|
*/
|
||||||
|
Credential issueIntermediateCertificate(IntermediateCertIssueCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Performs a CA credential rollover while keeping the same key reference.
|
||||||
|
*
|
||||||
|
* @param command rollover command
|
||||||
|
* @return CA identifier (same CA id expected; returned for convenience)
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if rollover fails
|
||||||
|
*/
|
||||||
|
PkiId rolloverCaCertificate(CaRolloverCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rotates the CA key reference and issues new corresponding CA credentials.
|
||||||
|
*
|
||||||
|
* @param command key rotation command
|
||||||
|
* @return CA identifier (same CA id expected; returned for convenience)
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if rotation fails
|
||||||
|
*/
|
||||||
|
PkiId rotateCaKey(CaKeyRotationCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates CA operational state.
|
||||||
|
*
|
||||||
|
* @param caId CA identifier
|
||||||
|
* @param state new CA state
|
||||||
|
* @param reason non-empty operator-readable reason suitable for audit
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if CA does not exist or update fails
|
||||||
|
*/
|
||||||
|
void setCaState(PkiId caId, CaState state, String reason);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a CA record.
|
||||||
|
*
|
||||||
|
* @param caId CA identifier
|
||||||
|
* @return CA record
|
||||||
|
* @throws IllegalArgumentException if {@code caId} is invalid
|
||||||
|
* @throws PkiException if CA does not exist
|
||||||
|
*/
|
||||||
|
CaRecord getCa(PkiId caId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists CA records matching query constraints.
|
||||||
|
*
|
||||||
|
* @param query query constraints
|
||||||
|
* @return list of CA records
|
||||||
|
* @throws IllegalArgumentException if {@code query} is invalid
|
||||||
|
* @throws PkiException if listing fails
|
||||||
|
*/
|
||||||
|
List<CaRecord> listCas(CaQuery query);
|
||||||
|
}
|
||||||
@@ -0,0 +1,123 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.issuance.VerificationPolicy;
|
||||||
|
import zeroecho.pki.api.request.CertificationRequest;
|
||||||
|
import zeroecho.pki.api.request.ParsedCertificationRequest;
|
||||||
|
import zeroecho.pki.api.request.ProofOfPossessionResult;
|
||||||
|
import zeroecho.pki.api.request.RequestQuery;
|
||||||
|
import zeroecho.pki.api.request.RequestStorePolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Processes certification requests (CSR-like objects) into a normalized
|
||||||
|
* representation.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This service provides request fingerprinting, parsing, proof-of-possession
|
||||||
|
* verification, and optional persistence for correlation and auditing. Request
|
||||||
|
* transport protocols such as ACME are expected to use this service as the core
|
||||||
|
* processing layer.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface CertificationRequestService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes a stable identifier (fingerprint) for the given request payload.
|
||||||
|
*
|
||||||
|
* @param request certification request
|
||||||
|
* @return stable request identifier
|
||||||
|
* @throws IllegalArgumentException if {@code request} is null
|
||||||
|
* @throws PkiException if fingerprinting fails
|
||||||
|
*/
|
||||||
|
PkiId fingerprint(CertificationRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Parses and normalizes a certification request.
|
||||||
|
*
|
||||||
|
* @param request certification request
|
||||||
|
* @return parsed request
|
||||||
|
* @throws IllegalArgumentException if {@code request} is null
|
||||||
|
* @throws PkiException if parsing fails (invalid request,
|
||||||
|
* unsupported format, backend failure)
|
||||||
|
*/
|
||||||
|
ParsedCertificationRequest parse(CertificationRequest request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verifies proof-of-possession (PoP) for the private key corresponding to the
|
||||||
|
* requested public key.
|
||||||
|
*
|
||||||
|
* @param parsed parsed request
|
||||||
|
* @param policy verification policy
|
||||||
|
* @return PoP verification result
|
||||||
|
* @throws IllegalArgumentException if inputs are null
|
||||||
|
* @throws PkiException if verification fails due to backend failure
|
||||||
|
*/
|
||||||
|
ProofOfPossessionResult verifyProofOfPossession(ParsedCertificationRequest parsed, VerificationPolicy policy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stores a parsed request for later correlation and audit.
|
||||||
|
*
|
||||||
|
* @param parsed parsed request
|
||||||
|
* @param policy storage policy
|
||||||
|
* @return stored request id
|
||||||
|
* @throws IllegalArgumentException if inputs are null
|
||||||
|
* @throws PkiException if persistence fails
|
||||||
|
*/
|
||||||
|
PkiId store(ParsedCertificationRequest parsed, RequestStorePolicy policy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a stored request.
|
||||||
|
*
|
||||||
|
* @param requestId request id
|
||||||
|
* @return parsed request if present
|
||||||
|
* @throws IllegalArgumentException if {@code requestId} is null
|
||||||
|
* @throws PkiException if retrieval fails
|
||||||
|
*/
|
||||||
|
Optional<ParsedCertificationRequest> get(PkiId requestId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches stored requests.
|
||||||
|
*
|
||||||
|
* @param query request query
|
||||||
|
* @return matching requests
|
||||||
|
* @throws IllegalArgumentException if {@code query} is null
|
||||||
|
* @throws PkiException if searching fails
|
||||||
|
*/
|
||||||
|
List<ParsedCertificationRequest> search(RequestQuery query);
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.credential.Credential;
|
||||||
|
import zeroecho.pki.api.credential.CredentialQuery;
|
||||||
|
import zeroecho.pki.api.credential.CredentialStatus;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Inventory and reporting service for issued credentials.
|
||||||
|
*/
|
||||||
|
public interface CredentialInventoryService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a credential by id.
|
||||||
|
*
|
||||||
|
* @param credentialId credential id
|
||||||
|
* @return credential if present
|
||||||
|
* @throws IllegalArgumentException if {@code credentialId} is null
|
||||||
|
* @throws PkiException if retrieval fails
|
||||||
|
*/
|
||||||
|
Optional<Credential> get(PkiId credentialId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a credential by issuer CA and serial/unique identifier.
|
||||||
|
*
|
||||||
|
* @param issuerCaId issuer CA id
|
||||||
|
* @param serialOrUniqueId serial/unique id
|
||||||
|
* @return credential if present
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if lookup fails
|
||||||
|
*/
|
||||||
|
Optional<Credential> findByIssuerSerial(PkiId issuerCaId, String serialOrUniqueId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists credentials bound to the same public key identifier.
|
||||||
|
*
|
||||||
|
* @param publicKeyId public key id
|
||||||
|
* @return credentials
|
||||||
|
* @throws IllegalArgumentException if {@code publicKeyId} is null
|
||||||
|
* @throws PkiException if lookup fails
|
||||||
|
*/
|
||||||
|
List<Credential> listByPublicKeyId(PkiId publicKeyId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches credentials by query constraints.
|
||||||
|
*
|
||||||
|
* @param query query constraints
|
||||||
|
* @return matching credentials
|
||||||
|
* @throws IllegalArgumentException if {@code query} is null
|
||||||
|
* @throws PkiException if search fails
|
||||||
|
*/
|
||||||
|
List<Credential> search(CredentialQuery query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Computes credential status at a given time.
|
||||||
|
*
|
||||||
|
* @param credentialId credential id
|
||||||
|
* @param now evaluation time
|
||||||
|
* @return computed status
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if evaluation fails
|
||||||
|
*/
|
||||||
|
CredentialStatus computeStatus(PkiId credentialId, Instant now);
|
||||||
|
}
|
||||||
72
pki/src/main/java/zeroecho/pki/api/EncodedObject.java
Normal file
72
pki/src/main/java/zeroecho/pki/api/EncodedObject.java
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immutable container for an encoded artifact.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This type intentionally carries only the {@link Encoding} and raw bytes. It
|
||||||
|
* does not carry a media type, because DER/PEM/BINARY do not uniquely determine
|
||||||
|
* the semantic meaning (a DER payload may represent a certificate, CSR, CRL,
|
||||||
|
* etc.). The semantic meaning is carried by the surrounding API context.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Security note: implementations must never log the raw bytes in full.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param encoding encoding kind
|
||||||
|
* @param bytes non-empty payload bytes
|
||||||
|
*/
|
||||||
|
public record EncodedObject(Encoding encoding, byte[] bytes) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an encoded object.
|
||||||
|
*
|
||||||
|
* @param encoding encoding kind
|
||||||
|
* @param bytes non-empty payload bytes
|
||||||
|
* @throws IllegalArgumentException if {@code encoding} is null or {@code bytes}
|
||||||
|
* is null/empty
|
||||||
|
*/
|
||||||
|
public EncodedObject {
|
||||||
|
if (encoding == null) {
|
||||||
|
throw new IllegalArgumentException("encoding must not be null");
|
||||||
|
}
|
||||||
|
if (bytes == null || bytes.length == 0) {
|
||||||
|
throw new IllegalArgumentException("bytes must not be null/empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
75
pki/src/main/java/zeroecho/pki/api/Encoding.java
Normal file
75
pki/src/main/java/zeroecho/pki/api/Encoding.java
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specifies the encoding of a binary artifact payload.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The encoding indicates how the {@code bytes} inside {@link EncodedObject}
|
||||||
|
* should be interpreted. The logical meaning of the payload (certificate vs CSR
|
||||||
|
* vs CRL vs backup) is defined by the surrounding API context and record types.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public enum Encoding {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ASN.1 Distinguished Encoding Rules (DER).
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Common for X.509 certificates, CRLs, and PKCS#10 certification requests.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
DER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* PEM armored textual representation.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Typically base64-wrapped DER with header/footer lines.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
PEM,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raw binary blob without implying ASN.1 DER or PEM semantics.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Use for non-ASN.1 frameworks (e.g., COSE/JWS) or container payloads (e.g.,
|
||||||
|
* backup archives).
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
BINARY
|
||||||
|
}
|
||||||
64
pki/src/main/java/zeroecho/pki/api/FormatId.java
Normal file
64
pki/src/main/java/zeroecho/pki/api/FormatId.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifier of a credential framework/format handled by the PKI core.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Examples: {@code "x509"}, {@code "ssh"}, {@code "cose"}, {@code "jws"}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This identifier is used to dispatch operations to a framework backend
|
||||||
|
* implementation.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value non-empty format identifier string
|
||||||
|
*/
|
||||||
|
public record FormatId(String value) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a format identifier.
|
||||||
|
*
|
||||||
|
* @param value non-empty format identifier string
|
||||||
|
* @throws IllegalArgumentException if {@code value} is null or blank
|
||||||
|
*/
|
||||||
|
public FormatId {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("value must not be null/blank");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
122
pki/src/main/java/zeroecho/pki/api/ImportExportService.java
Normal file
122
pki/src/main/java/zeroecho/pki/api/ImportExportService.java
Normal file
@@ -0,0 +1,122 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.revocation.RevokedRecord;
|
||||||
|
import zeroecho.pki.api.transfer.ExportArtifact;
|
||||||
|
import zeroecho.pki.api.transfer.ExportFormat;
|
||||||
|
import zeroecho.pki.api.transfer.ExportQuery;
|
||||||
|
import zeroecho.pki.api.transfer.ImportPolicy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Import and export operations for migration and interoperability.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Import does not imply trust; it is a controlled operation governed by policy.
|
||||||
|
* Import/export is expected to be auditable.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface ImportExportService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports an issued credential payload into inventory.
|
||||||
|
*
|
||||||
|
* @param formatId credential format id
|
||||||
|
* @param credential encoded credential payload
|
||||||
|
* @param policy import policy
|
||||||
|
* @return imported credential id
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if import fails
|
||||||
|
*/
|
||||||
|
PkiId importCredential(FormatId formatId, EncodedObject credential, ImportPolicy policy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports a CA certificate payload into an existing CA entity's credential set.
|
||||||
|
*
|
||||||
|
* @param caId CA entity id
|
||||||
|
* @param caCertificate CA certificate payload
|
||||||
|
* @param policy import policy
|
||||||
|
* @return imported credential id
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if import fails
|
||||||
|
*/
|
||||||
|
PkiId importCaCertificate(PkiId caId, EncodedObject caCertificate, ImportPolicy policy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Imports a revocation record.
|
||||||
|
*
|
||||||
|
* @param record revocation record
|
||||||
|
* @param policy import policy
|
||||||
|
* @return imported revocation record id (implementation-defined)
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if import fails
|
||||||
|
*/
|
||||||
|
PkiId importRevocation(RevokedRecord record, ImportPolicy policy);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports credentials matching the query constraints in the requested export
|
||||||
|
* format.
|
||||||
|
*
|
||||||
|
* @param query export query
|
||||||
|
* @param format export format
|
||||||
|
* @return export artifact
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if export fails
|
||||||
|
*/
|
||||||
|
ExportArtifact exportCredentials(ExportQuery query, ExportFormat format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports revocation records matching the query constraints in the requested
|
||||||
|
* export format.
|
||||||
|
*
|
||||||
|
* @param query export query
|
||||||
|
* @param format export format
|
||||||
|
* @return export artifact
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if export fails
|
||||||
|
*/
|
||||||
|
ExportArtifact exportRevocations(ExportQuery query, ExportFormat format);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports CA materials for a given CA entity in the requested export format.
|
||||||
|
*
|
||||||
|
* @param caId CA entity id
|
||||||
|
* @param format export format
|
||||||
|
* @return export artifact
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if export fails
|
||||||
|
*/
|
||||||
|
ExportArtifact exportCa(PkiId caId, ExportFormat format);
|
||||||
|
}
|
||||||
108
pki/src/main/java/zeroecho/pki/api/IssuanceService.java
Normal file
108
pki/src/main/java/zeroecho/pki/api/IssuanceService.java
Normal file
@@ -0,0 +1,108 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.credential.CredentialBundle;
|
||||||
|
import zeroecho.pki.api.issuance.BundleCommand;
|
||||||
|
import zeroecho.pki.api.issuance.IssueEndEntityCommand;
|
||||||
|
import zeroecho.pki.api.issuance.ReissueCommand;
|
||||||
|
import zeroecho.pki.api.issuance.RenewCommand;
|
||||||
|
import zeroecho.pki.api.issuance.ReplaceCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issues, renews, replaces, and reissues credentials, and builds distributable
|
||||||
|
* bundles.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This service is framework-agnostic: concrete credential formats are
|
||||||
|
* implemented by framework backends. The PKI runtime applies policy and profile
|
||||||
|
* constraints before calling issuance backends.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface IssuanceService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issues a new end-entity credential.
|
||||||
|
*
|
||||||
|
* @param command issuance command
|
||||||
|
* @return credential bundle (credential plus supporting artifacts)
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if issuance fails
|
||||||
|
*/
|
||||||
|
CredentialBundle issueEndEntity(IssueEndEntityCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Renews an existing credential according to policy-defined continuity
|
||||||
|
* semantics.
|
||||||
|
*
|
||||||
|
* @param command renewal command
|
||||||
|
* @return renewed credential bundle
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if renewal fails
|
||||||
|
*/
|
||||||
|
CredentialBundle renew(RenewCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Replaces an existing credential (e.g., after compromise or attribute
|
||||||
|
* changes).
|
||||||
|
*
|
||||||
|
* @param command replacement command
|
||||||
|
* @return replacement credential bundle
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if replacement fails
|
||||||
|
*/
|
||||||
|
CredentialBundle replace(ReplaceCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reissues based on a stored issuance record.
|
||||||
|
*
|
||||||
|
* @param command reissue command
|
||||||
|
* @return reissued credential bundle
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if reissue fails
|
||||||
|
*/
|
||||||
|
CredentialBundle reissue(ReissueCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a distributable bundle for an existing credential using chain
|
||||||
|
* selection rules.
|
||||||
|
*
|
||||||
|
* @param command bundle command
|
||||||
|
* @return bundle
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if bundle building fails
|
||||||
|
*/
|
||||||
|
CredentialBundle buildBundle(BundleCommand command);
|
||||||
|
}
|
||||||
55
pki/src/main/java/zeroecho/pki/api/IssuerRef.java
Normal file
55
pki/src/main/java/zeroecho/pki/api/IssuerRef.java
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* References an issuing CA entity.
|
||||||
|
*
|
||||||
|
* @param caId identifier of the CA entity acting as issuer
|
||||||
|
*/
|
||||||
|
public record IssuerRef(PkiId caId) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an issuer reference.
|
||||||
|
*
|
||||||
|
* @param caId CA identifier
|
||||||
|
* @throws IllegalArgumentException if {@code caId} is null
|
||||||
|
*/
|
||||||
|
public IssuerRef {
|
||||||
|
if (caId == null) {
|
||||||
|
throw new IllegalArgumentException("caId must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
62
pki/src/main/java/zeroecho/pki/api/KeyRef.java
Normal file
62
pki/src/main/java/zeroecho/pki/api/KeyRef.java
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opaque reference to private key material.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The PKI module never handles private key bytes. A {@link KeyRef} is resolved
|
||||||
|
* by runtime wiring, e.g., by a crypto component, an HSM adapter, or a remote
|
||||||
|
* signer. Implementations must treat this reference as sensitive metadata and
|
||||||
|
* avoid logging it unnecessarily.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value non-empty key reference token
|
||||||
|
*/
|
||||||
|
public record KeyRef(String value) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a key reference.
|
||||||
|
*
|
||||||
|
* @param value non-empty key reference token
|
||||||
|
* @throws IllegalArgumentException if {@code value} is null or blank
|
||||||
|
*/
|
||||||
|
public KeyRef {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("value must not be null/blank");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
82
pki/src/main/java/zeroecho/pki/api/PkiException.java
Normal file
82
pki/src/main/java/zeroecho/pki/api/PkiException.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base runtime exception for PKI domain failures.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This exception is used to report policy violations, storage failures,
|
||||||
|
* framework backend errors, and other domain-level problems not representable
|
||||||
|
* as {@link IllegalArgumentException}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Security note: exception messages must not contain secrets (private keys,
|
||||||
|
* plaintext, shared secrets, or other sensitive cryptographic material).
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public class PkiException extends RuntimeException {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 759504279718537161L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a PKI exception with a message.
|
||||||
|
*
|
||||||
|
* @param message non-empty message describing the failure in a non-sensitive
|
||||||
|
* manner
|
||||||
|
*/
|
||||||
|
public PkiException(String message) {
|
||||||
|
super(requireNonBlank(message, "message"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a PKI exception with a message and cause.
|
||||||
|
*
|
||||||
|
* @param message non-empty message describing the failure in a non-sensitive
|
||||||
|
* manner
|
||||||
|
* @param cause underlying cause
|
||||||
|
*/
|
||||||
|
public PkiException(String message, Throwable cause) {
|
||||||
|
super(requireNonBlank(message, "message"), cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static String requireNonBlank(String value, String name) {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
throw new IllegalArgumentException(name + " must not be null/blank");
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
70
pki/src/main/java/zeroecho/pki/api/PkiId.java
Normal file
70
pki/src/main/java/zeroecho/pki/api/PkiId.java
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opaque identifier for PKI-managed entities.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Instances of this type are used as stable references for CA entities,
|
||||||
|
* credentials, certification requests, status objects, backups, publications,
|
||||||
|
* exports, and policy/audit records.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The value must be treated as an opaque token and persisted verbatim.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value non-empty identifier string
|
||||||
|
*/
|
||||||
|
public record PkiId(String value) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an opaque PKI identifier.
|
||||||
|
*
|
||||||
|
* @param value non-empty identifier string
|
||||||
|
* @throws IllegalArgumentException if {@code value} is null or blank
|
||||||
|
*/
|
||||||
|
public PkiId {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("value must not be null/blank");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
}
|
||||||
82
pki/src/main/java/zeroecho/pki/api/PolicyService.java
Normal file
82
pki/src/main/java/zeroecho/pki/api/PolicyService.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.issuance.IssuanceInputs;
|
||||||
|
import zeroecho.pki.api.policy.PolicyDecision;
|
||||||
|
import zeroecho.pki.api.policy.PolicyTrace;
|
||||||
|
import zeroecho.pki.api.revocation.RevocationInputs;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Policy evaluation and explainability.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Policy decisions must be deterministic, auditable, and explainable.
|
||||||
|
* Implementations are expected to provide traces suitable for operator
|
||||||
|
* troubleshooting and compliance evidence.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface PolicyService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates an issuance request against policy and profile constraints.
|
||||||
|
*
|
||||||
|
* @param inputs normalized issuance inputs
|
||||||
|
* @return policy decision
|
||||||
|
* @throws IllegalArgumentException if {@code inputs} is null
|
||||||
|
* @throws PkiException if evaluation fails
|
||||||
|
*/
|
||||||
|
PolicyDecision evaluateIssuance(IssuanceInputs inputs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates a revocation request against policy constraints.
|
||||||
|
*
|
||||||
|
* @param inputs normalized revocation inputs
|
||||||
|
* @return policy decision
|
||||||
|
* @throws IllegalArgumentException if {@code inputs} is null
|
||||||
|
* @throws PkiException if evaluation fails
|
||||||
|
*/
|
||||||
|
PolicyDecision evaluateRevocation(RevocationInputs inputs);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a trace explaining a previous decision.
|
||||||
|
*
|
||||||
|
* @param decisionId decision id
|
||||||
|
* @return decision trace
|
||||||
|
* @throws IllegalArgumentException if {@code decisionId} is null
|
||||||
|
* @throws PkiException if trace retrieval fails
|
||||||
|
*/
|
||||||
|
PolicyTrace explain(PkiId decisionId);
|
||||||
|
}
|
||||||
91
pki/src/main/java/zeroecho/pki/api/ProfileService.java
Normal file
91
pki/src/main/java/zeroecho/pki/api/ProfileService.java
Normal file
@@ -0,0 +1,91 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.profile.CertificateProfile;
|
||||||
|
import zeroecho.pki.api.profile.ProfileQuery;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Profile registry for credential issuance.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Profiles define required/optional attributes, validity limits, and other
|
||||||
|
* constraints used by policy and framework mapping. Profiles are referenced by
|
||||||
|
* id during issuance.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface ProfileService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registers or updates a profile.
|
||||||
|
*
|
||||||
|
* @param profile profile definition
|
||||||
|
* @throws IllegalArgumentException if {@code profile} is null
|
||||||
|
* @throws PkiException if registration fails
|
||||||
|
*/
|
||||||
|
void register(CertificateProfile profile);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves a profile by id.
|
||||||
|
*
|
||||||
|
* @param profileId profile id
|
||||||
|
* @return profile
|
||||||
|
* @throws IllegalArgumentException if {@code profileId} is null/blank
|
||||||
|
* @throws PkiException if not found or retrieval fails
|
||||||
|
*/
|
||||||
|
CertificateProfile get(String profileId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists profiles matching query constraints.
|
||||||
|
*
|
||||||
|
* @param query query constraints
|
||||||
|
* @return list of profiles
|
||||||
|
* @throws IllegalArgumentException if {@code query} is null
|
||||||
|
* @throws PkiException if listing fails
|
||||||
|
*/
|
||||||
|
List<CertificateProfile> list(ProfileQuery query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retires a profile to prevent further issuance.
|
||||||
|
*
|
||||||
|
* @param profileId profile id
|
||||||
|
* @param reason non-empty reason suitable for audit
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if retire fails
|
||||||
|
*/
|
||||||
|
void retire(String profileId, String reason);
|
||||||
|
}
|
||||||
99
pki/src/main/java/zeroecho/pki/api/PublicationService.java
Normal file
99
pki/src/main/java/zeroecho/pki/api/PublicationService.java
Normal file
@@ -0,0 +1,99 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.publication.PublicationQuery;
|
||||||
|
import zeroecho.pki.api.publication.PublicationRecord;
|
||||||
|
import zeroecho.pki.api.publication.PublicationResult;
|
||||||
|
import zeroecho.pki.api.publication.PublicationTarget;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publication and distribution operations.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Publishing is an explicit operation enabling parity with established PKI
|
||||||
|
* systems. Implementations may publish credentials, CA materials, and status
|
||||||
|
* objects to configured targets such as filesystem mirrors, LDAP directories,
|
||||||
|
* HTTP endpoints, or object stores.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface PublicationService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publishes an issued credential to the specified target.
|
||||||
|
*
|
||||||
|
* @param credentialId credential id
|
||||||
|
* @param target publication target
|
||||||
|
* @return publication result
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if publication fails
|
||||||
|
*/
|
||||||
|
PublicationResult publishCredential(PkiId credentialId, PublicationTarget target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publishes CA materials (e.g., CA certificate sets) for the given CA entity to
|
||||||
|
* the specified target.
|
||||||
|
*
|
||||||
|
* @param caId CA entity id
|
||||||
|
* @param target publication target
|
||||||
|
* @return publication result
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if publication fails
|
||||||
|
*/
|
||||||
|
PublicationResult publishCaMaterials(PkiId caId, PublicationTarget target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Publishes a status object to the specified target.
|
||||||
|
*
|
||||||
|
* @param statusObjectId status object id
|
||||||
|
* @param target publication target
|
||||||
|
* @return publication result
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if publication fails
|
||||||
|
*/
|
||||||
|
PublicationResult publishStatusObject(PkiId statusObjectId, PublicationTarget target);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists publication records matching query constraints.
|
||||||
|
*
|
||||||
|
* @param query publication query
|
||||||
|
* @return publication records
|
||||||
|
* @throws IllegalArgumentException if {@code query} is invalid
|
||||||
|
* @throws PkiException if listing fails
|
||||||
|
*/
|
||||||
|
List<PublicationRecord> listPublications(PublicationQuery query);
|
||||||
|
}
|
||||||
100
pki/src/main/java/zeroecho/pki/api/RevocationService.java
Normal file
100
pki/src/main/java/zeroecho/pki/api/RevocationService.java
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.revocation.HoldCommand;
|
||||||
|
import zeroecho.pki.api.revocation.RevocationQuery;
|
||||||
|
import zeroecho.pki.api.revocation.RevokeCommand;
|
||||||
|
import zeroecho.pki.api.revocation.RevokedRecord;
|
||||||
|
import zeroecho.pki.api.revocation.UnholdCommand;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revocation operations and revocation record management.
|
||||||
|
*/
|
||||||
|
public interface RevocationService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revokes a credential.
|
||||||
|
*
|
||||||
|
* @param command revoke command
|
||||||
|
* @return revocation record
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if revocation fails
|
||||||
|
*/
|
||||||
|
RevokedRecord revoke(RevokeCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Places a credential on hold.
|
||||||
|
*
|
||||||
|
* @param command hold command
|
||||||
|
* @return revocation record
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if hold fails
|
||||||
|
*/
|
||||||
|
RevokedRecord hold(HoldCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes a hold from a credential.
|
||||||
|
*
|
||||||
|
* @param command unhold command
|
||||||
|
* @return revocation record
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if unhold fails
|
||||||
|
*/
|
||||||
|
RevokedRecord unhold(UnholdCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves revocation record for a credential.
|
||||||
|
*
|
||||||
|
* @param credentialId credential id
|
||||||
|
* @return record if present
|
||||||
|
* @throws IllegalArgumentException if {@code credentialId} is null
|
||||||
|
* @throws PkiException if retrieval fails
|
||||||
|
*/
|
||||||
|
Optional<RevokedRecord> get(PkiId credentialId);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches revocation records.
|
||||||
|
*
|
||||||
|
* @param query query constraints
|
||||||
|
* @return matching records
|
||||||
|
* @throws IllegalArgumentException if {@code query} is null
|
||||||
|
* @throws PkiException if search fails
|
||||||
|
*/
|
||||||
|
List<RevokedRecord> search(RevocationQuery query);
|
||||||
|
}
|
||||||
85
pki/src/main/java/zeroecho/pki/api/StatusObjectService.java
Normal file
85
pki/src/main/java/zeroecho/pki/api/StatusObjectService.java
Normal file
@@ -0,0 +1,85 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.status.StatusObject;
|
||||||
|
import zeroecho.pki.api.status.StatusObjectGenerateCommand;
|
||||||
|
import zeroecho.pki.api.status.StatusObjectQuery;
|
||||||
|
import zeroecho.pki.api.status.StatusObjectType;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status object generation and retrieval.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Status objects include CRLs, delta CRLs, OCSP responses, or
|
||||||
|
* framework-specific revocation lists.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface StatusObjectService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Generates a new status object for an issuer CA.
|
||||||
|
*
|
||||||
|
* @param command generation command
|
||||||
|
* @return generated status object
|
||||||
|
* @throws IllegalArgumentException if {@code command} is invalid
|
||||||
|
* @throws PkiException if generation fails
|
||||||
|
*/
|
||||||
|
StatusObject generate(StatusObjectGenerateCommand command);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the latest status object of a given type for an issuer CA.
|
||||||
|
*
|
||||||
|
* @param issuerCaId issuer CA id
|
||||||
|
* @param type status object type
|
||||||
|
* @return latest status object if present
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
* @throws PkiException if retrieval fails
|
||||||
|
*/
|
||||||
|
Optional<StatusObject> getLatest(PkiId issuerCaId, StatusObjectType type);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists status objects matching query constraints.
|
||||||
|
*
|
||||||
|
* @param query query constraints
|
||||||
|
* @return matching status objects
|
||||||
|
* @throws IllegalArgumentException if {@code query} is invalid
|
||||||
|
* @throws PkiException if listing fails
|
||||||
|
*/
|
||||||
|
List<StatusObject> list(StatusObjectQuery query);
|
||||||
|
}
|
||||||
61
pki/src/main/java/zeroecho/pki/api/SubjectRef.java
Normal file
61
pki/src/main/java/zeroecho/pki/api/SubjectRef.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Framework-agnostic subject identifier.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This identifier is used for policy evaluation, inventory queries, and audit
|
||||||
|
* correlation. Framework backends may map it to a distinguished name (DN), a
|
||||||
|
* claims subject, or a service identity, depending on the credential framework.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value non-empty subject reference
|
||||||
|
*/
|
||||||
|
public record SubjectRef(String value) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a subject reference.
|
||||||
|
*
|
||||||
|
* @param value non-empty subject reference
|
||||||
|
* @throws IllegalArgumentException if {@code value} is null or blank
|
||||||
|
*/
|
||||||
|
public SubjectRef {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("value must not be null/blank");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
74
pki/src/main/java/zeroecho/pki/api/Validity.java
Normal file
74
pki/src/main/java/zeroecho/pki/api/Validity.java
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validity interval for an issued credential.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The PKI core requires {@code notAfter} to be strictly after
|
||||||
|
* {@code notBefore}. Framework-specific interpretations (inclusive/exclusive)
|
||||||
|
* are resolved by the framework backend.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Policy and profile constraints (maximum lifetime, not-before skew) must be
|
||||||
|
* enforced by the PKI runtime.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param notBefore start of validity interval (inclusive)
|
||||||
|
* @param notAfter end of validity interval (must be after {@code notBefore})
|
||||||
|
*/
|
||||||
|
public record Validity(Instant notBefore, Instant notAfter) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a validity interval.
|
||||||
|
*
|
||||||
|
* @param notBefore start of validity interval (inclusive)
|
||||||
|
* @param notAfter end of validity interval
|
||||||
|
* @throws IllegalArgumentException if inputs are null or the interval is
|
||||||
|
* invalid
|
||||||
|
*/
|
||||||
|
public Validity {
|
||||||
|
if (notBefore == null || notAfter == null) {
|
||||||
|
throw new IllegalArgumentException("notBefore/notAfter must not be null");
|
||||||
|
}
|
||||||
|
if (!notAfter.isAfter(notBefore)) {
|
||||||
|
throw new IllegalArgumentException("notAfter must be after notBefore");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.attr;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Governance hints controlling auditing and exportability of an attribute.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This model is intentionally minimal. Implementations may interpret it via a
|
||||||
|
* richer policy decision point (roles, purposes, tenants), but the presence of
|
||||||
|
* these hints allows consistent enforcement and auditing.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param auditOnAllow if true, successful accesses should be audited
|
||||||
|
* @param auditOnDeny if true, denied accesses should be audited
|
||||||
|
* @param exportTargets allowed export targets
|
||||||
|
*/
|
||||||
|
public record AttributeAccessPolicy(boolean auditOnAllow, boolean auditOnDeny,
|
||||||
|
Set<AttributeExportTarget> exportTargets) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an access policy.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if {@code exportTargets} is null
|
||||||
|
*/
|
||||||
|
public AttributeAccessPolicy {
|
||||||
|
if (exportTargets == null) {
|
||||||
|
throw new IllegalArgumentException("exportTargets must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.attr;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Registry/catalogue of attribute definitions.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The catalogue is the shared vocabulary across credential frameworks.
|
||||||
|
* Identifiers must never be reused with a different meaning. Definitions should
|
||||||
|
* be versioned under a controlled process.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface AttributeCatalogue {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Finds a definition by id.
|
||||||
|
*
|
||||||
|
* @param id attribute id
|
||||||
|
* @return definition if present
|
||||||
|
* @throws IllegalArgumentException if {@code id} is null
|
||||||
|
*/
|
||||||
|
Optional<AttributeDefinition> find(AttributeId id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lists all known definitions.
|
||||||
|
*
|
||||||
|
* @return list of definitions
|
||||||
|
*/
|
||||||
|
List<AttributeDefinition> listAll();
|
||||||
|
}
|
||||||
@@ -0,0 +1,75 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.attr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typed and governed attribute definition used across credential frameworks.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The definition includes a stable identifier, type information, documentation
|
||||||
|
* metadata, and governance hints. Frameworks map universal attributes into
|
||||||
|
* framework-specific fields and extensions.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param id stable attribute identifier
|
||||||
|
* @param displayName human-readable name
|
||||||
|
* @param valueType logical value type
|
||||||
|
* @param multiValued whether multiple values are allowed
|
||||||
|
* @param sensitivity sensitivity classification
|
||||||
|
* @param stability lifecycle maturity
|
||||||
|
* @param accessPolicy governance hints
|
||||||
|
* @param meta structured documentation metadata
|
||||||
|
*/
|
||||||
|
public record AttributeDefinition(AttributeId id, String displayName, AttributeValueType valueType, boolean multiValued,
|
||||||
|
AttributeSensitivity sensitivity, AttributeStability stability, AttributeAccessPolicy accessPolicy,
|
||||||
|
AttributeMeta meta) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an attribute definition.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
*/
|
||||||
|
public AttributeDefinition {
|
||||||
|
if (id == null) {
|
||||||
|
throw new IllegalArgumentException("id must not be null");
|
||||||
|
}
|
||||||
|
if (displayName == null || displayName.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("displayName must not be null/blank");
|
||||||
|
}
|
||||||
|
if (valueType == null || sensitivity == null || stability == null || accessPolicy == null || meta == null) {
|
||||||
|
throw new IllegalArgumentException("non-null fields must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,66 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.attr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Named export targets used by governance and publication pipelines.
|
||||||
|
*/
|
||||||
|
public enum AttributeExportTarget {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export via a programmatic API.
|
||||||
|
*/
|
||||||
|
API,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export for UI rendering.
|
||||||
|
*/
|
||||||
|
UI,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export to LDAP directory.
|
||||||
|
*/
|
||||||
|
LDAP,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export to backups.
|
||||||
|
*/
|
||||||
|
BACKUP,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export to diagnostics/debugging channels (typically heavily redacted).
|
||||||
|
*/
|
||||||
|
DIAGNOSTICS
|
||||||
|
}
|
||||||
61
pki/src/main/java/zeroecho/pki/api/attr/AttributeId.java
Normal file
61
pki/src/main/java/zeroecho/pki/api/attr/AttributeId.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.attr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stable attribute identifier used by the attribute catalogue.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Identifiers should be globally stable (recommended as OIDs under a project or
|
||||||
|
* enterprise arc). Identifiers must never be reused with a different semantic
|
||||||
|
* meaning.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value non-empty identifier string
|
||||||
|
*/
|
||||||
|
public record AttributeId(String value) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an attribute identifier.
|
||||||
|
*
|
||||||
|
* @param value non-empty identifier string
|
||||||
|
* @throws IllegalArgumentException if {@code value} is null or blank
|
||||||
|
*/
|
||||||
|
public AttributeId {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("value must not be null/blank");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
81
pki/src/main/java/zeroecho/pki/api/attr/AttributeMeta.java
Normal file
81
pki/src/main/java/zeroecho/pki/api/attr/AttributeMeta.java
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.attr;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structured, human-facing documentation metadata for an attribute definition.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This metadata is intended to be rendered in operator tooling, APIs, and UI.
|
||||||
|
* It must not contain secrets.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param description normative description of meaning and usage
|
||||||
|
* @param notes additional guidance and security considerations
|
||||||
|
* @param examples example values (must not contain secrets)
|
||||||
|
* @param tags classification tags (e.g., "identity", "x509", "san")
|
||||||
|
* @param extra additional annotations for future extensions
|
||||||
|
* (non-sensitive)
|
||||||
|
*/
|
||||||
|
public record AttributeMeta(String description, List<String> notes, List<String> examples, List<String> tags,
|
||||||
|
Map<String, String> extra) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates attribute metadata.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid or collections/maps
|
||||||
|
* are null
|
||||||
|
*/
|
||||||
|
public AttributeMeta {
|
||||||
|
if (description == null || description.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("description must not be null/blank");
|
||||||
|
}
|
||||||
|
if (notes == null) {
|
||||||
|
throw new IllegalArgumentException("notes must not be null");
|
||||||
|
}
|
||||||
|
if (examples == null) {
|
||||||
|
throw new IllegalArgumentException("examples must not be null");
|
||||||
|
}
|
||||||
|
if (tags == null) {
|
||||||
|
throw new IllegalArgumentException("tags must not be null");
|
||||||
|
}
|
||||||
|
if (extra == null) {
|
||||||
|
throw new IllegalArgumentException("extra must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.attr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data sensitivity classification for an attribute.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Sensitivity influences default auditing/export/redaction behavior.
|
||||||
|
* Implementations must ensure that SECRET and SENSITIVE values are not exposed
|
||||||
|
* to logs or unauthorized channels.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public enum AttributeSensitivity {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public value; can be disclosed broadly.
|
||||||
|
*/
|
||||||
|
PUBLIC,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Internal operational value; restricted to internal components and operators.
|
||||||
|
*/
|
||||||
|
INTERNAL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sensitive value; disclosure may create security or privacy risk.
|
||||||
|
*/
|
||||||
|
SENSITIVE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Secret value; must not be disclosed outside the strictest trust boundary.
|
||||||
|
*/
|
||||||
|
SECRET
|
||||||
|
}
|
||||||
82
pki/src/main/java/zeroecho/pki/api/attr/AttributeSet.java
Normal file
82
pki/src/main/java/zeroecho/pki/api/attr/AttributeSet.java
Normal file
@@ -0,0 +1,82 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.attr;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Immutable set of typed attributes.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This is a passive container. Production code is expected to mediate
|
||||||
|
* read/write/export/derive operations through a governance/enforcement layer
|
||||||
|
* that performs ACL checks and emits audit events.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface AttributeSet {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns all attribute identifiers present in this set.
|
||||||
|
*
|
||||||
|
* @return set of attribute ids
|
||||||
|
*/
|
||||||
|
Set<AttributeId> ids();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a single-valued attribute.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* If the attribute is multi-valued, implementations may return empty or one
|
||||||
|
* chosen value; callers should prefer {@link #getAll(AttributeId)} when
|
||||||
|
* multi-valued is expected.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param id attribute id
|
||||||
|
* @return attribute value if present
|
||||||
|
* @throws IllegalArgumentException if {@code id} is null
|
||||||
|
*/
|
||||||
|
Optional<AttributeValue> get(AttributeId id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads a potentially multi-valued attribute.
|
||||||
|
*
|
||||||
|
* @param id attribute id
|
||||||
|
* @return list of values (empty if absent)
|
||||||
|
* @throws IllegalArgumentException if {@code id} is null
|
||||||
|
*/
|
||||||
|
List<AttributeValue> getAll(AttributeId id);
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.attr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Lifecycle maturity of an attribute definition.
|
||||||
|
*/
|
||||||
|
public enum AttributeStability {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute is stable and recommended for general use.
|
||||||
|
*/
|
||||||
|
STABLE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute is experimental and may change under a controlled evolution
|
||||||
|
* process.
|
||||||
|
*/
|
||||||
|
EXPERIMENTAL,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attribute is deprecated and should not be used for new profiles.
|
||||||
|
*/
|
||||||
|
DEPRECATED
|
||||||
|
}
|
||||||
131
pki/src/main/java/zeroecho/pki/api/attr/AttributeValue.java
Normal file
131
pki/src/main/java/zeroecho/pki/api/attr/AttributeValue.java
Normal file
@@ -0,0 +1,131 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.attr;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Typed attribute value.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Values are modeled as a sealed hierarchy for type safety and deterministic
|
||||||
|
* mapping. Implementations must treat values as potentially sensitive and apply
|
||||||
|
* redaction where required.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public sealed interface AttributeValue permits AttributeValue.StringValue, AttributeValue.BooleanValue,
|
||||||
|
AttributeValue.IntegerValue, AttributeValue.InstantValue, AttributeValue.BytesValue {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* String value.
|
||||||
|
*
|
||||||
|
* @param value string content (may be empty depending on attribute definition)
|
||||||
|
*/
|
||||||
|
record StringValue(String value) implements AttributeValue {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a string value.
|
||||||
|
*
|
||||||
|
* @param value string content
|
||||||
|
* @throws IllegalArgumentException if {@code value} is null
|
||||||
|
*/
|
||||||
|
public StringValue {
|
||||||
|
if (value == null) {
|
||||||
|
throw new IllegalArgumentException("value must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boolean value.
|
||||||
|
*
|
||||||
|
* @param value boolean content
|
||||||
|
*/
|
||||||
|
record BooleanValue(boolean value) implements AttributeValue {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integer/long value.
|
||||||
|
*
|
||||||
|
* @param value numeric content
|
||||||
|
*/
|
||||||
|
record IntegerValue(long value) implements AttributeValue {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instant value.
|
||||||
|
*
|
||||||
|
* @param value timestamp content
|
||||||
|
*/
|
||||||
|
record InstantValue(Instant value) implements AttributeValue {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instant value.
|
||||||
|
*
|
||||||
|
* @param value timestamp
|
||||||
|
* @throws IllegalArgumentException if {@code value} is null
|
||||||
|
*/
|
||||||
|
public InstantValue {
|
||||||
|
if (value == null) {
|
||||||
|
throw new IllegalArgumentException("value must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Byte string value.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Byte values should be treated as potentially sensitive. Implementations must
|
||||||
|
* not log full contents.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value non-empty byte array
|
||||||
|
*/
|
||||||
|
record BytesValue(byte[] value) implements AttributeValue {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a byte string value.
|
||||||
|
*
|
||||||
|
* @param value byte array (non-empty)
|
||||||
|
* @throws IllegalArgumentException if {@code value} is null or empty
|
||||||
|
*/
|
||||||
|
public BytesValue {
|
||||||
|
if (value == null || value.length == 0) {
|
||||||
|
throw new IllegalArgumentException("value must not be null/empty");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,98 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.attr;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declares the logical value type of an attribute.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Framework backends map these logical types into framework-specific constructs
|
||||||
|
* (e.g., X.509 extensions, claims, or other credential fields).
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public enum AttributeValueType {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* UTF-8 string value.
|
||||||
|
*/
|
||||||
|
STRING,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Boolean value.
|
||||||
|
*/
|
||||||
|
BOOLEAN,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Integer/long value.
|
||||||
|
*/
|
||||||
|
INTEGER,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Timestamp value.
|
||||||
|
*/
|
||||||
|
INSTANT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Raw byte string.
|
||||||
|
*/
|
||||||
|
BYTES,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Object identifier string.
|
||||||
|
*/
|
||||||
|
OID,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Distinguished Name representation (string form with normalization rules
|
||||||
|
* defined by profile/policy).
|
||||||
|
*/
|
||||||
|
DN,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* GeneralName-like identity (DNS/IP/URI/email/etc.) represented in a canonical
|
||||||
|
* structured form.
|
||||||
|
*/
|
||||||
|
GENERAL_NAME,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Public key information representation (e.g., SPKI).
|
||||||
|
*/
|
||||||
|
KEY_INFO,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Structured composite value.
|
||||||
|
*/
|
||||||
|
STRUCT
|
||||||
|
}
|
||||||
62
pki/src/main/java/zeroecho/pki/api/attr/package-info.java
Normal file
62
pki/src/main/java/zeroecho/pki/api/attr/package-info.java
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* Attribute catalogue and attribute-level modeling.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This package defines a typed attribute system used across the PKI API and
|
||||||
|
* independent of any specific credential framework. Attributes are described
|
||||||
|
* through definitions and metadata and carried in structured containers to
|
||||||
|
* support safe reuse and deterministic mapping into concrete frameworks (e.g.,
|
||||||
|
* via a framework attribute mapper SPI).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Typical responsibilities</h2>
|
||||||
|
* <ul>
|
||||||
|
* <li>Define attribute identity and value types.</li>
|
||||||
|
* <li>Provide metadata needed for validation and governance (stability,
|
||||||
|
* sensitivity, etc.).</li>
|
||||||
|
* <li>Support export/import targets without binding to a certificate
|
||||||
|
* format.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Access control and governance for attribute access is described in
|
||||||
|
* {@code zeroecho.pki.api.audit}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
package zeroecho.pki.api.attr;
|
||||||
61
pki/src/main/java/zeroecho/pki/api/audit/AccessAction.java
Normal file
61
pki/src/main/java/zeroecho/pki/api/audit/AccessAction.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.audit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Action performed on an attribute for access governance.
|
||||||
|
*/
|
||||||
|
public enum AccessAction {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Read an attribute value.
|
||||||
|
*/
|
||||||
|
READ,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Write or modify an attribute value.
|
||||||
|
*/
|
||||||
|
WRITE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Export attribute value to an external channel (e.g., UI, LDAP, backups).
|
||||||
|
*/
|
||||||
|
EXPORT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derive/computed attribute value from other sources.
|
||||||
|
*/
|
||||||
|
DERIVE
|
||||||
|
}
|
||||||
74
pki/src/main/java/zeroecho/pki/api/audit/AccessContext.java
Normal file
74
pki/src/main/java/zeroecho/pki/api/audit/AccessContext.java
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.audit;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.FormatId;
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Context used for attribute ACL checks and audit correlation.
|
||||||
|
*
|
||||||
|
* @param principal actor requesting access
|
||||||
|
* @param purpose declared purpose of access
|
||||||
|
* @param objectId optional object id being accessed (credential id, request
|
||||||
|
* id, etc.)
|
||||||
|
* @param formatId optional format id relevant to the object being accessed
|
||||||
|
*/
|
||||||
|
public record AccessContext(Principal principal, Purpose purpose, Optional<PkiId> objectId,
|
||||||
|
Optional<FormatId> formatId) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an access context.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if mandatory inputs are null or optional
|
||||||
|
* containers are null
|
||||||
|
*/
|
||||||
|
public AccessContext {
|
||||||
|
if (principal == null) {
|
||||||
|
throw new IllegalArgumentException("principal must not be null");
|
||||||
|
}
|
||||||
|
if (purpose == null) {
|
||||||
|
throw new IllegalArgumentException("purpose must not be null");
|
||||||
|
}
|
||||||
|
if (objectId == null) {
|
||||||
|
throw new IllegalArgumentException("objectId must not be null");
|
||||||
|
}
|
||||||
|
if (formatId == null) {
|
||||||
|
throw new IllegalArgumentException("formatId must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
pki/src/main/java/zeroecho/pki/api/audit/AccessDecision.java
Normal file
51
pki/src/main/java/zeroecho/pki/api/audit/AccessDecision.java
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.audit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Decision outcome of an access control check.
|
||||||
|
*/
|
||||||
|
public enum AccessDecision {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access is allowed.
|
||||||
|
*/
|
||||||
|
ALLOW,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Access is denied.
|
||||||
|
*/
|
||||||
|
DENY
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.audit;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.attr.AttributeDefinition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Policy decision point for attribute-level access control.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This interface decides whether an attribute action is permitted given the
|
||||||
|
* attribute definition and the access context. A separate enforcement layer is
|
||||||
|
* expected to record audit events.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
@FunctionalInterface
|
||||||
|
public interface AttributeAccessController {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates an access request.
|
||||||
|
*
|
||||||
|
* @param definition attribute definition
|
||||||
|
* @param action access action
|
||||||
|
* @param context access context
|
||||||
|
* @return allow/deny decision
|
||||||
|
* @throws IllegalArgumentException if inputs are null
|
||||||
|
*/
|
||||||
|
AccessDecision decide(AttributeDefinition definition, AccessAction action, AccessContext context);
|
||||||
|
}
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.audit;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.attr.AttributeCatalogue;
|
||||||
|
import zeroecho.pki.api.attr.AttributeId;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
import zeroecho.pki.api.attr.AttributeValue;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Policy enforcement point for attribute access with mandatory auditing.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* All attribute read/write/export/derive operations should be performed through
|
||||||
|
* this service to ensure: (1) consistent ACL evaluation and (2) consistent
|
||||||
|
* audit event emission.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface AttributeGovernanceService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads an attribute value after applying access control.
|
||||||
|
*
|
||||||
|
* @param catalogue attribute catalogue used to resolve definitions
|
||||||
|
* @param set attribute set being accessed
|
||||||
|
* @param id attribute id
|
||||||
|
* @param context access context
|
||||||
|
* @return value if present and access is allowed; empty otherwise
|
||||||
|
* @throws IllegalArgumentException if inputs are null
|
||||||
|
*/
|
||||||
|
Optional<AttributeValue> read(AttributeCatalogue catalogue, AttributeSet set, AttributeId id,
|
||||||
|
AccessContext context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes an attribute value after applying access control.
|
||||||
|
*
|
||||||
|
* @param catalogue attribute catalogue used to resolve definitions
|
||||||
|
* @param set attribute set being modified
|
||||||
|
* @param id attribute id
|
||||||
|
* @param value value to write
|
||||||
|
* @param context access context
|
||||||
|
* @return new attribute set instance containing the updated value
|
||||||
|
* @throws IllegalArgumentException if inputs are null
|
||||||
|
*/
|
||||||
|
AttributeSet write(AttributeCatalogue catalogue, AttributeSet set, AttributeId id, AttributeValue value,
|
||||||
|
AccessContext context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Exports an attribute value after applying access control.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Export may imply redaction. The exact redaction rules are
|
||||||
|
* implementation-defined and should take attribute sensitivity and export
|
||||||
|
* target into account.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param catalogue attribute catalogue used to resolve definitions
|
||||||
|
* @param set attribute set being exported from
|
||||||
|
* @param id attribute id
|
||||||
|
* @param context access context
|
||||||
|
* @return exported value if present and allowed; empty otherwise
|
||||||
|
* @throws IllegalArgumentException if inputs are null
|
||||||
|
*/
|
||||||
|
Optional<AttributeValue> export(AttributeCatalogue catalogue, AttributeSet set, AttributeId id,
|
||||||
|
AccessContext context);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derives an attribute value from other inputs after applying access control.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Derivation may be used to compute attributes such as fingerprints or
|
||||||
|
* normalized identity fields.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param catalogue attribute catalogue used to resolve definitions
|
||||||
|
* @param set attribute set being modified
|
||||||
|
* @param id attribute id
|
||||||
|
* @param context access context
|
||||||
|
* @return new attribute set instance containing the derived value
|
||||||
|
* (implementation-defined)
|
||||||
|
* @throws IllegalArgumentException if inputs are null
|
||||||
|
*/
|
||||||
|
AttributeSet derive(AttributeCatalogue catalogue, AttributeSet set, AttributeId id, AccessContext context);
|
||||||
|
}
|
||||||
213
pki/src/main/java/zeroecho/pki/api/audit/AuditEvent.java
Normal file
213
pki/src/main/java/zeroecho/pki/api/audit/AuditEvent.java
Normal file
@@ -0,0 +1,213 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.audit;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Comparator;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.FormatId;
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Auditable event emitted by the PKI core and governance layer.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* An {@code AuditEvent} is an immutable, structured record describing a
|
||||||
|
* security-relevant action or outcome. Typical event categories include
|
||||||
|
* high-level PKI operations (issuance, revocation, publication, backup) and
|
||||||
|
* attribute-level governance decisions (read/export attempts and outcomes).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Security properties</h2>
|
||||||
|
* <ul>
|
||||||
|
* <li><strong>No secrets:</strong> {@link #details()} MUST NOT contain secrets
|
||||||
|
* (keys, seeds, shared secrets, plaintext, private material, or other sensitive
|
||||||
|
* cryptographic/internal state). It is intended for non-sensitive metadata only
|
||||||
|
* (e.g., decision, policy id, reason codes, counters).</li>
|
||||||
|
* <li><strong>Minimality:</strong> callers should prefer coarse,
|
||||||
|
* non-identifying fields and avoid excessive detail. If an identifier is
|
||||||
|
* needed, prefer {@link #objectId()} and a stable, non-secret reference.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <h2>Determinism and ordering</h2>
|
||||||
|
* <p>
|
||||||
|
* The static comparator returned by {@link #auditOrder()} defines a
|
||||||
|
* deterministic order for presentation and query results. It does not imply
|
||||||
|
* causality; it is purely a stable sort key.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Validation</h2>
|
||||||
|
* <p>
|
||||||
|
* This record enforces basic invariants: time is non-null, {@code category} and
|
||||||
|
* {@code action} are non-blank, {@code principal} and {@code purpose} are
|
||||||
|
* non-null, and optional containers/maps are non-null.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param time event time (server time), never {@code null}
|
||||||
|
* @param category non-blank category (e.g., {@code "ISSUANCE"},
|
||||||
|
* {@code "REVOCATION"}, {@code "ATTRIBUTE_ACCESS"})
|
||||||
|
* @param action non-blank action string (e.g., {@code "ISSUE_END_ENTITY"},
|
||||||
|
* {@code "REVOKE"}, {@code "READ"})
|
||||||
|
* @param principal actor responsible for the event, never {@code null}
|
||||||
|
* @param purpose declared purpose of the operation/access, never {@code null}
|
||||||
|
* @param objectId optional subject object id (credential id, request id,
|
||||||
|
* attribute id, etc.), never {@code null}
|
||||||
|
* @param formatId optional format id related to the object (e.g., encoding),
|
||||||
|
* never {@code null}
|
||||||
|
* @param details additional non-sensitive key/value details, never
|
||||||
|
* {@code null}
|
||||||
|
*/
|
||||||
|
public record AuditEvent(Instant time, String category, String action, Principal principal, Purpose purpose,
|
||||||
|
Optional<PkiId> objectId, Optional<FormatId> formatId, Map<String, String> details) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an audit event and validates record invariants.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Note that this constructor does not (and cannot) automatically prove the
|
||||||
|
* absence of secrets in {@link #details()}. The responsibility to redact and
|
||||||
|
* constrain details is on the event producer.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if {@code time} is {@code null},
|
||||||
|
* {@code category/action} are blank,
|
||||||
|
* {@code principal/purpose} are {@code null},
|
||||||
|
* or any of {@code objectId/formatId/details}
|
||||||
|
* are {@code null}
|
||||||
|
*/
|
||||||
|
public AuditEvent {
|
||||||
|
if (time == null) {
|
||||||
|
throw new IllegalArgumentException("time must not be null");
|
||||||
|
}
|
||||||
|
if (category == null || category.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("category must not be null/blank");
|
||||||
|
}
|
||||||
|
if (action == null || action.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("action must not be null/blank");
|
||||||
|
}
|
||||||
|
if (principal == null) {
|
||||||
|
throw new IllegalArgumentException("principal must not be null");
|
||||||
|
}
|
||||||
|
if (purpose == null) {
|
||||||
|
throw new IllegalArgumentException("purpose must not be null");
|
||||||
|
}
|
||||||
|
if (objectId == null) {
|
||||||
|
throw new IllegalArgumentException("objectId must not be null");
|
||||||
|
}
|
||||||
|
if (formatId == null) {
|
||||||
|
throw new IllegalArgumentException("formatId must not be null");
|
||||||
|
}
|
||||||
|
if (details == null) {
|
||||||
|
throw new IllegalArgumentException("details must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns a deterministic comparator for audit events.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The comparator orders events by: {@code time}, {@code category},
|
||||||
|
* {@code action}, {@code principal.type}, {@code principal.name}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This ordering is intended for consistent presentation and stable test
|
||||||
|
* assertions. It is not a security primitive.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @return deterministic comparator, never {@code null}
|
||||||
|
*/
|
||||||
|
public static Comparator<AuditEvent> auditOrder() {
|
||||||
|
return Comparator.comparing(AuditEvent::time).thenComparing(AuditEvent::category)
|
||||||
|
.thenComparing(AuditEvent::action).thenComparing(e -> e.principal().type())
|
||||||
|
.thenComparing(e -> e.principal().name());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Evaluates whether this event matches a query constraint set.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Matching semantics:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>If {@code query.category} is present, it must equal
|
||||||
|
* {@link #category()}.</li>
|
||||||
|
* <li>If {@code query.action} is present, it must equal {@link #action()}.</li>
|
||||||
|
* <li>If {@code query.after} is present, event time must be {@code >= after}
|
||||||
|
* (implemented as {@code !time.isBefore(after)}).</li>
|
||||||
|
* <li>If {@code query.before} is present, event time must be {@code <= before}
|
||||||
|
* (implemented as {@code !time.isAfter(before)}).</li>
|
||||||
|
* <li>If {@code query.objectId} is present, it must equal {@link #objectId()}
|
||||||
|
* (empty optional does not match).</li>
|
||||||
|
* <li>If {@code query.principalName} is present, it must equal
|
||||||
|
* {@link #principal()}.{@code name()}.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This method is side-effect free and deterministic.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param query query constraints, must not be {@code null}
|
||||||
|
* @return {@code true} if this event matches all present constraints;
|
||||||
|
* {@code false} otherwise
|
||||||
|
* @throws NullPointerException if {@code query} is {@code null}
|
||||||
|
*/
|
||||||
|
public boolean matches(AuditQuery query) {
|
||||||
|
Objects.requireNonNull(query, "query");
|
||||||
|
|
||||||
|
if (query.category().isPresent() && !query.category().get().equals(category())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (query.action().isPresent() && !query.action().get().equals(action())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (query.after().isPresent() && time().isBefore(query.after().get())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (query.before().isPresent() && time().isAfter(query.before().get())) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (query.objectId().isPresent() && !query.objectId().get().equals(objectId().orElse(null))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (query.principalName().isPresent() && !query.principalName().get().equals(principal().name())) { // NOPMD
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
66
pki/src/main/java/zeroecho/pki/api/audit/AuditQuery.java
Normal file
66
pki/src/main/java/zeroecho/pki/api/audit/AuditQuery.java
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.audit;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query constraints for searching audit events.
|
||||||
|
*
|
||||||
|
* @param category optional category filter
|
||||||
|
* @param action optional action filter
|
||||||
|
* @param after optional lower bound for event time
|
||||||
|
* @param before optional upper bound for event time
|
||||||
|
* @param objectId optional object id filter
|
||||||
|
* @param principalName optional principal name filter
|
||||||
|
*/
|
||||||
|
public record AuditQuery(Optional<String> category, Optional<String> action, Optional<Instant> after,
|
||||||
|
Optional<Instant> before, Optional<PkiId> objectId, Optional<String> principalName) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an audit query.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if any optional container is null
|
||||||
|
*/
|
||||||
|
public AuditQuery {
|
||||||
|
if (category == null || action == null || after == null || before == null || objectId == null
|
||||||
|
|| principalName == null) {
|
||||||
|
throw new IllegalArgumentException("optional fields must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
80
pki/src/main/java/zeroecho/pki/api/audit/AuditService.java
Normal file
80
pki/src/main/java/zeroecho/pki/api/audit/AuditService.java
Normal file
@@ -0,0 +1,80 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.audit;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records and queries audit events for PKI operations and attribute governance.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Implementations must ensure sensitive data is never stored or logged in clear
|
||||||
|
* text.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public interface AuditService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Records an audit event.
|
||||||
|
*
|
||||||
|
* @param event audit event
|
||||||
|
* @throws IllegalArgumentException if {@code event} is null
|
||||||
|
* @throws RuntimeException if recording fails (implementation-defined)
|
||||||
|
*/
|
||||||
|
void record(AuditEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches audit events by query constraints.
|
||||||
|
*
|
||||||
|
* @param query query constraints
|
||||||
|
* @return matching audit events
|
||||||
|
* @throws IllegalArgumentException if {@code query} is null
|
||||||
|
* @throws RuntimeException if search fails
|
||||||
|
*/
|
||||||
|
List<AuditEvent> search(AuditQuery query);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves an audit event by id if the implementation assigns stable ids.
|
||||||
|
*
|
||||||
|
* @param eventId event id
|
||||||
|
* @return audit event if present
|
||||||
|
* @throws IllegalArgumentException if {@code eventId} is null
|
||||||
|
* @throws RuntimeException if retrieval fails
|
||||||
|
*/
|
||||||
|
Optional<AuditEvent> get(PkiId eventId);
|
||||||
|
}
|
||||||
63
pki/src/main/java/zeroecho/pki/api/audit/Principal.java
Normal file
63
pki/src/main/java/zeroecho/pki/api/audit/Principal.java
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.audit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Identifies an actor performing an operation or requesting access.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* A principal may represent a human user, service account, subsystem component,
|
||||||
|
* or a scheduled job.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param type principal type (e.g., "USER", "SERVICE", "COMPONENT")
|
||||||
|
* @param name principal name/identifier
|
||||||
|
*/
|
||||||
|
public record Principal(String type, String name) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a principal.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are null/blank
|
||||||
|
*/
|
||||||
|
public Principal {
|
||||||
|
if (type == null || type.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("type must not be null/blank");
|
||||||
|
}
|
||||||
|
if (name == null || name.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("name must not be null/blank");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
pki/src/main/java/zeroecho/pki/api/audit/Purpose.java
Normal file
59
pki/src/main/java/zeroecho/pki/api/audit/Purpose.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.audit;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Declares the purpose of an operation/access for governance and auditing.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Examples: {@code ISSUANCE}, {@code VALIDATION}, {@code UI_RENDER},
|
||||||
|
* {@code BACKUP_EXPORT}, {@code LDAP_PUBLISH}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param value non-empty purpose string
|
||||||
|
*/
|
||||||
|
public record Purpose(String value) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a purpose.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if {@code value} is null/blank
|
||||||
|
*/
|
||||||
|
public Purpose {
|
||||||
|
if (value == null || value.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("value must not be null/blank");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
59
pki/src/main/java/zeroecho/pki/api/audit/package-info.java
Normal file
59
pki/src/main/java/zeroecho/pki/api/audit/package-info.java
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* Audit and governance API.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This package defines audit events, principals, purposes, queries, and
|
||||||
|
* attribute-access governance abstractions used to support compliance and
|
||||||
|
* operational forensics.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Security</h2>
|
||||||
|
* <ul>
|
||||||
|
* <li>Audit events MUST NOT contain private keys, shared secrets, or plaintext
|
||||||
|
* sensitive content.</li>
|
||||||
|
* <li>Audit records should be structured and stable for long-term retention and
|
||||||
|
* analysis.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The persistence and routing of audit events is an SPI concern (e.g.,
|
||||||
|
* {@code zeroecho.pki.spi.AuditSink}).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
package zeroecho.pki.api.audit;
|
||||||
@@ -0,0 +1,69 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.backup;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.BackupService;
|
||||||
|
import zeroecho.pki.api.EncodedObject;
|
||||||
|
import zeroecho.pki.api.Encoding;
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Opaque backup artifact produced by {@link BackupService}.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The payload is typically {@link Encoding#BINARY}. The internal structure is
|
||||||
|
* implementation-defined (e.g., tar/zip-like). Consumers should treat it as
|
||||||
|
* opaque.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param backupId backup identifier
|
||||||
|
* @param payload backup payload bytes
|
||||||
|
*/
|
||||||
|
public record BackupArtifact(PkiId backupId, EncodedObject payload) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a backup artifact.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are null
|
||||||
|
*/
|
||||||
|
public BackupArtifact {
|
||||||
|
if (backupId == null) {
|
||||||
|
throw new IllegalArgumentException("backupId must not be null");
|
||||||
|
}
|
||||||
|
if (payload == null) {
|
||||||
|
throw new IllegalArgumentException("payload must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
pki/src/main/java/zeroecho/pki/api/backup/BackupRequest.java
Normal file
68
pki/src/main/java/zeroecho/pki/api/backup/BackupRequest.java
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.backup;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.KeyRef;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests creation of a PKI backup.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Backups are expected to contain PKI state (CAs, credentials, requests,
|
||||||
|
* revocations, profiles, publication records, policy traces). Private keys are
|
||||||
|
* excluded and referenced via {@link KeyRef}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param label operator-provided label for human identification
|
||||||
|
* @param attributes optional backup metadata (may be empty but not null)
|
||||||
|
*/
|
||||||
|
public record BackupRequest(String label, AttributeSet attributes) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a backup request.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if {@code label} is null/blank or
|
||||||
|
* {@code attributes} is null
|
||||||
|
*/
|
||||||
|
public BackupRequest {
|
||||||
|
if (label == null || label.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("label must not be null/blank");
|
||||||
|
}
|
||||||
|
if (attributes == null) {
|
||||||
|
throw new IllegalArgumentException("attributes must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.backup;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Verification results for a backup artifact.
|
||||||
|
*
|
||||||
|
* @param valid true if the artifact is structurally valid and integrity checks
|
||||||
|
* passed
|
||||||
|
* @param issues list of issues found (non-sensitive)
|
||||||
|
*/
|
||||||
|
public record BackupVerificationReport(boolean valid, List<String> issues) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a backup verification report.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if {@code issues} is null
|
||||||
|
*/
|
||||||
|
public BackupVerificationReport {
|
||||||
|
if (issues == null) {
|
||||||
|
throw new IllegalArgumentException("issues must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
68
pki/src/main/java/zeroecho/pki/api/backup/RestoreReport.java
Normal file
68
pki/src/main/java/zeroecho/pki/api/backup/RestoreReport.java
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.backup;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Result report for a restore operation.
|
||||||
|
*
|
||||||
|
* @param restoreId restore identifier
|
||||||
|
* @param success true if restore completed successfully
|
||||||
|
* @param warnings operator-readable warnings (non-sensitive)
|
||||||
|
* @param errors operator-readable errors (non-sensitive)
|
||||||
|
*/
|
||||||
|
public record RestoreReport(PkiId restoreId, boolean success, List<String> warnings, List<String> errors) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a restore report.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if {@code restoreId} is null or lists are
|
||||||
|
* null
|
||||||
|
*/
|
||||||
|
public RestoreReport {
|
||||||
|
if (restoreId == null) {
|
||||||
|
throw new IllegalArgumentException("restoreId must not be null");
|
||||||
|
}
|
||||||
|
if (warnings == null) {
|
||||||
|
throw new IllegalArgumentException("warnings must not be null");
|
||||||
|
}
|
||||||
|
if (errors == null) {
|
||||||
|
throw new IllegalArgumentException("errors must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.backup;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Requests restore of PKI state from a backup artifact.
|
||||||
|
*
|
||||||
|
* @param artifact backup artifact
|
||||||
|
* @param attributes optional restore hints (may be empty but not null)
|
||||||
|
*/
|
||||||
|
public record RestoreRequest(BackupArtifact artifact, AttributeSet attributes) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a restore request.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are null
|
||||||
|
*/
|
||||||
|
public RestoreRequest {
|
||||||
|
if (artifact == null) {
|
||||||
|
throw new IllegalArgumentException("artifact must not be null");
|
||||||
|
}
|
||||||
|
if (attributes == null) {
|
||||||
|
throw new IllegalArgumentException("attributes must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
61
pki/src/main/java/zeroecho/pki/api/backup/package-info.java
Normal file
61
pki/src/main/java/zeroecho/pki/api/backup/package-info.java
Normal file
@@ -0,0 +1,61 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* Backup and restore domain model.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This package provides request/response and artifact model types used for
|
||||||
|
* backing up and restoring PKI state. The intent is to support offline escrow,
|
||||||
|
* migration, disaster recovery, and integrity verification workflows.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Scope</h2>
|
||||||
|
* <ul>
|
||||||
|
* <li>Backup artifacts describe exported PKI state suitable for durable
|
||||||
|
* storage.</li>
|
||||||
|
* <li>Verification reports provide evidence that backups are structurally valid
|
||||||
|
* and complete.</li>
|
||||||
|
* <li>Restore requests and reports model controlled restoration
|
||||||
|
* operations.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Concrete serialization formats and transport mechanisms are handled by
|
||||||
|
* services and the transfer layer.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
package zeroecho.pki.api.backup;
|
||||||
86
pki/src/main/java/zeroecho/pki/api/ca/CaCreateCommand.java
Normal file
86
pki/src/main/java/zeroecho/pki/api/ca/CaCreateCommand.java
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.ca;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.FormatId;
|
||||||
|
import zeroecho.pki.api.KeyRef;
|
||||||
|
import zeroecho.pki.api.SubjectRef;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command to create a new root CA entity and issue its initial CA credential.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* If {@code keyRef} is absent, the runtime may generate a new key pair
|
||||||
|
* depending on policy and runtime wiring. This command carries universal
|
||||||
|
* {@code attributes} used by policy and mapping.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param formatId target credential format
|
||||||
|
* @param subjectRef normalized CA subject reference
|
||||||
|
* @param profileId profile id governing issuance and mapping
|
||||||
|
* @param keyRef optional existing key reference; empty requests key
|
||||||
|
* generation
|
||||||
|
* @param attributes universal attributes (may be empty but not null)
|
||||||
|
*/
|
||||||
|
public record CaCreateCommand(FormatId formatId, SubjectRef subjectRef, String profileId, Optional<KeyRef> keyRef,
|
||||||
|
AttributeSet attributes) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a CA create command.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid or optional container
|
||||||
|
* is null
|
||||||
|
*/
|
||||||
|
public CaCreateCommand {
|
||||||
|
if (formatId == null) {
|
||||||
|
throw new IllegalArgumentException("formatId must not be null");
|
||||||
|
}
|
||||||
|
if (subjectRef == null) {
|
||||||
|
throw new IllegalArgumentException("subjectRef must not be null");
|
||||||
|
}
|
||||||
|
if (profileId == null || profileId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("profileId must not be null/blank");
|
||||||
|
}
|
||||||
|
if (keyRef == null) {
|
||||||
|
throw new IllegalArgumentException("keyRef must not be null");
|
||||||
|
}
|
||||||
|
if (attributes == null) {
|
||||||
|
throw new IllegalArgumentException("attributes must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
86
pki/src/main/java/zeroecho/pki/api/ca/CaImportCommand.java
Normal file
86
pki/src/main/java/zeroecho/pki/api/ca/CaImportCommand.java
Normal file
@@ -0,0 +1,86 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.ca;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.EncodedObject;
|
||||||
|
import zeroecho.pki.api.FormatId;
|
||||||
|
import zeroecho.pki.api.KeyRef;
|
||||||
|
import zeroecho.pki.api.SubjectRef;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command to import an existing root CA credential into PKI inventory.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This operation registers a CA entity and associates it with an externally
|
||||||
|
* managed key reference.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param formatId credential format id
|
||||||
|
* @param subjectRef normalized CA subject reference
|
||||||
|
* @param profileId profile id for mapping/constraints
|
||||||
|
* @param keyRef reference to private key material
|
||||||
|
* @param existingCaCredential existing CA credential payload (certificate-like)
|
||||||
|
* @param attributes universal attributes (may be empty but not null)
|
||||||
|
*/
|
||||||
|
public record CaImportCommand(FormatId formatId, SubjectRef subjectRef, String profileId, KeyRef keyRef,
|
||||||
|
EncodedObject existingCaCredential, AttributeSet attributes) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a CA import command.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
*/
|
||||||
|
public CaImportCommand {
|
||||||
|
if (formatId == null) {
|
||||||
|
throw new IllegalArgumentException("formatId must not be null");
|
||||||
|
}
|
||||||
|
if (subjectRef == null) {
|
||||||
|
throw new IllegalArgumentException("subjectRef must not be null");
|
||||||
|
}
|
||||||
|
if (profileId == null || profileId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("profileId must not be null/blank");
|
||||||
|
}
|
||||||
|
if (keyRef == null) {
|
||||||
|
throw new IllegalArgumentException("keyRef must not be null");
|
||||||
|
}
|
||||||
|
if (existingCaCredential == null) {
|
||||||
|
throw new IllegalArgumentException("existingCaCredential must not be null");
|
||||||
|
}
|
||||||
|
if (attributes == null) {
|
||||||
|
throw new IllegalArgumentException("attributes must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,83 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.ca;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.KeyRef;
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command to rotate a CA key reference and issue new corresponding CA
|
||||||
|
* credentials.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Key rotation changes the underlying key material. Historical key references
|
||||||
|
* and credentials must remain discoverable for audit and validation of
|
||||||
|
* previously issued credentials.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param caId CA entity id
|
||||||
|
* @param newKeyRef optional new key reference; empty requests key generation
|
||||||
|
* via runtime wiring
|
||||||
|
* @param issuerCaId optional issuer CA id (required for intermediate rotation;
|
||||||
|
* empty for root depending on policy)
|
||||||
|
* @param attributes universal attributes (may be empty but not null)
|
||||||
|
*/
|
||||||
|
public record CaKeyRotationCommand(PkiId caId, Optional<KeyRef> newKeyRef, Optional<PkiId> issuerCaId,
|
||||||
|
AttributeSet attributes) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a CA key rotation command.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid or optional containers
|
||||||
|
* are null
|
||||||
|
*/
|
||||||
|
public CaKeyRotationCommand {
|
||||||
|
if (caId == null) {
|
||||||
|
throw new IllegalArgumentException("caId must not be null");
|
||||||
|
}
|
||||||
|
if (newKeyRef == null) {
|
||||||
|
throw new IllegalArgumentException("newKeyRef must not be null");
|
||||||
|
}
|
||||||
|
if (issuerCaId == null) {
|
||||||
|
throw new IllegalArgumentException("issuerCaId must not be null");
|
||||||
|
}
|
||||||
|
if (attributes == null) {
|
||||||
|
throw new IllegalArgumentException("attributes must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
51
pki/src/main/java/zeroecho/pki/api/ca/CaKind.java
Normal file
51
pki/src/main/java/zeroecho/pki/api/ca/CaKind.java
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.ca;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Classifies CA entity type.
|
||||||
|
*/
|
||||||
|
public enum CaKind {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Root CA (initial credential is typically self-issued).
|
||||||
|
*/
|
||||||
|
ROOT,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Intermediate CA (issued by another CA).
|
||||||
|
*/
|
||||||
|
INTERMEDIATE
|
||||||
|
}
|
||||||
64
pki/src/main/java/zeroecho/pki/api/ca/CaQuery.java
Normal file
64
pki/src/main/java/zeroecho/pki/api/ca/CaQuery.java
Normal file
@@ -0,0 +1,64 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.ca;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.FormatId;
|
||||||
|
import zeroecho.pki.api.SubjectRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query constraints for listing CA entities.
|
||||||
|
*
|
||||||
|
* @param kind optional CA kind filter
|
||||||
|
* @param state optional state filter
|
||||||
|
* @param formatId optional framework filter (implementation-defined; may map
|
||||||
|
* to CA credential format)
|
||||||
|
* @param subjectRef optional subject filter
|
||||||
|
*/
|
||||||
|
public record CaQuery(Optional<CaKind> kind, Optional<CaState> state, Optional<FormatId> formatId,
|
||||||
|
Optional<SubjectRef> subjectRef) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a CA query.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if any optional container is null
|
||||||
|
*/
|
||||||
|
public CaQuery {
|
||||||
|
if (kind == null || state == null || formatId == null || subjectRef == null) {
|
||||||
|
throw new IllegalArgumentException("optional fields must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
93
pki/src/main/java/zeroecho/pki/api/ca/CaRecord.java
Normal file
93
pki/src/main/java/zeroecho/pki/api/ca/CaRecord.java
Normal file
@@ -0,0 +1,93 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.ca;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.KeyRef;
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.SubjectRef;
|
||||||
|
import zeroecho.pki.api.credential.Credential;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents a CA entity and its issued CA credentials.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* A CA entity may have multiple CA credentials to support:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>cross-signing (multiple issuers for the same subject key),</li>
|
||||||
|
* <li>credential rollover (new CA credential with the same key),</li>
|
||||||
|
* <li>key rotation (new CA key with a new set of credentials).</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param caId CA identifier
|
||||||
|
* @param kind CA kind (root or intermediate)
|
||||||
|
* @param state operational state
|
||||||
|
* @param issuerKeyRef key reference used for issuing operations (private key
|
||||||
|
* reference)
|
||||||
|
* @param subjectRef normalized subject reference
|
||||||
|
* @param caCredentials CA credentials currently associated with the entity
|
||||||
|
* (historical and active)
|
||||||
|
*/
|
||||||
|
public record CaRecord(PkiId caId, CaKind kind, CaState state, KeyRef issuerKeyRef, SubjectRef subjectRef,
|
||||||
|
List<Credential> caCredentials) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a CA record.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are null
|
||||||
|
*/
|
||||||
|
public CaRecord {
|
||||||
|
if (caId == null) {
|
||||||
|
throw new IllegalArgumentException("caId must not be null");
|
||||||
|
}
|
||||||
|
if (kind == null) {
|
||||||
|
throw new IllegalArgumentException("kind must not be null");
|
||||||
|
}
|
||||||
|
if (state == null) {
|
||||||
|
throw new IllegalArgumentException("state must not be null");
|
||||||
|
}
|
||||||
|
if (issuerKeyRef == null) {
|
||||||
|
throw new IllegalArgumentException("issuerKeyRef must not be null");
|
||||||
|
}
|
||||||
|
if (subjectRef == null) {
|
||||||
|
throw new IllegalArgumentException("subjectRef must not be null");
|
||||||
|
}
|
||||||
|
if (caCredentials == null) {
|
||||||
|
throw new IllegalArgumentException("caCredentials must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
81
pki/src/main/java/zeroecho/pki/api/ca/CaRolloverCommand.java
Normal file
81
pki/src/main/java/zeroecho/pki/api/ca/CaRolloverCommand.java
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.ca;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.Validity;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command to roll over a CA credential while keeping the same key reference.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Rollover issues a new CA credential for the CA entity without changing the
|
||||||
|
* underlying key material. Historical credentials remain accessible for audit
|
||||||
|
* and chain selection.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param caId CA entity id
|
||||||
|
* @param issuerCaId optional issuer CA id (empty for self-issued root
|
||||||
|
* rollover where applicable)
|
||||||
|
* @param requestedValidity optional requested validity
|
||||||
|
* @param attributes universal attributes (may be empty but not null)
|
||||||
|
*/
|
||||||
|
public record CaRolloverCommand(PkiId caId, Optional<PkiId> issuerCaId, Optional<Validity> requestedValidity,
|
||||||
|
AttributeSet attributes) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a CA rollover command.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid or optional containers
|
||||||
|
* are null
|
||||||
|
*/
|
||||||
|
public CaRolloverCommand {
|
||||||
|
if (caId == null) {
|
||||||
|
throw new IllegalArgumentException("caId must not be null");
|
||||||
|
}
|
||||||
|
if (issuerCaId == null) {
|
||||||
|
throw new IllegalArgumentException("issuerCaId must not be null");
|
||||||
|
}
|
||||||
|
if (requestedValidity == null) {
|
||||||
|
throw new IllegalArgumentException("requestedValidity must not be null");
|
||||||
|
}
|
||||||
|
if (attributes == null) {
|
||||||
|
throw new IllegalArgumentException("attributes must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
75
pki/src/main/java/zeroecho/pki/api/ca/CaState.java
Normal file
75
pki/src/main/java/zeroecho/pki/api/ca/CaState.java
Normal file
@@ -0,0 +1,75 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.ca;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operational state of a CA entity.
|
||||||
|
*/
|
||||||
|
public enum CaState {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CA is active and may issue new credentials according to policy.
|
||||||
|
*/
|
||||||
|
ACTIVE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CA is retired and must not issue new credentials.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Historical credentials remain available for validation and audit until they
|
||||||
|
* expire or are revoked.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
RETIRED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CA is compromised and must not be used for issuance.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Operators should perform incident response, publish updated status objects,
|
||||||
|
* and rotate trust anchors.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
COMPROMISED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* CA is administratively disabled.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This state is distinct from retirement and may be reversible.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
DISABLED
|
||||||
|
}
|
||||||
@@ -0,0 +1,90 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.ca;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.FormatId;
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.Validity;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command to issue a new CA credential for an existing intermediate CA entity.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This command supports cross-signing (issuing with a different issuer CA) and
|
||||||
|
* renewal scenarios.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param formatId credential format id
|
||||||
|
* @param issuerCaId issuer CA entity id
|
||||||
|
* @param subjectCaId subject CA entity id (the intermediate being
|
||||||
|
* certified)
|
||||||
|
* @param profileId profile id governing issuance
|
||||||
|
* @param requestedValidity optional requested validity (policy may
|
||||||
|
* override/deny)
|
||||||
|
* @param attributes universal attributes (may be empty but not null)
|
||||||
|
*/
|
||||||
|
public record IntermediateCertIssueCommand(FormatId formatId, PkiId issuerCaId, PkiId subjectCaId, String profileId,
|
||||||
|
Optional<Validity> requestedValidity, AttributeSet attributes) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an intermediate CA credential issuance command.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid or optional container
|
||||||
|
* is null
|
||||||
|
*/
|
||||||
|
public IntermediateCertIssueCommand {
|
||||||
|
if (formatId == null) {
|
||||||
|
throw new IllegalArgumentException("formatId must not be null");
|
||||||
|
}
|
||||||
|
if (issuerCaId == null) {
|
||||||
|
throw new IllegalArgumentException("issuerCaId must not be null");
|
||||||
|
}
|
||||||
|
if (subjectCaId == null) {
|
||||||
|
throw new IllegalArgumentException("subjectCaId must not be null");
|
||||||
|
}
|
||||||
|
if (profileId == null || profileId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("profileId must not be null/blank");
|
||||||
|
}
|
||||||
|
if (requestedValidity == null) {
|
||||||
|
throw new IllegalArgumentException("requestedValidity must not be null");
|
||||||
|
}
|
||||||
|
if (attributes == null) {
|
||||||
|
throw new IllegalArgumentException("attributes must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.ca;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.FormatId;
|
||||||
|
import zeroecho.pki.api.KeyRef;
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.SubjectRef;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command to create a new intermediate CA entity and issue its initial CA
|
||||||
|
* credential.
|
||||||
|
*
|
||||||
|
* @param formatId credential format id
|
||||||
|
* @param issuerCaId issuer CA entity id
|
||||||
|
* @param subjectRef normalized subject reference for the intermediate
|
||||||
|
* @param profileId profile id governing issuance
|
||||||
|
* @param keyRef optional existing key reference; empty requests key
|
||||||
|
* generation
|
||||||
|
* @param attributes universal attributes (may be empty but not null)
|
||||||
|
*/
|
||||||
|
public record IntermediateCreateCommand(FormatId formatId, PkiId issuerCaId, SubjectRef subjectRef, String profileId,
|
||||||
|
Optional<KeyRef> keyRef, AttributeSet attributes) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an intermediate create command.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid or optional container
|
||||||
|
* is null
|
||||||
|
*/
|
||||||
|
public IntermediateCreateCommand {
|
||||||
|
if (formatId == null) {
|
||||||
|
throw new IllegalArgumentException("formatId must not be null");
|
||||||
|
}
|
||||||
|
if (issuerCaId == null) {
|
||||||
|
throw new IllegalArgumentException("issuerCaId must not be null");
|
||||||
|
}
|
||||||
|
if (subjectRef == null) {
|
||||||
|
throw new IllegalArgumentException("subjectRef must not be null");
|
||||||
|
}
|
||||||
|
if (profileId == null || profileId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("profileId must not be null/blank");
|
||||||
|
}
|
||||||
|
if (keyRef == null) {
|
||||||
|
throw new IllegalArgumentException("keyRef must not be null");
|
||||||
|
}
|
||||||
|
if (attributes == null) {
|
||||||
|
throw new IllegalArgumentException("attributes must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
60
pki/src/main/java/zeroecho/pki/api/ca/package-info.java
Normal file
60
pki/src/main/java/zeroecho/pki/api/ca/package-info.java
Normal file
@@ -0,0 +1,60 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* Certificate Authority (CA) domain model.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This package contains CA records, lifecycle state, CA kinds, and CA-related
|
||||||
|
* commands and queries. It models root and intermediate CA management,
|
||||||
|
* including creation, import, rollover, and key rotation operations.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Responsibilities</h2>
|
||||||
|
* <ul>
|
||||||
|
* <li>Represent CA identity and state through records and enums.</li>
|
||||||
|
* <li>Define CA management commands used by
|
||||||
|
* {@link zeroecho.pki.api.CaService}.</li>
|
||||||
|
* <li>Support intermediate CA creation and intermediate certificate
|
||||||
|
* issuance.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Concrete certificate framework specifics are delegated to framework
|
||||||
|
* integrations.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
package zeroecho.pki.api.ca;
|
||||||
117
pki/src/main/java/zeroecho/pki/api/credential/Credential.java
Normal file
117
pki/src/main/java/zeroecho/pki/api/credential/Credential.java
Normal file
@@ -0,0 +1,117 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.credential;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.EncodedObject;
|
||||||
|
import zeroecho.pki.api.FormatId;
|
||||||
|
import zeroecho.pki.api.IssuerRef;
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.SubjectRef;
|
||||||
|
import zeroecho.pki.api.Validity;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Issued credential with mandatory core metadata and universal attributes.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The PKI core does not assume X.509 semantics. The {@code serialOrUniqueId}
|
||||||
|
* field maps to X.509 serial numbers when applicable, but can represent another
|
||||||
|
* framework's unique identifier.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The {@code publicKeyId} is intended to group multiple credentials for the
|
||||||
|
* same key (e.g., cross-signing, migrations, or parallel classical/PQC chains).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param credentialId stable identifier for the credential (typically a
|
||||||
|
* fingerprint of encoded bytes)
|
||||||
|
* @param formatId framework identifier
|
||||||
|
* @param issuerRef issuing CA reference
|
||||||
|
* @param subjectRef normalized subject reference
|
||||||
|
* @param validity validity interval
|
||||||
|
* @param serialOrUniqueId framework-specific unique identifier (serial for
|
||||||
|
* X.509)
|
||||||
|
* @param publicKeyId stable identifier derived from the subject public key
|
||||||
|
* @param profileId profile governing issuance
|
||||||
|
* @param status inventory status
|
||||||
|
* @param encoded encoded credential bytes
|
||||||
|
* @param attributes universal attribute set
|
||||||
|
*/
|
||||||
|
public record Credential(PkiId credentialId, FormatId formatId, IssuerRef issuerRef, SubjectRef subjectRef,
|
||||||
|
Validity validity, String serialOrUniqueId, PkiId publicKeyId, String profileId, CredentialStatus status,
|
||||||
|
EncodedObject encoded, AttributeSet attributes) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a credential record.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if mandatory inputs are invalid
|
||||||
|
*/
|
||||||
|
public Credential {
|
||||||
|
if (credentialId == null) {
|
||||||
|
throw new IllegalArgumentException("credentialId must not be null");
|
||||||
|
}
|
||||||
|
if (formatId == null) {
|
||||||
|
throw new IllegalArgumentException("formatId must not be null");
|
||||||
|
}
|
||||||
|
if (issuerRef == null) {
|
||||||
|
throw new IllegalArgumentException("issuerRef must not be null");
|
||||||
|
}
|
||||||
|
if (subjectRef == null) {
|
||||||
|
throw new IllegalArgumentException("subjectRef must not be null");
|
||||||
|
}
|
||||||
|
if (validity == null) {
|
||||||
|
throw new IllegalArgumentException("validity must not be null");
|
||||||
|
}
|
||||||
|
if (serialOrUniqueId == null || serialOrUniqueId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("serialOrUniqueId must not be null/blank");
|
||||||
|
}
|
||||||
|
if (publicKeyId == null) {
|
||||||
|
throw new IllegalArgumentException("publicKeyId must not be null");
|
||||||
|
}
|
||||||
|
if (profileId == null || profileId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("profileId must not be null/blank");
|
||||||
|
}
|
||||||
|
if (status == null) {
|
||||||
|
throw new IllegalArgumentException("status must not be null");
|
||||||
|
}
|
||||||
|
if (encoded == null) {
|
||||||
|
throw new IllegalArgumentException("encoded must not be null");
|
||||||
|
}
|
||||||
|
if (attributes == null) {
|
||||||
|
throw new IllegalArgumentException("attributes must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.credential;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.EncodedObject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Bundle of a primary credential and supporting objects.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Supporting objects enable distribution and validation. For X.509 these are
|
||||||
|
* typically chain certificates. Frameworks may define additional supporting
|
||||||
|
* artifacts.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param credential primary credential
|
||||||
|
* @param supportingObjects supporting artifacts (framework-defined ordering)
|
||||||
|
*/
|
||||||
|
public record CredentialBundle(Credential credential, List<EncodedObject> supportingObjects) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a bundle.
|
||||||
|
*
|
||||||
|
* @param credential primary credential
|
||||||
|
* @param supportingObjects supporting artifacts (non-null, may be empty)
|
||||||
|
* @throws IllegalArgumentException if inputs are null
|
||||||
|
*/
|
||||||
|
public CredentialBundle {
|
||||||
|
if (credential == null) {
|
||||||
|
throw new IllegalArgumentException("credential must not be null");
|
||||||
|
}
|
||||||
|
if (supportingObjects == null) {
|
||||||
|
throw new IllegalArgumentException("supportingObjects must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.credential;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.FormatId;
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.SubjectRef;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Query constraints for searching credentials in inventory.
|
||||||
|
*
|
||||||
|
* @param formatId optional framework filter
|
||||||
|
* @param issuerCaId optional issuer CA filter
|
||||||
|
* @param subjectRef optional subject filter
|
||||||
|
* @param profileId optional profile filter
|
||||||
|
* @param status optional status filter
|
||||||
|
* @param publicKeyId optional public key grouping filter
|
||||||
|
* @param validAt optional evaluation time for validity-based filtering
|
||||||
|
*/
|
||||||
|
public record CredentialQuery(Optional<FormatId> formatId, Optional<PkiId> issuerCaId, Optional<SubjectRef> subjectRef,
|
||||||
|
Optional<String> profileId, Optional<CredentialStatus> status, Optional<PkiId> publicKeyId,
|
||||||
|
Optional<Instant> validAt) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a credential query.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if any optional container is null
|
||||||
|
*/
|
||||||
|
public CredentialQuery {
|
||||||
|
if (formatId == null || issuerCaId == null || subjectRef == null || profileId == null || status == null
|
||||||
|
|| publicKeyId == null || validAt == null) {
|
||||||
|
throw new IllegalArgumentException("optional fields must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.credential;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Status of a credential as tracked by PKI inventory.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Status may be computed from validity and revocation state or stored directly
|
||||||
|
* depending on implementation.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
public enum CredentialStatus {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credential is issued and not revoked. Validity may still expire later.
|
||||||
|
*/
|
||||||
|
ISSUED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credential is revoked.
|
||||||
|
*/
|
||||||
|
REVOKED,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Credential validity interval has ended.
|
||||||
|
*/
|
||||||
|
EXPIRED
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* Credential inventory domain model.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This package defines the model types representing issued credentials and
|
||||||
|
* their inventory view, including status tracking and query objects. It is used
|
||||||
|
* by {@link zeroecho.pki.api.CredentialInventoryService}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Notes</h2>
|
||||||
|
* <ul>
|
||||||
|
* <li>Credentials are treated as immutable artifacts once issued.</li>
|
||||||
|
* <li>Status values capture the operational lifecycle (e.g., issued, expired,
|
||||||
|
* revoked, on hold).</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
package zeroecho.pki.api.credential;
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.issuance;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command to build a distributable bundle for an existing credential.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Bundles are constructed using chain selection rules, trust anchor selection,
|
||||||
|
* and optional compatibility profiles. This is especially relevant for
|
||||||
|
* cross-signing and migration scenarios.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param credentialId credential id
|
||||||
|
* @param preferredTrustAnchorId optional preferred trust anchor id
|
||||||
|
* (implementation-defined)
|
||||||
|
* @param compatibilityProfileId optional compatibility profile id influencing
|
||||||
|
* chain selection
|
||||||
|
*/
|
||||||
|
public record BundleCommand(PkiId credentialId, Optional<PkiId> preferredTrustAnchorId,
|
||||||
|
Optional<String> compatibilityProfileId) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a bundle command.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid or optional containers
|
||||||
|
* are null
|
||||||
|
*/
|
||||||
|
public BundleCommand {
|
||||||
|
if (credentialId == null) {
|
||||||
|
throw new IllegalArgumentException("credentialId must not be null");
|
||||||
|
}
|
||||||
|
if (preferredTrustAnchorId == null) {
|
||||||
|
throw new IllegalArgumentException("preferredTrustAnchorId must not be null");
|
||||||
|
}
|
||||||
|
if (compatibilityProfileId == null) {
|
||||||
|
throw new IllegalArgumentException("compatibilityProfileId must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.issuance;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
import zeroecho.pki.api.request.ParsedCertificationRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Normalized inputs for issuance policy evaluation.
|
||||||
|
*
|
||||||
|
* @param issuerCaId issuer CA entity id
|
||||||
|
* @param request parsed certification request
|
||||||
|
* @param profileId profile id selected for issuance
|
||||||
|
* @param requestedOverrides user-requested overrides (may be empty but not
|
||||||
|
* null)
|
||||||
|
*/
|
||||||
|
public record IssuanceInputs(PkiId issuerCaId, ParsedCertificationRequest request, String profileId,
|
||||||
|
AttributeSet requestedOverrides) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates issuance inputs for policy evaluation.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
*/
|
||||||
|
public IssuanceInputs {
|
||||||
|
if (issuerCaId == null) {
|
||||||
|
throw new IllegalArgumentException("issuerCaId must not be null");
|
||||||
|
}
|
||||||
|
if (request == null) {
|
||||||
|
throw new IllegalArgumentException("request must not be null");
|
||||||
|
}
|
||||||
|
if (profileId == null || profileId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("profileId must not be null/blank");
|
||||||
|
}
|
||||||
|
if (requestedOverrides == null) {
|
||||||
|
throw new IllegalArgumentException("requestedOverrides must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,82 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.issuance;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.Validity;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
import zeroecho.pki.api.request.ParsedCertificationRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command to issue an end-entity credential from a parsed certification
|
||||||
|
* request.
|
||||||
|
*
|
||||||
|
* @param issuerCaId issuer CA entity id
|
||||||
|
* @param request parsed certification request
|
||||||
|
* @param profileId profile id governing issuance
|
||||||
|
* @param validityOverride optional requested validity override
|
||||||
|
* (policy-validated)
|
||||||
|
* @param overrides additional universal attribute overrides
|
||||||
|
* (policy-validated; may be empty but not null)
|
||||||
|
*/
|
||||||
|
public record IssueEndEntityCommand(PkiId issuerCaId, ParsedCertificationRequest request, String profileId,
|
||||||
|
Optional<Validity> validityOverride, AttributeSet overrides) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an issuance command.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid or optional container
|
||||||
|
* is null
|
||||||
|
*/
|
||||||
|
public IssueEndEntityCommand {
|
||||||
|
if (issuerCaId == null) {
|
||||||
|
throw new IllegalArgumentException("issuerCaId must not be null");
|
||||||
|
}
|
||||||
|
if (request == null) {
|
||||||
|
throw new IllegalArgumentException("request must not be null");
|
||||||
|
}
|
||||||
|
if (profileId == null || profileId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("profileId must not be null/blank");
|
||||||
|
}
|
||||||
|
if (validityOverride == null) {
|
||||||
|
throw new IllegalArgumentException("validityOverride must not be null");
|
||||||
|
}
|
||||||
|
if (overrides == null) {
|
||||||
|
throw new IllegalArgumentException("overrides must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,68 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.issuance;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command to reissue based on a stored issuance record.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The meaning of "issuance record" is implementation-defined (it may be derived
|
||||||
|
* from audit/store metadata). Reissue is useful for reproducing issuance under
|
||||||
|
* controlled changes.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param issuanceRecordId issuance record id
|
||||||
|
* @param overrides universal attribute overrides (policy-validated; may
|
||||||
|
* be empty but not null)
|
||||||
|
*/
|
||||||
|
public record ReissueCommand(PkiId issuanceRecordId, AttributeSet overrides) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a reissue command.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
*/
|
||||||
|
public ReissueCommand {
|
||||||
|
if (issuanceRecordId == null) {
|
||||||
|
throw new IllegalArgumentException("issuanceRecordId must not be null");
|
||||||
|
}
|
||||||
|
if (overrides == null) {
|
||||||
|
throw new IllegalArgumentException("overrides must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.issuance;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.Validity;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command to renew an existing credential.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Renewal typically retains continuity (same identity and key constraints)
|
||||||
|
* under policy-defined semantics. The implementation decides what "renew" means
|
||||||
|
* for a given framework and profile.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param existingCredentialId credential id to renew
|
||||||
|
* @param validityOverride optional validity override (policy-validated)
|
||||||
|
* @param overrides universal attribute overrides (policy-validated;
|
||||||
|
* may be empty but not null)
|
||||||
|
*/
|
||||||
|
public record RenewCommand(PkiId existingCredentialId, Optional<Validity> validityOverride, AttributeSet overrides) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a renewal command.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid or optional container
|
||||||
|
* is null
|
||||||
|
*/
|
||||||
|
public RenewCommand {
|
||||||
|
if (existingCredentialId == null) {
|
||||||
|
throw new IllegalArgumentException("existingCredentialId must not be null");
|
||||||
|
}
|
||||||
|
if (validityOverride == null) {
|
||||||
|
throw new IllegalArgumentException("validityOverride must not be null");
|
||||||
|
}
|
||||||
|
if (overrides == null) {
|
||||||
|
throw new IllegalArgumentException("overrides must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.issuance;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
import zeroecho.pki.api.request.ParsedCertificationRequest;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Command to replace an existing credential.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Replacement is used for scenarios such as compromise or identity attribute
|
||||||
|
* changes. Policy determines whether replacement is permitted and what
|
||||||
|
* continuity constraints apply.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param existingCredentialId existing credential id
|
||||||
|
* @param newRequest new parsed request for the replacement credential
|
||||||
|
* @param profileId profile id governing issuance
|
||||||
|
* @param overrides universal attribute overrides (policy-validated;
|
||||||
|
* may be empty but not null)
|
||||||
|
*/
|
||||||
|
public record ReplaceCommand(PkiId existingCredentialId, ParsedCertificationRequest newRequest, String profileId,
|
||||||
|
AttributeSet overrides) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a replacement command.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
*/
|
||||||
|
public ReplaceCommand {
|
||||||
|
if (existingCredentialId == null) {
|
||||||
|
throw new IllegalArgumentException("existingCredentialId must not be null");
|
||||||
|
}
|
||||||
|
if (newRequest == null) {
|
||||||
|
throw new IllegalArgumentException("newRequest must not be null");
|
||||||
|
}
|
||||||
|
if (profileId == null || profileId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("profileId must not be null/blank");
|
||||||
|
}
|
||||||
|
if (overrides == null) {
|
||||||
|
throw new IllegalArgumentException("overrides must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.issuance;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constraints for certification request verification.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This policy controls proof-of-possession requirements and may carry
|
||||||
|
* framework-specific verification modes via optional hints.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param requireProofOfPossession whether proof-of-possession is required
|
||||||
|
* @param compatibilityProfileId optional compatibility profile hint for
|
||||||
|
* parsers/verifiers
|
||||||
|
*/
|
||||||
|
public record VerificationPolicy(boolean requireProofOfPossession, Optional<String> compatibilityProfileId) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a verification policy.
|
||||||
|
*
|
||||||
|
* @param requireProofOfPossession PoP requirement
|
||||||
|
* @param compatibilityProfileId optional compatibility profile id
|
||||||
|
* @throws IllegalArgumentException if {@code compatibilityProfileId} is null
|
||||||
|
*/
|
||||||
|
public VerificationPolicy {
|
||||||
|
if (compatibilityProfileId == null) {
|
||||||
|
throw new IllegalArgumentException("compatibilityProfileId must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,61 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* Credential issuance domain model.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This package contains command objects and input types used to issue, renew,
|
||||||
|
* replace, and reissue credentials, as well as optional issuance verification
|
||||||
|
* policies. The operations are executed through
|
||||||
|
* {@link zeroecho.pki.api.IssuanceService}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Command-driven operations</h2>
|
||||||
|
* <ul>
|
||||||
|
* <li>Issue end-entity credentials.</li>
|
||||||
|
* <li>Renew existing credentials.</li>
|
||||||
|
* <li>Replace credentials (e.g., due to key changes).</li>
|
||||||
|
* <li>Reissue credentials (policy-driven reissuance).</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Requests may originate from the request domain
|
||||||
|
* ({@code zeroecho.pki.api.request}) and issuance outcomes may be published
|
||||||
|
* and/or recorded in inventory.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
package zeroecho.pki.api.issuance;
|
||||||
@@ -0,0 +1,114 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.orch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Durability policy for workflow continuation data managed by orchestrators.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Orchestrators coordinate long-running operations (e.g., human approvals,
|
||||||
|
* remote signing, certificate issuance). Some workflows require local
|
||||||
|
* continuation state to resume after a JVM restart. This enum defines how such
|
||||||
|
* state is handled.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Examples</h2>
|
||||||
|
* <ul>
|
||||||
|
* <li>A remote signature workflow may wait for hours. If the remote system is
|
||||||
|
* the source of truth and all necessary data can be re-derived from external
|
||||||
|
* references (operation ID, request ID), the workflow can run in a durable mode
|
||||||
|
* without storing sensitive material locally.</li>
|
||||||
|
* <li>If a workflow requires local ephemeral secrets (e.g., a one-time approval
|
||||||
|
* challenge that cannot be recomputed), strict mode should abort on restart
|
||||||
|
* (fail-closed) unless encrypted persistence is configured.</li>
|
||||||
|
* </ul>
|
||||||
|
*/
|
||||||
|
public enum OrchestrationDurabilityPolicy {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fail-closed behavior.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The orchestrator does not persist continuation state that would be required
|
||||||
|
* to resume the workflow after a process restart. If the process restarts,
|
||||||
|
* operations that cannot be safely resumed must be cancelled or marked as
|
||||||
|
* failed deterministically.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Example: A workflow requires an ephemeral secret that is only available in
|
||||||
|
* memory. In this mode, the operation is aborted on restart and the client must
|
||||||
|
* resubmit.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
STRICT_ABORT_ON_RESTART,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Durable operation using minimal non-sensitive state.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The orchestrator persists only references and non-sensitive continuation
|
||||||
|
* state, sufficient to resume the workflow after restart. Sensitive payloads
|
||||||
|
* must remain outside the local state (e.g., in dedicated stores or remote
|
||||||
|
* systems).
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Example: An operation persists a reference to a stored CSR and a reference to
|
||||||
|
* the selected certificate profile, but does not persist raw key material or
|
||||||
|
* private tokens.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
DURABLE_MIN_STATE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Durable operation with encrypted continuation state.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The orchestrator persists continuation state encrypted (e.g., AES-256/GCM)
|
||||||
|
* using a key supplied by external configuration (environment variable, secret
|
||||||
|
* store, or KMS). This allows workflows to resume after restart even when they
|
||||||
|
* require sensitive local state.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Example: A workflow stores an encrypted blob containing a transient approval
|
||||||
|
* context. The encryption uses authenticated data derived from operation ID,
|
||||||
|
* operation type, and owner identity to prevent swapping blobs across
|
||||||
|
* operations.
|
||||||
|
* </p>
|
||||||
|
*/
|
||||||
|
DURABLE_ENCRYPTED_STATE
|
||||||
|
}
|
||||||
120
pki/src/main/java/zeroecho/pki/api/orch/WorkflowStateRecord.java
Normal file
120
pki/src/main/java/zeroecho/pki/api/orch/WorkflowStateRecord.java
Normal file
@@ -0,0 +1,120 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.orch;
|
||||||
|
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.EncodedObject;
|
||||||
|
import zeroecho.pki.api.Encoding;
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.audit.Principal;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Persisted continuation state for an orchestrated workflow.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This record is used by orchestrators to persist the minimum information
|
||||||
|
* needed to resume long-running workflows after a process restart, according to
|
||||||
|
* the selected {@link OrchestrationDurabilityPolicy}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Storage model</h2>
|
||||||
|
* <p>
|
||||||
|
* The async bus is the authoritative source for operation lifecycle and status,
|
||||||
|
* but it does not persist sensitive payloads and may be configured not to
|
||||||
|
* persist results. Orchestrators therefore persist workflow-specific
|
||||||
|
* continuation state through {@code PkiStore}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Security</h2>
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link #payload()} may contain sensitive information. It must not be
|
||||||
|
* logged.</li>
|
||||||
|
* <li>When {@link #durabilityPolicy()} is
|
||||||
|
* {@link OrchestrationDurabilityPolicy#DURABLE_ENCRYPTED_STATE},
|
||||||
|
* {@link #payloadEncoding()} must reflect an encrypted form and the payload
|
||||||
|
* must be authenticated using AAD derived from operation identity.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* @param opId async operation identifier (never {@code null})
|
||||||
|
* @param type operation type string (never {@code null})
|
||||||
|
* @param owner operation owner (never {@code null})
|
||||||
|
* @param durabilityPolicy durability policy (never {@code null})
|
||||||
|
* @param createdAt creation time (never {@code null})
|
||||||
|
* @param updatedAt last update time (never {@code null})
|
||||||
|
* @param expiresAt expiration/deadline (never {@code null})
|
||||||
|
* @param payloadEncoding encoding of {@link #payload()} (never {@code null})
|
||||||
|
* @param payload optional persisted continuation payload
|
||||||
|
*/
|
||||||
|
public record WorkflowStateRecord(PkiId opId, String type, Principal owner,
|
||||||
|
OrchestrationDurabilityPolicy durabilityPolicy, Instant createdAt, Instant updatedAt, Instant expiresAt,
|
||||||
|
Encoding payloadEncoding, Optional<EncodedObject> payload) {
|
||||||
|
|
||||||
|
public WorkflowStateRecord {
|
||||||
|
Objects.requireNonNull(opId, "opId");
|
||||||
|
Objects.requireNonNull(type, "type");
|
||||||
|
Objects.requireNonNull(owner, "owner");
|
||||||
|
Objects.requireNonNull(durabilityPolicy, "durabilityPolicy");
|
||||||
|
Objects.requireNonNull(createdAt, "createdAt");
|
||||||
|
Objects.requireNonNull(updatedAt, "updatedAt");
|
||||||
|
Objects.requireNonNull(expiresAt, "expiresAt");
|
||||||
|
Objects.requireNonNull(payloadEncoding, "payloadEncoding");
|
||||||
|
Objects.requireNonNull(payload, "payload");
|
||||||
|
|
||||||
|
if (type.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("type must not be blank.");
|
||||||
|
}
|
||||||
|
if (!expiresAt.isAfter(createdAt) && !expiresAt.equals(createdAt)) {
|
||||||
|
// Allow expiresAt == createdAt for immediate-expire test scenarios, but reject
|
||||||
|
// negative durations.
|
||||||
|
if (expiresAt.isBefore(createdAt)) { // NOPMD
|
||||||
|
throw new IllegalArgumentException("expiresAt must not be before createdAt.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns whether the record is expired at the provided time.
|
||||||
|
*
|
||||||
|
* @param now current time (never {@code null})
|
||||||
|
* @return {@code true} if {@code now} is strictly after {@link #expiresAt()}
|
||||||
|
*/
|
||||||
|
public boolean isExpiredAt(Instant now) {
|
||||||
|
Objects.requireNonNull(now, "now");
|
||||||
|
return now.isAfter(expiresAt);
|
||||||
|
}
|
||||||
|
}
|
||||||
114
pki/src/main/java/zeroecho/pki/api/orch/package-info.java
Normal file
114
pki/src/main/java/zeroecho/pki/api/orch/package-info.java
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* Orchestration and workflow durability API for ZeroEcho PKI.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This package defines stable domain abstractions related to <em>long-running
|
||||||
|
* PKI workflows</em> and their durability requirements. It is concerned with
|
||||||
|
* describing <strong>what must be persisted and how durable such persistence
|
||||||
|
* must be</strong>, not with <em>how</em> the persistence is implemented.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Scope and responsibilities</h2>
|
||||||
|
* <p>
|
||||||
|
* The orchestration layer in ZeroEcho PKI coordinates multi-step operations
|
||||||
|
* such as certificate issuance, revocation processing, key rollover, or
|
||||||
|
* publication workflows. These operations:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>may span multiple logical steps,</li>
|
||||||
|
* <li>may involve external systems or asynchronous callbacks,</li>
|
||||||
|
* <li>must tolerate restarts, crashes, or redeployments.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This package provides the minimal API necessary to:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>describe the required durability guarantees for workflow state,</li>
|
||||||
|
* <li>represent persisted workflow state in a storage-agnostic form,</li>
|
||||||
|
* <li>enable deterministic recovery and audit of workflow progression.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <h2>Key abstractions</h2>
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link zeroecho.pki.api.orch.OrchestrationDurabilityPolicy
|
||||||
|
* OrchestrationDurabilityPolicy} defines <em>how durable</em> orchestration
|
||||||
|
* state must be (e.g. write-through, buffered, best-effort), allowing different
|
||||||
|
* operational trade-offs without changing orchestration logic.</li>
|
||||||
|
* <li>{@link zeroecho.pki.api.orch.WorkflowStateRecord WorkflowStateRecord}
|
||||||
|
* represents an immutable, persisted snapshot of workflow state at a specific
|
||||||
|
* point in time, suitable for recovery, audit, and historical inspection.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <h2>Immutability and history</h2>
|
||||||
|
* <p>
|
||||||
|
* Workflow state records are designed to be immutable once persisted.
|
||||||
|
* Implementations are expected to append new state records rather than
|
||||||
|
* overwrite existing ones, enabling:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>full audit trails,</li>
|
||||||
|
* <li>temporal queries ("state at time T"),</li>
|
||||||
|
* <li>post-mortem analysis of failed or aborted workflows.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Whether and for how long historical records are retained is governed by
|
||||||
|
* policy and implementation, but the API itself is intentionally compatible
|
||||||
|
* with history-preserving stores.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>API stability and integration</h2>
|
||||||
|
* <p>
|
||||||
|
* The types in this package are part of the public PKI API surface. They are
|
||||||
|
* intended to be usable across different runtime environments, including:
|
||||||
|
* </p>
|
||||||
|
* <ul>
|
||||||
|
* <li>standalone CLI applications,</li>
|
||||||
|
* <li>long-running server processes,</li>
|
||||||
|
* <li>container-managed frameworks such as Spring or Micronaut.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* No assumptions are made about the underlying persistence mechanism
|
||||||
|
* (filesystem, database, distributed log, etc.). Such concerns are handled by
|
||||||
|
* SPI and implementation layers.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
package zeroecho.pki.api.orch;
|
||||||
81
pki/src/main/java/zeroecho/pki/api/package-info.java
Normal file
81
pki/src/main/java/zeroecho/pki/api/package-info.java
Normal file
@@ -0,0 +1,81 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
/**
|
||||||
|
* Public, framework-agnostic PKI API.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* This package provides stable entry points and core value types for operating
|
||||||
|
* a PKI instance. The API is intentionally independent of any concrete
|
||||||
|
* certificate framework (for example X.509), allowing multiple frameworks to be
|
||||||
|
* integrated via SPIs in {@code zeroecho.pki.spi.*}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* <h2>Design principles</h2>
|
||||||
|
* <ul>
|
||||||
|
* <li><strong>Framework independence:</strong> the API models PKI concepts (CA,
|
||||||
|
* issuance, revocation, status objects, publication, backup/restore) without
|
||||||
|
* binding to a single certificate technology.</li>
|
||||||
|
* <li><strong>Explicit commands and queries:</strong> mutable operations are
|
||||||
|
* expressed as command objects and retrieval via query objects in
|
||||||
|
* subpackages.</li>
|
||||||
|
* <li><strong>Safety and auditability:</strong> security-relevant operations
|
||||||
|
* are designed to be auditable; sensitive data must never be exposed by API
|
||||||
|
* abstractions.</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <h2>Key entry points</h2>
|
||||||
|
* <ul>
|
||||||
|
* <li>{@link zeroecho.pki.api.CaService}</li>
|
||||||
|
* <li>{@link zeroecho.pki.api.CertificationRequestService}</li>
|
||||||
|
* <li>{@link zeroecho.pki.api.IssuanceService}</li>
|
||||||
|
* <li>{@link zeroecho.pki.api.RevocationService}</li>
|
||||||
|
* <li>{@link zeroecho.pki.api.StatusObjectService}</li>
|
||||||
|
* <li>{@link zeroecho.pki.api.PublicationService}</li>
|
||||||
|
* <li>{@link zeroecho.pki.api.ProfileService}</li>
|
||||||
|
* <li>{@link zeroecho.pki.api.PolicyService}</li>
|
||||||
|
* <li>{@link zeroecho.pki.api.ImportExportService}</li>
|
||||||
|
* <li>{@link zeroecho.pki.api.BackupService}</li>
|
||||||
|
* </ul>
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* Subpackages further organize domain models: {@code ca}, {@code issuance},
|
||||||
|
* {@code request}, {@code revocation}, {@code status}, {@code publication},
|
||||||
|
* {@code profile}, {@code policy}, {@code transfer}, plus attribute and audit
|
||||||
|
* domains in {@code attr} and {@code audit}.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @since 1.0
|
||||||
|
*/
|
||||||
|
package zeroecho.pki.api;
|
||||||
@@ -0,0 +1,80 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.policy;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
import zeroecho.pki.api.attr.AttributeSet;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Policy decision including optional modifications to be applied to an
|
||||||
|
* operation.
|
||||||
|
*
|
||||||
|
* <p>
|
||||||
|
* The {@code appliedOverrides} attribute set is used to communicate
|
||||||
|
* policy-enforced adjustments (e.g., constrained validity, normalized
|
||||||
|
* attributes). It must not contain secrets.
|
||||||
|
* </p>
|
||||||
|
*
|
||||||
|
* @param decisionId stable decision identifier for correlation and
|
||||||
|
* explainability
|
||||||
|
* @param status decision outcome status
|
||||||
|
* @param messages non-sensitive operator-readable messages
|
||||||
|
* @param appliedOverrides policy-enforced overrides to be applied downstream
|
||||||
|
*/
|
||||||
|
public record PolicyDecision(PkiId decisionId, PolicyDecisionStatus status, List<String> messages,
|
||||||
|
AttributeSet appliedOverrides) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a policy decision.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
*/
|
||||||
|
public PolicyDecision {
|
||||||
|
if (decisionId == null) {
|
||||||
|
throw new IllegalArgumentException("decisionId must not be null");
|
||||||
|
}
|
||||||
|
if (status == null) {
|
||||||
|
throw new IllegalArgumentException("status must not be null");
|
||||||
|
}
|
||||||
|
if (messages == null) {
|
||||||
|
throw new IllegalArgumentException("messages must not be null");
|
||||||
|
}
|
||||||
|
if (appliedOverrides == null) {
|
||||||
|
throw new IllegalArgumentException("appliedOverrides must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.policy;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Outcome status of a policy evaluation.
|
||||||
|
*/
|
||||||
|
public enum PolicyDecisionStatus {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation is allowed under current policy.
|
||||||
|
*/
|
||||||
|
ALLOW,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation is denied under current policy.
|
||||||
|
*/
|
||||||
|
DENY,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Operation is allowed, but policy requires modifications (e.g., validity
|
||||||
|
* truncation).
|
||||||
|
*/
|
||||||
|
ALLOW_WITH_MODIFICATIONS
|
||||||
|
}
|
||||||
62
pki/src/main/java/zeroecho/pki/api/policy/PolicyTrace.java
Normal file
62
pki/src/main/java/zeroecho/pki/api/policy/PolicyTrace.java
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.policy;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import zeroecho.pki.api.PkiId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Explainability trace for a policy decision.
|
||||||
|
*
|
||||||
|
* @param decisionId decision id this trace explains
|
||||||
|
* @param steps ordered evaluation steps
|
||||||
|
*/
|
||||||
|
public record PolicyTrace(PkiId decisionId, List<PolicyTraceStep> steps) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a policy trace.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
*/
|
||||||
|
public PolicyTrace {
|
||||||
|
if (decisionId == null) {
|
||||||
|
throw new IllegalArgumentException("decisionId must not be null");
|
||||||
|
}
|
||||||
|
if (steps == null) {
|
||||||
|
throw new IllegalArgumentException("steps must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,65 @@
|
|||||||
|
/*******************************************************************************
|
||||||
|
* Copyright (C) 2025, Leo Galambos
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* Redistribution and use in source and binary forms, with or without
|
||||||
|
* modification, are permitted provided that the following conditions are met:
|
||||||
|
*
|
||||||
|
* 1. Redistributions of source code must retain the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer.
|
||||||
|
*
|
||||||
|
* 2. Redistributions in binary form must reproduce the above copyright notice,
|
||||||
|
* this list of conditions and the following disclaimer in the documentation
|
||||||
|
* and/or other materials provided with the distribution.
|
||||||
|
*
|
||||||
|
* 3. All advertising materials mentioning features or use of this software must
|
||||||
|
* display the following acknowledgement:
|
||||||
|
* This product includes software developed by the Egothor project.
|
||||||
|
*
|
||||||
|
* 4. Neither the name of the copyright holder nor the names of its contributors
|
||||||
|
* may be used to endorse or promote products derived from this software
|
||||||
|
* without specific prior written permission.
|
||||||
|
*
|
||||||
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||||
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||||
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||||
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
|
||||||
|
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||||
|
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||||
|
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||||
|
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||||
|
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||||
|
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||||
|
* POSSIBILITY OF SUCH DAMAGE.
|
||||||
|
******************************************************************************/
|
||||||
|
package zeroecho.pki.api.policy;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Single evaluation step within a policy trace.
|
||||||
|
*
|
||||||
|
* @param ruleId stable rule identifier (implementation-defined)
|
||||||
|
* @param outcome human-readable outcome string (e.g., "ALLOW", "DENY",
|
||||||
|
* "MODIFY")
|
||||||
|
* @param notes non-sensitive explanatory notes
|
||||||
|
*/
|
||||||
|
public record PolicyTraceStep(String ruleId, String outcome, List<String> notes) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a policy trace step.
|
||||||
|
*
|
||||||
|
* @throws IllegalArgumentException if inputs are invalid
|
||||||
|
*/
|
||||||
|
public PolicyTraceStep {
|
||||||
|
if (ruleId == null || ruleId.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("ruleId must not be null/blank");
|
||||||
|
}
|
||||||
|
if (outcome == null || outcome.isBlank()) {
|
||||||
|
throw new IllegalArgumentException("outcome must not be null/blank");
|
||||||
|
}
|
||||||
|
if (notes == null) {
|
||||||
|
throw new IllegalArgumentException("notes must not be null");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user