diff --git a/README.md b/README.md index 23b7e87..9817b41 100644 --- a/README.md +++ b/README.md @@ -11,20 +11,23 @@ To generate a key, run `java -jar target/json-web-key-generator-1.1.0-SNAPSHOT-j ``` usage: java -jar json-web-key-generator.jar -t [options] -t,--type Key Type, one of: RSA, oct, EC, OKP + (case-insensitive) -s,--size Key Size in bits, required for RSA and oct key - types. Must be an integer divisible by 8 + types. Must be an integer divisible by 8. If + omitted, defaults to 2048 for RSA, 2048 for oct -c,--curve Key Curve, required for EC or OKP key type. Must be one of P-256, secp256k1, P-384, P-521 for EC keys or one of Ed25519, Ed448, X25519, - X448 for OKP keys. + X448 for OKP keys. If omitted, defaults to + P-256 for EC, Ed25519 for OKP -u,--usage Usage, one of: enc, sig (optional) -a,--algorithm Algorithm (optional) -i,--id Key ID (optional), one will be generated if not defined -g,--idGenerator Key ID generation method (optional). Can be one - of: date, timestamp, sha256, sha384, sha512, uuid, none. If - omitted, generator method defaults to - 'timestamp'. + of: date, timestamp, sha256, sha384, sha512, + uuid, none. If omitted, generator method + defaults to 'timestamp'. -I,--noGenerateId Don't generate a Key ID. (Deprecated, use '-g none' instead.) -p,--showPubKey Display public key separately (if applicable) diff --git a/pom.xml b/pom.xml index 83520dc..5b70572 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ org.mitre json-web-key-generator - 1.1.0-SNAPSHOT + 1.2.0-SNAPSHOT jar json-web-key-generator diff --git a/src/main/java/org/mitre/jose/jwk/ECKeyMaker.java b/src/main/java/org/mitre/jose/jwk/ECKeyMaker.java index 9c3edec..3e6b85d 100644 --- a/src/main/java/org/mitre/jose/jwk/ECKeyMaker.java +++ b/src/main/java/org/mitre/jose/jwk/ECKeyMaker.java @@ -25,6 +25,8 @@ */ public class ECKeyMaker { + public static final Curve DEFAULT_CURVE = Curve.P_256; + /** * @param crv * @param keyUse diff --git a/src/main/java/org/mitre/jose/jwk/Launcher.java b/src/main/java/org/mitre/jose/jwk/Launcher.java index 7c2bd79..7f2e716 100644 --- a/src/main/java/org/mitre/jose/jwk/Launcher.java +++ b/src/main/java/org/mitre/jose/jwk/Launcher.java @@ -59,6 +59,8 @@ import com.nimbusds.jose.jwk.JWKSet; import com.nimbusds.jose.jwk.KeyType; import com.nimbusds.jose.jwk.KeyUse; +import com.nimbusds.jose.jwk.OctetSequenceKey; +import com.nimbusds.jose.jwk.RSAKey; import com.nimbusds.jose.util.JSONObjectUtils; /** @@ -124,7 +126,7 @@ public static void main(String[] args) { // parse out the important bits - KeyType keyType = KeyType.parse(kty); + KeyType keyType = parseKeyType(kty); KeyUse keyUse = validateKeyUse(use); @@ -151,10 +153,13 @@ private static void configureCommandLineOptions(Options options) { options.addOption("t", "type", true, "Key Type, one of: " + keyTypes.stream() .map(KeyType::getValue) - .collect(Collectors.joining(", "))); + .collect(Collectors.joining(", ")) + + " (case-insensitive)"); options.addOption("s", "size", true, - "Key Size in bits, required for " + KeyType.RSA.getValue() + " and " + KeyType.OCT.getValue() + " key types. Must be an integer divisible by 8"); + "Key Size in bits, required for " + KeyType.RSA.getValue() + " and " + KeyType.OCT.getValue() + " key types. " + + "Must be an integer divisible by 8. " + "If omitted, defaults to " + RSAKeyMaker.DEFAULT_KEY_SIZE + " for " + + KeyType.RSA + ", " + OctetSequenceKeyMaker.DEFAULT_KEY_SIZE + " for " + KeyType.OCT); options.addOption("c", "curve", true, "Key Curve, required for " + KeyType.EC.getValue() + " or " + KeyType.OKP.getValue() + " key type. Must be one of " + ecCurves.stream() @@ -164,7 +169,8 @@ private static void configureCommandLineOptions(Options options) { + okpCurves.stream() .map(Curve::getName) .collect(Collectors.joining(", ")) - + " for OKP keys."); + + " for OKP keys. " + "If omitted, defaults to " + ECKeyMaker.DEFAULT_CURVE + " for " + KeyType.EC + ", " + + OKPKeyMaker.DEFAULT_CURVE + " for " + KeyType.OKP); options.addOption("u", "usage", true, "Usage, one of: enc, sig (optional)"); options.addOption("a", "algorithm", true, "Algorithm (optional)"); @@ -200,55 +206,50 @@ private static KeyUse validateKeyUse(String use) { } } - private static JWK makeKey(String size, KeyIdGenerator kid, String crv, KeyType keyType, KeyUse keyUse, Algorithm keyAlg) { + private static JWK makeKey(String size, KeyIdGenerator kid, String crv, KeyType keyType, KeyUse keyUse, Algorithm keyAlg) { JWK jwk; if (keyType.equals(KeyType.RSA)) { - jwk = makeRsaKey(kid, size, keyType, keyUse, keyAlg); + jwk = makeRsaKey(kid, size, keyUse, keyAlg); } else if (keyType.equals(KeyType.OCT)) { - jwk = makeOctKey(kid, size, keyType, keyUse, keyAlg); + jwk = makeOctKey(kid, size, keyUse, keyAlg); } else if (keyType.equals(KeyType.EC)) { - jwk = makeEcKey(kid, crv, keyType, keyUse, keyAlg); + jwk = makeEcKey(kid, crv, keyUse, keyAlg); } else if (keyType.equals(KeyType.OKP)) { - jwk = makeOkpKey(kid, crv, keyType, keyUse, keyAlg); + jwk = makeOkpKey(kid, crv, keyUse, keyAlg); } else { throw printUsageAndExit("Unknown key type: " + keyType); } return jwk; } - private static JWK makeOkpKey(KeyIdGenerator kid, String crv, KeyType keyType, KeyUse keyUse, Algorithm keyAlg) { - if (Strings.isNullOrEmpty(crv)) { - throw printUsageAndExit("Curve is required for key type " + keyType); - } - Curve keyCurve = Curve.parse(crv); + private static JWK makeOkpKey(KeyIdGenerator kid, String crv, KeyUse keyUse, Algorithm keyAlg) { + Curve keyCurve = Strings.isNullOrEmpty(crv) ? OKPKeyMaker.DEFAULT_CURVE : Curve.parse(crv); if (!okpCurves.contains(keyCurve)) { - throw printUsageAndExit("Curve " + crv + " is not valid for key type " + keyType); + throw printUsageAndExit("Curve " + crv + " is not valid for key type " + KeyType.OKP); } return OKPKeyMaker.make(keyCurve, keyUse, keyAlg, kid); } - private static JWK makeEcKey(KeyIdGenerator kid, String crv, KeyType keyType, KeyUse keyUse, Algorithm keyAlg) { - if (Strings.isNullOrEmpty(crv)) { - throw printUsageAndExit("Curve is required for key type " + keyType); - } - Curve keyCurve = Curve.parse(crv); + private static JWK makeEcKey(KeyIdGenerator kid, String crv, KeyUse keyUse, Algorithm keyAlg) { + Curve keyCurve = Strings.isNullOrEmpty(crv) ? ECKeyMaker.DEFAULT_CURVE : Curve.parse(crv); if (!ecCurves.contains(keyCurve)) { - throw printUsageAndExit("Curve " + crv + " is not valid for key type " + keyType); + throw printUsageAndExit("Curve " + crv + " is not valid for key type " + KeyType.EC); } return ECKeyMaker.make(keyCurve, keyUse, keyAlg, kid); } - private static JWK makeOctKey(KeyIdGenerator kid, String size, KeyType keyType, KeyUse keyUse, Algorithm keyAlg) { - if (Strings.isNullOrEmpty(size)) { - throw printUsageAndExit("Key size (in bits) is required for key type " + keyType); + private static OctetSequenceKey makeOctKey(KeyIdGenerator kid, String size, KeyUse keyUse, Algorithm keyAlg) { + String keySizeValue = size; + if (Strings.isNullOrEmpty(keySizeValue)) { + keySizeValue = OctetSequenceKeyMaker.DEFAULT_KEY_SIZE; } - // surrounding try/catch catches numberformatexception from this - Integer keySize = Integer.decode(size); + // surrounding try/catch catches NumberFormatException from this + Integer keySize = Integer.decode(keySizeValue); if (keySize % 8 != 0) { throw printUsageAndExit("Key size (in bits) must be divisible by 8, got " + keySize); } @@ -256,13 +257,14 @@ private static JWK makeOctKey(KeyIdGenerator kid, String size, KeyType keyType, return OctetSequenceKeyMaker.make(keySize, keyUse, keyAlg, kid); } - private static JWK makeRsaKey(KeyIdGenerator kid, String size, KeyType keyType, KeyUse keyUse, Algorithm keyAlg) { - if (Strings.isNullOrEmpty(size)) { - throw printUsageAndExit("Key size (in bits) is required for key type " + keyType); + private static RSAKey makeRsaKey(KeyIdGenerator kid, String size, KeyUse keyUse, Algorithm keyAlg) { + String keySizeValue = size; + if (Strings.isNullOrEmpty(keySizeValue)) { + keySizeValue = RSAKeyMaker.DEFAULT_KEY_SIZE; } - // surrounding try/catch catches numberformatexception from this - Integer keySize = Integer.decode(size); + // surrounding try/catch catches NumberFormatException from this + Integer keySize = Integer.decode(keySizeValue); if (keySize % 8 != 0) { throw printUsageAndExit("Key size (in bits) must be divisible by 8, got " + keySize); } @@ -464,4 +466,13 @@ private static IllegalArgumentException printUsageAndExit(String message) { System.exit(1); return new IllegalArgumentException("Program was called with invalid arguments"); } + + private static KeyType parseKeyType(String kty) { + for (KeyType kt : keyTypes) { + if (kt.getValue().equalsIgnoreCase(kty)) { + return kt; + } + } + return new KeyType(kty, null); + } } diff --git a/src/main/java/org/mitre/jose/jwk/OKPKeyMaker.java b/src/main/java/org/mitre/jose/jwk/OKPKeyMaker.java index 30ceabc..cffe7b9 100644 --- a/src/main/java/org/mitre/jose/jwk/OKPKeyMaker.java +++ b/src/main/java/org/mitre/jose/jwk/OKPKeyMaker.java @@ -24,6 +24,8 @@ */ public class OKPKeyMaker { + public static final Curve DEFAULT_CURVE = Curve.Ed25519; + /** * @param keyCurve * @param keyUse diff --git a/src/main/java/org/mitre/jose/jwk/OctetSequenceKeyMaker.java b/src/main/java/org/mitre/jose/jwk/OctetSequenceKeyMaker.java index e2446fb..b6a3a63 100644 --- a/src/main/java/org/mitre/jose/jwk/OctetSequenceKeyMaker.java +++ b/src/main/java/org/mitre/jose/jwk/OctetSequenceKeyMaker.java @@ -18,6 +18,8 @@ */ public class OctetSequenceKeyMaker { + public static final String DEFAULT_KEY_SIZE = "2048"; + /** * @param keySize in bits * @return diff --git a/src/main/java/org/mitre/jose/jwk/RSAKeyMaker.java b/src/main/java/org/mitre/jose/jwk/RSAKeyMaker.java index 5334c3f..1db8f72 100644 --- a/src/main/java/org/mitre/jose/jwk/RSAKeyMaker.java +++ b/src/main/java/org/mitre/jose/jwk/RSAKeyMaker.java @@ -22,6 +22,8 @@ */ public class RSAKeyMaker { + public static final String DEFAULT_KEY_SIZE = "2048"; + /** * @param keySize * @param keyUse