diff --git a/core/common/lib/crypto-common-lib/src/main/java/org/eclipse/edc/security/token/jwt/CryptoConverter.java b/core/common/lib/crypto-common-lib/src/main/java/org/eclipse/edc/security/token/jwt/CryptoConverter.java index bdda18fada8..7f2af352f83 100644 --- a/core/common/lib/crypto-common-lib/src/main/java/org/eclipse/edc/security/token/jwt/CryptoConverter.java +++ b/core/common/lib/crypto-common-lib/src/main/java/org/eclipse/edc/security/token/jwt/CryptoConverter.java @@ -50,6 +50,7 @@ import java.security.interfaces.EdECKey; import java.security.interfaces.EdECPrivateKey; import java.security.interfaces.EdECPublicKey; +import java.security.interfaces.RSAPrivateCrtKey; import java.security.interfaces.RSAPublicKey; import java.security.spec.ECGenParameterSpec; import java.security.spec.ECPoint; @@ -302,8 +303,24 @@ private static Curve getCurveAllowing(EdECKey edKey, String... allowedCurves) { } private static RSAKey convertRsaKey(KeyPair keypair, @Nullable String kid) { - return new RSAKey.Builder((RSAPublicKey) keypair.getPublic()) - .privateKey(keypair.getPrivate()) + + if (keypair.getPublic() == null && keypair.getPrivate() == null) { + throw new IllegalArgumentException("Either the public or the private key of a keypair must be non-null when converting RSA -> JWK"); + } + var key = Optional.ofNullable(keypair.getPublic()).orElseGet(() -> { + var keySpec = new java.security.spec.RSAPublicKeySpec(((RSAPrivateCrtKey) keypair.getPrivate()).getModulus(), ((RSAPrivateCrtKey) keypair.getPrivate()).getPublicExponent()); + try { + var gen = KeyFactory.getInstance("RSA"); + return gen.generatePublic(keySpec); + } catch (NoSuchAlgorithmException | InvalidKeySpecException e) { + throw new RuntimeException(e); + } + }); + var builder = new RSAKey.Builder((RSAPublicKey) key); + if (keypair.getPrivate() != null) { + builder.privateKey(keypair.getPrivate()); + } + return builder .keyID(kid) .keyUse(KeyUse.SIGNATURE).build(); } diff --git a/core/common/lib/crypto-common-lib/src/test/java/org/eclipse/edc/security/token/jwt/CryptoConverterTest.java b/core/common/lib/crypto-common-lib/src/test/java/org/eclipse/edc/security/token/jwt/CryptoConverterTest.java index 5d27c028b07..994c46b049d 100644 --- a/core/common/lib/crypto-common-lib/src/test/java/org/eclipse/edc/security/token/jwt/CryptoConverterTest.java +++ b/core/common/lib/crypto-common-lib/src/test/java/org/eclipse/edc/security/token/jwt/CryptoConverterTest.java @@ -148,6 +148,33 @@ void createJwk_rsaKey() throws NoSuchAlgorithmException { assertThat(jwk.getKeyID()).isNull(); } + @Test + void createJwk_rsaKey_onlyPrivate() throws NoSuchAlgorithmException { + var pk = createRsa(); + var keypair = new KeyPair(null, pk.getPrivate()); + var jwk = CryptoConverter.createJwk(keypair); + assertThat(jwk).isInstanceOf(RSAKey.class); + assertThat(jwk.isPrivate()).isTrue(); + assertThat(jwk.getKeyID()).isNull(); + } + + @Test + void createJwk_rsaKey_whenEmptyKeypair() throws NoSuchAlgorithmException { + var keypair = new KeyPair(null, null); + assertThatThrownBy(() -> CryptoConverter.createJwk(keypair)) + .isInstanceOf(IllegalArgumentException.class); + } + + @Test + void createJwk_rsaKey_onlyPublic() throws NoSuchAlgorithmException { + var pk = createRsa(); + var keypair = new KeyPair(pk.getPublic(), null); + var jwk = CryptoConverter.createJwk(keypair); + assertThat(jwk).isInstanceOf(RSAKey.class); + assertThat(jwk.isPrivate()).isFalse(); + assertThat(jwk.getKeyID()).isNull(); + } + @Test void createJwk_rsaKey_withKeyId() throws NoSuchAlgorithmException { var pk = createRsa();