diff --git a/sigstore-java/src/main/java/dev/sigstore/encryption/Keys.java b/sigstore-java/src/main/java/dev/sigstore/encryption/Keys.java index 3bbce56d..0db4619e 100644 --- a/sigstore-java/src/main/java/dev/sigstore/encryption/Keys.java +++ b/sigstore-java/src/main/java/dev/sigstore/encryption/Keys.java @@ -108,6 +108,24 @@ public static PublicKey parsePublicKey(byte[] keyBytes) return keyFactory.generatePublic(publicKeySpec); } + /** + * Takes a PKIX DER formatted public key in bytes and constructs a {@code PublicKey} with it. + * + *
This method is known to work with keys algorithms: RSA, EdDSA, EC. + * + * @param contents the public key bytes + * @param algorithm the key algorithm + * @return a PublicKey object + * @throws NoSuchAlgorithmException if we don't support the scheme provided + * @throws InvalidKeySpecException if the public key material is invalid + */ + public static PublicKey parsePkixPublicKey(byte[] contents, String algorithm) + throws NoSuchAlgorithmException, InvalidKeySpecException { + X509EncodedKeySpec spec = new X509EncodedKeySpec(contents); + KeyFactory factory = KeyFactory.getInstance(algorithm); + return factory.generatePublic(spec); + } + /** * Valid values for scheme are: * @@ -127,16 +145,12 @@ public static PublicKey parsePublicKey(byte[] keyBytes) */ public static PublicKey constructTufPublicKey(byte[] contents, String scheme) throws NoSuchAlgorithmException, InvalidKeySpecException { - PublicKey publicKey = null; switch (scheme) { - case "rsassa-pss-sha256": - throw new RuntimeException("rsassa-pss-sha256 not currently supported"); case "ed25519": { final KeyFactory kf = KeyFactory.getInstance("Ed25519"); final X509EncodedKeySpec keySpec = new X509EncodedKeySpec(contents); - publicKey = kf.generatePublic(keySpec); - break; + return kf.generatePublic(keySpec); } case "ecdsa-sha2-nistp256": { @@ -157,11 +171,11 @@ public static PublicKey constructTufPublicKey(byte[] contents, String scheme) new ECNamedCurveSpec("P-256", spec.getCurve(), spec.getG(), spec.getN()); ECPoint point = decodePoint(params.getCurve(), contents); ECPublicKeySpec pubKeySpec = new ECPublicKeySpec(point, params); - publicKey = kf.generatePublic(pubKeySpec); - break; + return kf.generatePublic(pubKeySpec); } + default: + throw new RuntimeException(scheme + " not currently supported"); } - return publicKey; } // https://stackoverflow.com/questions/42911637/get-publickey-from-key-bytes-not-knowing-the-key-algorithm diff --git a/sigstore-java/src/test/java/dev/sigstore/encryption/KeysTest.java b/sigstore-java/src/test/java/dev/sigstore/encryption/KeysTest.java index b8cf1e11..f9a46907 100644 --- a/sigstore-java/src/test/java/dev/sigstore/encryption/KeysTest.java +++ b/sigstore-java/src/test/java/dev/sigstore/encryption/KeysTest.java @@ -23,6 +23,7 @@ import java.security.NoSuchProviderException; import java.security.PublicKey; import java.security.spec.InvalidKeySpecException; +import org.bouncycastle.util.encoders.Base64; import org.bouncycastle.util.encoders.Hex; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; @@ -155,33 +156,56 @@ void parseTufPublicKey_ed25519_lteJava14() @Test void parseTufPublicKey_ed25519Bad() { - - try { - PublicKey key = - Keys.constructTufPublicKey( - Hex.decode( - "302b300506032b65700321008b2e369230c3b97f4627fd6a59eb054a83ec15ed929ab3d983a40ffd322a223d"), - "ed25519"); - fail(); - } catch (Exception e) { - } + Assertions.assertThrows( + InvalidKeySpecException.class, + () -> + Keys.constructTufPublicKey( + Hex.decode( + "302b300506032b65700321008b2e369230c3b97f4627fd6a59eb054a83ec15ed929ab3d983a40ffd322a223d"), + "ed25519")); } @Test - void parseTufPublicKey_rsa() - throws NoSuchAlgorithmException, InvalidKeySpecException, NoSuchProviderException { + void parseTufPublicKey_rsa() throws NoSuchAlgorithmException, InvalidKeySpecException { // {@code step crypto keypair ed25519.pub /dev/null --kty OKP --curve Ed25519} // copy just the key part out of ed25519.pub removing PEM header and footer // {@code echo $(copied content) | base64 -d | hexdump -v -e '/1 "%02x" '} - try { - PublicKey key = - Keys.constructTufPublicKey( - Hex.decode( - "302a300506032b65700321008b2e369230c3b97f4627fd6a59eb054a83ec15ed929ab3d983a40ffd322a223d"), - "rsassa-pss-sha256"); - fail(); - } catch (RuntimeException e) { - } + Assertions.assertThrows( + RuntimeException.class, + () -> + Keys.constructTufPublicKey( + Hex.decode( + "302a300506032b65700321008b2e369230c3b97f4627fd6a59eb054a83ec15ed929ab3d983a40ffd322a223d"), + "rsassa-pss-sha256")); + } + + @Test + void parsePkixPublicKey_rsa() throws NoSuchAlgorithmException, InvalidKeySpecException { + var base64Key = + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAghWkDAnX9F5QZZ9NxIWg9vcjULtD/kkbQwlcSm22e06FrgOdiFy1fKN/Ng32qEk1ZIKyi0HFzZxzPIcvg7eaFTRb7+AQiG6eMDmUzPGr67Jp0Di2ncH9+uOZmv4PVKovvQLq7qnEwbDk0HttxUscLQ2e36Lfv/2lpGW7apVmHVMoC5kwZ3KTiAk/DUtDhD4VQjU2rBy6OneO6pm6vdNzG4Jktjc0uUKFCRRUzydGEh05PgC9vSQu/EOiU+7aQPV1ZDUGpjg9tOM0SgaTOU3YSUfGiXZNHoiS2HwLyQPaxiHR2NPVH75bwnUFBHhdMxT1rhU+yLhXaweDQW6GQ0ti8wIDAQAB"; + Assertions.assertNotNull(Keys.parsePkixPublicKey(Base64.decode(base64Key), "RSA")); + } + + @Test + void parsePkixPublicKey_rsaKeyButWrongAlgorithm() { + var base64Key = + "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAghWkDAnX9F5QZZ9NxIWg9vcjULtD/kkbQwlcSm22e06FrgOdiFy1fKN/Ng32qEk1ZIKyi0HFzZxzPIcvg7eaFTRb7+AQiG6eMDmUzPGr67Jp0Di2ncH9+uOZmv4PVKovvQLq7qnEwbDk0HttxUscLQ2e36Lfv/2lpGW7apVmHVMoC5kwZ3KTiAk/DUtDhD4VQjU2rBy6OneO6pm6vdNzG4Jktjc0uUKFCRRUzydGEh05PgC9vSQu/EOiU+7aQPV1ZDUGpjg9tOM0SgaTOU3YSUfGiXZNHoiS2HwLyQPaxiHR2NPVH75bwnUFBHhdMxT1rhU+yLhXaweDQW6GQ0ti8wIDAQAB"; + Assertions.assertThrows( + InvalidKeySpecException.class, + () -> Keys.parsePkixPublicKey(Base64.decode(base64Key), "EC")); + } + + @Test + void parsePkixPublicKey_eddsa() throws NoSuchAlgorithmException, InvalidKeySpecException { + var base64Key = "MCowBQYDK2VwAyEAixzZOnx34hveTZ69J5iBCkmerK5Oh7EzJqTh3YY55jI="; + Assertions.assertNotNull(Keys.parsePkixPublicKey(Base64.decode(base64Key), "EdDSA")); + } + + @Test + void parsePkixPublicKey_ecdsa() throws NoSuchAlgorithmException, InvalidKeySpecException { + var base64Key = + "MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEVqBnvab9XEVlTLW4iGKBIdrL6Sxf0x5vclZyXtR6hl79/o+RSgyr1ZQKLLCUC20imDWUgFMmfLu4UUiKNcI2uQ=="; + Assertions.assertNotNull(Keys.parsePkixPublicKey(Base64.decode(base64Key), "EC")); } @Test