Skip to content
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -218,24 +213,38 @@ public static byte[] generateSalt(int bytes) {
return randomBytes;
}

/**
* get JWK string from JWK map
* @param jwk Map<String,Object>
* @return jwkString
*/
public static String getJWKString(Map<String, Object> 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);
}

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -150,20 +150,51 @@ public void test_generateSalt() {

@Test
public void getJWKString_withValidAndMissingKty_thenFail() {
Assertions.assertNotNull(IdentityProviderUtil.getJWKString((Map<String, Object>) generateJWK_RSA().getRequiredParams()));
try {
IdentityProviderUtil.getJWKString(new HashMap<String, Object>()); // missing kty
Assertions.fail();
} catch (EsignetException e) {
Assertions.assertEquals(ErrorConstants.INVALID_PUBLIC_KEY, e.getMessage());
}
Map<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> jwkMap = new HashMap<>();
jwkMap.put("kty", "OCT"); // Unsupported key type

try {
IdentityProviderUtil.getJWKString(jwkMap);
Assertions.fail("Expected EsignetException was not thrown");
Expand All @@ -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<String, Object> 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<String, Object> 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<String, Object> 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<String, Object> 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\""));
}
Expand Down
2 changes: 2 additions & 0 deletions esignet-service/src/test/java/io/mosip/esignet/TestUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
*/
package io.mosip.esignet;

import com.nimbusds.jose.Algorithm;
import com.nimbusds.jose.jwk.*;
import lombok.extern.slf4j.Slf4j;

Expand All @@ -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) {
Expand Down
Loading