diff --git a/binding-service-impl/src/test/java/io/mosip/esignet/KeyBindingServiceTest.java b/binding-service-impl/src/test/java/io/mosip/esignet/KeyBindingServiceTest.java index 8cc8917a5..ccdc681e6 100644 --- a/binding-service-impl/src/test/java/io/mosip/esignet/KeyBindingServiceTest.java +++ b/binding-service-impl/src/test/java/io/mosip/esignet/KeyBindingServiceTest.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; +import com.nimbusds.jose.Algorithm; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.KeyUse; import com.nimbusds.jose.jwk.RSAKey; @@ -417,6 +418,7 @@ public static JWK generateJWK_RSA() { return new RSAKey.Builder((RSAPublicKey) keyPair.getPublic()) .privateKey((RSAPrivateKey) keyPair.getPrivate()) .keyUse(KeyUse.SIGNATURE) + .algorithm(new Algorithm("RS256")) .keyID(UUID.randomUUID().toString()) .build(); } catch (Exception e) { diff --git a/client-management-service-impl/src/test/java/io/mosip/esignet/ClientManagementServiceTest.java b/client-management-service-impl/src/test/java/io/mosip/esignet/ClientManagementServiceTest.java index 5cfe740e1..ecbb38fa5 100644 --- a/client-management-service-impl/src/test/java/io/mosip/esignet/ClientManagementServiceTest.java +++ b/client-management-service-impl/src/test/java/io/mosip/esignet/ClientManagementServiceTest.java @@ -7,6 +7,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; +import com.nimbusds.jose.Algorithm; import com.nimbusds.jose.jwk.JWK; import com.nimbusds.jose.jwk.KeyUse; import com.nimbusds.jose.jwk.RSAKey; @@ -349,6 +350,7 @@ public static JWK generateJWK_RSA() { return new RSAKey.Builder((RSAPublicKey)keyPair.getPublic()) .privateKey((RSAPrivateKey)keyPair.getPrivate()) .keyUse(KeyUse.SIGNATURE) + .algorithm(new Algorithm("RS256")) .keyID(UUID.randomUUID().toString()) .build(); } catch (NoSuchAlgorithmException e) { diff --git a/esignet-core/src/main/java/io/mosip/esignet/core/util/IdentityProviderUtil.java b/esignet-core/src/main/java/io/mosip/esignet/core/util/IdentityProviderUtil.java index f79b6dc31..830a19c61 100644 --- a/esignet-core/src/main/java/io/mosip/esignet/core/util/IdentityProviderUtil.java +++ b/esignet-core/src/main/java/io/mosip/esignet/core/util/IdentityProviderUtil.java @@ -16,12 +16,7 @@ import java.time.ZoneOffset; import java.time.ZonedDateTime; import java.time.format.DateTimeFormatter; -import java.util.Arrays; -import java.util.Base64; -import java.util.List; -import java.util.Map; -import java.util.UUID; -import java.util.Objects; +import java.util.*; import java.util.concurrent.ThreadLocalRandom; import io.mosip.esignet.core.constants.Constants; @@ -218,24 +213,38 @@ public static byte[] generateSalt(int bytes) { return randomBytes; } + /** + * get JWK string from JWK map + * @param jwk Map + * @return jwkString + */ public static String getJWKString(Map jwk) throws EsignetException { + String keyType = (String) jwk.get("kty"); + String use = (String) jwk.get("use"); + String alg = (String) jwk.get("alg"); + + if (keyType == null || alg==null || use==null) { + throw new EsignetException(ErrorConstants.INVALID_PUBLIC_KEY); + } + try { - String keyType = (String) jwk.get("kty"); - if (keyType != null) { - switch (keyType) { - case "RSA": - return new RsaJsonWebKey(jwk).toJson(); - case "EC": - return new EllipticCurveJsonWebKey(jwk).toJson(); - default: - log.error("Unsupported key type '{}' in JWK", keyType); + String jwkString = switch (keyType) { + case "RSA" -> new RsaJsonWebKey(jwk).toJson(); + case "EC" -> new EllipticCurveJsonWebKey(jwk).toJson(); + default -> { + log.error("Unsupported key type '{}' in JWK", keyType); + throw new EsignetException(ErrorConstants.INVALID_PUBLIC_KEY); } + }; + // Validate alg and use fields as RSAPublicKey and ECPublicKey classes do not validate these fields + if (alg.isEmpty() || use.isEmpty()) { + throw new EsignetException(ErrorConstants.INVALID_PUBLIC_KEY); } + return jwkString; } catch (JoseException e) { log.error("Error creating JWK: {}", e.getMessage(), e); + throw new EsignetException(ErrorConstants.INVALID_PUBLIC_KEY); } - log.error("Missing 'kty' field in JWK"); - throw new EsignetException(ErrorConstants.INVALID_PUBLIC_KEY); } /** diff --git a/esignet-core/src/test/java/io/mosip/esignet/core/IdentityProviderUtilTest.java b/esignet-core/src/test/java/io/mosip/esignet/core/IdentityProviderUtilTest.java index 7209df7e1..263b3e888 100644 --- a/esignet-core/src/test/java/io/mosip/esignet/core/IdentityProviderUtilTest.java +++ b/esignet-core/src/test/java/io/mosip/esignet/core/IdentityProviderUtilTest.java @@ -150,20 +150,51 @@ public void test_generateSalt() { @Test public void getJWKString_withValidAndMissingKty_thenFail() { - Assertions.assertNotNull(IdentityProviderUtil.getJWKString((Map) generateJWK_RSA().getRequiredParams())); - try { - IdentityProviderUtil.getJWKString(new HashMap()); // missing kty - Assertions.fail(); - } catch (EsignetException e) { - Assertions.assertEquals(ErrorConstants.INVALID_PUBLIC_KEY, e.getMessage()); - } + Map jwk = new HashMap<>(); + jwk.put("alg", "RS256"); + jwk.put("use", "sig"); + EsignetException ex = Assertions.assertThrows(EsignetException.class, + () -> IdentityProviderUtil.getJWKString(jwk)); + Assertions.assertEquals(ErrorConstants.INVALID_PUBLIC_KEY, ex.getMessage()); + } + + @Test + public void getJWKString_withEmptyAlgOrUse_thenFail() { + Map jwk = new HashMap<>(); + jwk.put("kty", "RSA"); + jwk.put("n", "oahUIzUup5kqncCkHk5Zb1pRrLx7e6YtM-9jX1f5e6mHnZFkC2LJUZ0sEh0n5Y5KnQfW9s7d7gK2b8P0EEl0h3ZyHkWzA3YbsgzB4pDxP4RxMZ1I8xD2z3UvfA1zjvKDHz6wEweq4hVJ8nS8GzZJ2E_vb3s"); + jwk.put("e", "AQAB"); + jwk.put("alg", ""); + jwk.put("use", ""); + EsignetException ex = Assertions.assertThrows(EsignetException.class, + () -> IdentityProviderUtil.getJWKString(jwk)); + Assertions.assertEquals(ErrorConstants.INVALID_PUBLIC_KEY, ex.getMessage()); + } + + @Test + public void getJWKString_withMissingAlg_thenFail() { + Map jwk = new HashMap<>(); + jwk.put("kty", "RSA"); + jwk.put("use", "sig"); + EsignetException ex = Assertions.assertThrows(EsignetException.class, + () -> IdentityProviderUtil.getJWKString(jwk)); + Assertions.assertEquals(ErrorConstants.INVALID_PUBLIC_KEY, ex.getMessage()); + } + + @Test + public void getJWKString_withMissingUse_thenFail() { + Map jwk = new HashMap<>(); + jwk.put("kty", "RSA"); + jwk.put("alg", "RS256"); + EsignetException ex = Assertions.assertThrows(EsignetException.class, + () -> IdentityProviderUtil.getJWKString(jwk)); + Assertions.assertEquals(ErrorConstants.INVALID_PUBLIC_KEY, ex.getMessage()); } @Test public void getJWKString_withUnsupportedKty_thenFail() { Map jwkMap = new HashMap<>(); jwkMap.put("kty", "OCT"); // Unsupported key type - try { IdentityProviderUtil.getJWKString(jwkMap); Assertions.fail("Expected EsignetException was not thrown"); @@ -178,19 +209,59 @@ public void getJWKString_withValidRSAKey_thenPass() throws Exception { jwkMap.put("kty", "RSA"); jwkMap.put("n", "oahUIzUup5kqncCkHk5Zb1pRrLx7e6YtM-9jX1f5e6mHnZFkC2LJUZ0sEh0n5Y5KnQfW9s7d7gK2b8P0EEl0h3ZyHkWzA3YbsgzB4pDxP4RxMZ1I8xD2z3UvfA1zjvKDHz6wEweq4hVJ8nS8GzZJ2E_vb3s"); jwkMap.put("e", "AQAB"); + jwkMap.put("alg", "RS256"); + jwkMap.put("use", "sig"); + String jwkJson = IdentityProviderUtil.getJWKString(jwkMap); + Assertions.assertTrue(jwkJson.contains("\"kty\":\"RSA\"")); + } + @Test + public void getJWKString_withValidFullRSAKey_thenPass() { + Map jwkMap = new HashMap<>(); + jwkMap.put("kty", "RSA"); + jwkMap.put("n", "oahUIzUup5kqncCkHk5Zb1pRrLx7e6YtM-9jX1f5e6mHnZFkC2LJUZ0sEh0n5Y5KnQfW9s7d7gK2b8P0EEl0h3ZyHkWzA3YbsgzB4pDxP4RxMZ1I8xD2z3UvfA1zjvKDHz6wEweq4hVJ8nS8GzZJ2E_vb3s"); + jwkMap.put("e", "AQAB"); + jwkMap.put("alg", "RS256"); + jwkMap.put("use", "sig"); String jwkJson = IdentityProviderUtil.getJWKString(jwkMap); Assertions.assertTrue(jwkJson.contains("\"kty\":\"RSA\"")); } @Test - public void getJWKString_withValidECKey_thenPass() throws Exception { + public void getJWKString_withInvalidAlgForRSA_thenFail() { + Map jwkMap = new HashMap<>(); + jwkMap.put("kty", "RSA"); + jwkMap.put("n", "oahUIzUup5kqncCkHk5Zb1pRrLx7e6YtM-9jX1f5e6mHnZFkC2LJUZ0sEh0n5Y5KnQfW9s7d7gK2b8P0EEl0h3ZyHkWzA3YbsgzB4pDxP4RxMZ1I8xD2z3UvfA1zjvKDHz6wEweq4hVJ8nS8GzZJ2E_vb3s"); + jwkMap.put("e", "AQAB"); + jwkMap.put("alg", "ES256"); + + EsignetException ex = Assertions.assertThrows(EsignetException.class, + () -> IdentityProviderUtil.getJWKString(jwkMap)); + Assertions.assertEquals(ErrorConstants.INVALID_PUBLIC_KEY, ex.getMessage()); + } + + @Test + public void getJWKString_withInvalidUse_thenFail() { + Map jwkMap = new HashMap<>(); + jwkMap.put("kty", "RSA"); + jwkMap.put("n", "oahUIzUup5kqncCkHk5Zb1pRrLx7e6YtM-9jX1f5e6mHnZFkC2LJUZ0sEh0n5Y5KnQfW9s7d7gK2b8P0EEl0h3ZyHkWzA3YbsgzB4pDxP4RxMZ1I8xD2z3UvfA1zjvKDHz6wEweq4hVJ8nS8GzZJ2E_vb3s"); + jwkMap.put("e", "AQAB"); + jwkMap.put("use", "enc"); + + EsignetException ex = Assertions.assertThrows(EsignetException.class, + () -> IdentityProviderUtil.getJWKString(jwkMap)); + Assertions.assertEquals(ErrorConstants.INVALID_PUBLIC_KEY, ex.getMessage()); + } + + @Test + public void getJWKString_withValidECKey_thenPass() { Map jwkMap = new HashMap<>(); jwkMap.put("kty", "EC"); jwkMap.put("crv", "P-256"); jwkMap.put("x", "f83OJ3D2xF4vOQ6aE1n8bQJ8iTo2DJH6TLO8kMZb3mg"); jwkMap.put("y", "x_FEzRu9l1tlZRjGZkIvYyC6i76h3C1j6w9kq3fJSNc"); - + jwkMap.put("alg", "ES256"); + jwkMap.put("use", "sig"); String jwkJson = IdentityProviderUtil.getJWKString(jwkMap); Assertions.assertTrue(jwkJson.contains("\"kty\":\"EC\"")); } diff --git a/esignet-service/src/test/java/io/mosip/esignet/TestUtil.java b/esignet-service/src/test/java/io/mosip/esignet/TestUtil.java index 303997190..cc9e24292 100644 --- a/esignet-service/src/test/java/io/mosip/esignet/TestUtil.java +++ b/esignet-service/src/test/java/io/mosip/esignet/TestUtil.java @@ -5,6 +5,7 @@ */ package io.mosip.esignet; +import com.nimbusds.jose.Algorithm; import com.nimbusds.jose.jwk.*; import lombok.extern.slf4j.Slf4j; @@ -30,6 +31,7 @@ public static JWK generateJWK_RSA() { return new RSAKey.Builder((RSAPublicKey)keyPair.getPublic()) .privateKey((RSAPrivateKey)keyPair.getPrivate()) .keyUse(KeyUse.SIGNATURE) + .algorithm(new Algorithm("RS256")) .keyID(UUID.randomUUID().toString()) .build(); } catch (NoSuchAlgorithmException e) {