diff --git a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/cryptomanager/test/service/Argon2HashServiceTest.java b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/cryptomanager/test/service/Argon2HashServiceTest.java index 44caf87d..ce54c172 100644 --- a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/cryptomanager/test/service/Argon2HashServiceTest.java +++ b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/cryptomanager/test/service/Argon2HashServiceTest.java @@ -1,24 +1,39 @@ package io.mosip.kernel.cryptomanager.test.service; -import static org.junit.Assert.*; -import static org.mockito.ArgumentMatchers.*; -import static org.mockito.Mockito.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyInt; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.mockStatic; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; import java.lang.reflect.Field; -import java.lang.reflect.Method; +import java.util.concurrent.atomic.AtomicLong; -import javax.crypto.KeyGenerator; import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; +import org.cache2k.Cache; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; +import org.mockito.MockedStatic; import org.mockito.junit.MockitoJUnitRunner; +import de.mkammerer.argon2.Argon2Advanced; +import de.mkammerer.argon2.Argon2Factory; import io.mosip.kernel.core.http.RequestWrapper; import io.mosip.kernel.core.http.ResponseWrapper; +import io.mosip.kernel.core.util.CryptoUtil; +import io.mosip.kernel.cryptomanager.constant.CryptomanagerConstant; import io.mosip.kernel.cryptomanager.controller.CryptomanagerController; import io.mosip.kernel.cryptomanager.dto.Argon2GenerateHashRequestDto; import io.mosip.kernel.cryptomanager.dto.Argon2GenerateHashResponseDto; @@ -33,9 +48,18 @@ public class Argon2HashServiceTest { @Mock private CryptomanagerService cryptomanagerService; + @Mock + private Cache saltGenParamsCache; + + @Mock + private CryptomanagerUtils cryptomanagerUtil; + @InjectMocks private CryptomanagerController cryptomanagerController; + @InjectMocks + private CryptomanagerServiceImpl cryptomanagerServiceImpl; + private Argon2GenerateHashRequestDto validRequest; private Argon2GenerateHashRequestDto requestWithSalt; private Argon2GenerateHashResponseDto validResponse; @@ -43,7 +67,7 @@ public class Argon2HashServiceTest { private String testSalt = "dGVzdFNhbHQ"; @Before - public void setUp() { + public void setUp() throws Exception { validRequest = new Argon2GenerateHashRequestDto(); validRequest.setInputData(testInputData); @@ -54,6 +78,19 @@ public void setUp() { validResponse = new Argon2GenerateHashResponseDto(); validResponse.setHashValue("mockHashValue"); validResponse.setSalt("mockSalt"); + + // Initialize private fields in CryptomanagerServiceImpl for Argon2 + Field iterationsField = CryptomanagerServiceImpl.class.getDeclaredField("argon2Iterations"); + iterationsField.setAccessible(true); + iterationsField.set(cryptomanagerServiceImpl, 2); + + Field memoryField = CryptomanagerServiceImpl.class.getDeclaredField("argon2Memory"); + memoryField.setAccessible(true); + memoryField.set(cryptomanagerServiceImpl, 1024); + + Field parallelismField = CryptomanagerServiceImpl.class.getDeclaredField("argon2Parallelism"); + parallelismField.setAccessible(true); + parallelismField.set(cryptomanagerServiceImpl, 1); } @Test @@ -123,189 +160,88 @@ public void testGenerateArgon2Hash_Controller_NullRequest() { } @Test - public void testGenerateArgon2Hash_Service_Success() { - when(cryptomanagerService.generateArgon2Hash(validRequest)) - .thenReturn(validResponse); - - Argon2GenerateHashResponseDto response = cryptomanagerService.generateArgon2Hash(validRequest); - - assertNotNull(response); - assertEquals("mockHashValue", response.getHashValue()); - assertEquals("mockSalt", response.getSalt()); - verify(cryptomanagerService).generateArgon2Hash(validRequest); - } - - @Test - public void testGenerateArgon2Hash_Service_WithProvidedSalt() { - Argon2GenerateHashResponseDto responseWithSalt = new Argon2GenerateHashResponseDto(); - responseWithSalt.setHashValue("hashWithProvidedSalt"); - responseWithSalt.setSalt(testSalt); - - when(cryptomanagerService.generateArgon2Hash(requestWithSalt)) - .thenReturn(responseWithSalt); - - Argon2GenerateHashResponseDto response = cryptomanagerService.generateArgon2Hash(requestWithSalt); - - assertNotNull(response); - assertEquals("hashWithProvidedSalt", response.getHashValue()); - assertEquals(testSalt, response.getSalt()); - verify(cryptomanagerService).generateArgon2Hash(requestWithSalt); - } - - @Test(expected = CryptoManagerSerivceException.class) - public void testGenerateArgon2Hash_Service_InvalidInput() { - Argon2GenerateHashRequestDto invalidRequest = new Argon2GenerateHashRequestDto(); - invalidRequest.setInputData(""); - - when(cryptomanagerService.generateArgon2Hash(invalidRequest)) - .thenThrow(new CryptoManagerSerivceException("KER-CRY-001", "Invalid input data")); - - cryptomanagerService.generateArgon2Hash(invalidRequest); - } + public void testGenerateArgon2HashWithGeneratedSalt() { + Argon2GenerateHashRequestDto request = new Argon2GenerateHashRequestDto(); + request.setInputData("testPassword"); + request.setSalt(null); - @Test(expected = CryptoManagerSerivceException.class) - public void testGenerateArgon2Hash_Service_NullInput() { - Argon2GenerateHashRequestDto nullRequest = new Argon2GenerateHashRequestDto(); - nullRequest.setInputData(null); + SecretKey mockAesKey = new SecretKeySpec(new byte[16], "AES"); + AtomicLong mockCounter = new AtomicLong(12345L); - when(cryptomanagerService.generateArgon2Hash(nullRequest)) - .thenThrow(new CryptoManagerSerivceException("KER-CRY-001", "Input data cannot be null")); + byte[] dummyHash = "dummyHash".getBytes(); + Argon2Advanced argon2AdvancedMock = mock(Argon2Advanced.class); + when(argon2AdvancedMock.rawHash(anyInt(), anyInt(), anyInt(), any(char[].class), any(byte[].class))) + .thenReturn(dummyHash); - cryptomanagerService.generateArgon2Hash(nullRequest); - } + try (MockedStatic argon2Factory = mockStatic(Argon2Factory.class)) { + argon2Factory.when(() -> Argon2Factory.createAdvanced(any())).thenReturn(argon2AdvancedMock); - @Test - public void testGenerateArgon2Hash_Service_EmptyInput() { - Argon2GenerateHashRequestDto emptyRequest = new Argon2GenerateHashRequestDto(); - emptyRequest.setInputData(""); + when(saltGenParamsCache.get(CryptomanagerConstant.CACHE_AES_KEY)).thenReturn(mockAesKey); + when(saltGenParamsCache.get(CryptomanagerConstant.CACHE_INT_COUNTER)).thenReturn(mockCounter); + doNothing().when(cryptomanagerUtil).validateInputData(anyString()); + when(cryptomanagerUtil.isDataValid(any())).thenReturn(false); - when(cryptomanagerService.generateArgon2Hash(emptyRequest)) - .thenThrow(new CryptoManagerSerivceException("KER-CRY-001", "Input data cannot be empty")); + Argon2GenerateHashResponseDto response = cryptomanagerServiceImpl.generateArgon2Hash(request); - try { - cryptomanagerService.generateArgon2Hash(emptyRequest); - fail("Expected exception was not thrown"); - } catch (CryptoManagerSerivceException e) { - assertEquals("KER-CRY-001", e.getErrorCode()); + assertNotNull(response.getHashValue()); + assertNotNull(response.getSalt()); + assertEquals(CryptoUtil.encodeToURLSafeBase64(dummyHash), response.getHashValue()); + verify(cryptomanagerUtil).validateInputData("testPassword"); + verify(saltGenParamsCache).put(eq(CryptomanagerConstant.CACHE_INT_COUNTER), any(AtomicLong.class)); } } - // DTO Tests - 100% Coverage @Test - public void testArgon2RequestDto_SettersGetters() { + public void testGenerateArgon2HashWithProvidedSalt() { + String providedSalt = CryptoUtil.encodeToURLSafeBase64("testSalt".getBytes()); Argon2GenerateHashRequestDto request = new Argon2GenerateHashRequestDto(); - request.setInputData("testInput"); - request.setSalt("testSalt"); + request.setInputData("testPassword"); + request.setSalt(providedSalt); - assertEquals("testInput", request.getInputData()); - assertEquals("testSalt", request.getSalt()); - assertNotNull(request.toString()); - } + byte[] dummyHash = "dummyHash".getBytes(); + Argon2Advanced argon2AdvancedMock = mock(Argon2Advanced.class); + when(argon2AdvancedMock.rawHash(anyInt(), anyInt(), anyInt(), any(char[].class), any(byte[].class))) + .thenReturn(dummyHash); - @Test - public void testArgon2ResponseDto_SettersGetters() { - Argon2GenerateHashResponseDto response = new Argon2GenerateHashResponseDto(); - response.setHashValue("testHash"); - response.setSalt("testSalt"); + try (MockedStatic argon2Factory = mockStatic(Argon2Factory.class)) { + argon2Factory.when(() -> Argon2Factory.createAdvanced(any())).thenReturn(argon2AdvancedMock); - assertEquals("testHash", response.getHashValue()); - assertEquals("testSalt", response.getSalt()); - } + doNothing().when(cryptomanagerUtil).validateInputData(anyString()); + when(cryptomanagerUtil.isDataValid(providedSalt)).thenReturn(true); - @Test - public void testArgon2RequestDto_AllArgsConstructor() { - Argon2GenerateHashRequestDto request = new Argon2GenerateHashRequestDto(testInputData, testSalt); - assertEquals(testInputData, request.getInputData()); - assertEquals(testSalt, request.getSalt()); - } + Argon2GenerateHashResponseDto response = cryptomanagerServiceImpl.generateArgon2Hash(request); - @Test - public void testArgon2ResponseDto_AllArgsConstructor() { - Argon2GenerateHashResponseDto response = new Argon2GenerateHashResponseDto("hashValue", "saltValue"); - assertEquals("hashValue", response.getHashValue()); - assertEquals("saltValue", response.getSalt()); + assertNotNull(response.getHashValue()); + assertEquals(providedSalt, response.getSalt()); + assertEquals(CryptoUtil.encodeToURLSafeBase64(dummyHash), response.getHashValue()); + verify(cryptomanagerUtil).validateInputData("testPassword"); + } } @Test - public void testArgon2RequestDto_NoArgsConstructor() { + public void testGenerateArgon2HashWithSaltGenerationFallback() { Argon2GenerateHashRequestDto request = new Argon2GenerateHashRequestDto(); - assertNull(request.getInputData()); - assertNull(request.getSalt()); - } + request.setInputData("testPassword"); + request.setSalt(null); - @Test - public void testArgon2ResponseDto_NoArgsConstructor() { - Argon2GenerateHashResponseDto response = new Argon2GenerateHashResponseDto(); - assertNull(response.getHashValue()); - assertNull(response.getSalt()); - } + byte[] dummyHash = "dummyHash".getBytes(); + Argon2Advanced argon2AdvancedMock = mock(Argon2Advanced.class); + when(argon2AdvancedMock.rawHash(anyInt(), anyInt(), anyInt(), any(char[].class), any(byte[].class))) + .thenReturn(dummyHash); - @Test - public void testArgon2RequestDto_Equals() { - Argon2GenerateHashRequestDto request1 = new Argon2GenerateHashRequestDto(testInputData, testSalt); - Argon2GenerateHashRequestDto request2 = new Argon2GenerateHashRequestDto(testInputData, testSalt); - - assertEquals(request1, request2); - assertEquals(request1.hashCode(), request2.hashCode()); - } + try (MockedStatic argon2Factory = mockStatic(Argon2Factory.class)) { + argon2Factory.when(() -> Argon2Factory.createAdvanced(any())).thenReturn(argon2AdvancedMock); - @Test - public void testArgon2ResponseDto_Equals() { - Argon2GenerateHashResponseDto response1 = new Argon2GenerateHashResponseDto("hash", "salt"); - Argon2GenerateHashResponseDto response2 = new Argon2GenerateHashResponseDto("hash", "salt"); - - assertEquals(response1, response2); - assertEquals(response1.hashCode(), response2.hashCode()); - } - - // Private Method Tests using Reflection - Service Implementation Coverage - @Test - public void testGetLongBytes_PrivateMethod() throws Exception { - CryptomanagerServiceImpl realService = new CryptomanagerServiceImpl(); - long testValue = 12345L; - - Method getLongBytesMethod = CryptomanagerServiceImpl.class.getDeclaredMethod("getLongBytes", long.class); - getLongBytesMethod.setAccessible(true); - - byte[] result = (byte[]) getLongBytesMethod.invoke(realService, testValue); - - assertNotNull(result); - assertEquals(8, result.length); - } - - @Test - public void testGetSaltBytes_PrivateMethod_WithValidKey() throws Exception { - CryptomanagerServiceImpl realService = new CryptomanagerServiceImpl(); - SecretKey testKey = KeyGenerator.getInstance("AES").generateKey(); - byte[] testBytes = "testData".getBytes(); - - Method getSaltBytesMethod = CryptomanagerServiceImpl.class.getDeclaredMethod("getSaltBytes", byte[].class, SecretKey.class); - getSaltBytesMethod.setAccessible(true); - - byte[] result = (byte[]) getSaltBytesMethod.invoke(realService, testBytes, testKey); - - assertNotNull(result); - assertTrue(result.length > 0); - } - - - - // Real Service Implementation Test - Validation Coverage - @Test(expected = CryptoManagerSerivceException.class) - public void testGenerateArgon2Hash_RealService_ValidationError() throws Exception { - CryptomanagerServiceImpl realService = new CryptomanagerServiceImpl(); - CryptomanagerUtils mockUtil = mock(CryptomanagerUtils.class); - - Field utilField = CryptomanagerServiceImpl.class.getDeclaredField("cryptomanagerUtil"); - utilField.setAccessible(true); - utilField.set(realService, mockUtil); + when(saltGenParamsCache.get(CryptomanagerConstant.CACHE_AES_KEY)).thenReturn(null); + doNothing().when(cryptomanagerUtil).validateInputData(anyString()); + when(cryptomanagerUtil.isDataValid(any())).thenReturn(false); - Argon2GenerateHashRequestDto invalidRequest = new Argon2GenerateHashRequestDto(); - invalidRequest.setInputData(""); + Argon2GenerateHashResponseDto response = cryptomanagerServiceImpl.generateArgon2Hash(request); - doThrow(new CryptoManagerSerivceException("KER-CRY-001", "Invalid input")) - .when(mockUtil).validateInputData(""); - - realService.generateArgon2Hash(invalidRequest); + assertNotNull(response.getHashValue()); + assertNotNull(response.getSalt()); + assertEquals(CryptoUtil.encodeToURLSafeBase64(dummyHash), response.getHashValue()); + verify(cryptomanagerUtil).validateInputData("testPassword"); + } } -} \ No newline at end of file +} diff --git a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/keymanager/hsm/test/health/HSMHealthCheckTest.java b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/keymanager/hsm/test/health/HSMHealthCheckTest.java new file mode 100644 index 00000000..3483dfbe --- /dev/null +++ b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/keymanager/hsm/test/health/HSMHealthCheckTest.java @@ -0,0 +1,193 @@ +package io.mosip.kernel.keymanager.hsm.test.health; + +import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; + +import java.security.Key; +import java.time.LocalDateTime; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import javax.crypto.SecretKey; +import javax.crypto.spec.SecretKeySpec; + +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.springframework.boot.actuate.health.Health; +import org.springframework.boot.actuate.health.Status; +import org.springframework.test.util.ReflectionTestUtils; + +import io.mosip.kernel.core.keymanager.spi.ECKeyStore; +import io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant; +import io.mosip.kernel.keymanagerservice.entity.KeyAlias; +import io.mosip.kernel.keymanagerservice.helper.KeymanagerDBHelper; +import io.mosip.kernel.keymanager.hsm.health.HSMHealthCheck; +import reactor.core.publisher.Mono; + +@RunWith(MockitoJUnitRunner.class) +public class HSMHealthCheckTest { + + @Mock + private KeymanagerDBHelper dbHelper; + + @Mock + private ECKeyStore keyStore; + + @InjectMocks + private HSMHealthCheck hsmHealthCheck; + + @Before + public void setup() { + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckDefaultAppId", "KERNEL"); + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckDefaultRefId", "IDENTITY_CACHE"); + ReflectionTestUtils.setField(hsmHealthCheck, "aesECBTransformation", "AES/ECB/NoPadding"); + ReflectionTestUtils.setField(hsmHealthCheck, "cachedKeyAlias", null); + } + + @Test + public void testHealthUpWhenDisabled() { + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEnabled", false); + Mono healthMono = hsmHealthCheck.health(); + Health health = healthMono.block(); + assertEquals(Status.UP, health.getStatus()); + assertEquals("HEALTH_CHECK_NOT_ENABLED", health.getDetails().get("Info: ")); + } + + @Test + public void testHealthDownWhenNoKeyAliasFound() { + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEnabled", true); + Map> emptyMap = new HashMap<>(); + emptyMap.put(KeymanagerConstant.CURRENTKEYALIAS, Collections.emptyList()); + when(dbHelper.getKeyAliases(any(), any(), any(LocalDateTime.class))).thenReturn(emptyMap); + Mono healthMono = hsmHealthCheck.health(); + Health health = healthMono.block(); + assertEquals(Status.DOWN, health.getStatus()); + assertEquals("NO_UNIQUE_KEY_ALIAS_FOUND", health.getDetails().get("Error: ")); + } + + @Test + public void testHealthDownWhenMultipleKeyAliasesFound() { + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEnabled", true); + Map> keyAliasMap = new HashMap<>(); + List currentKeyAliases = new ArrayList<>(); + currentKeyAliases.add(new KeyAlias()); + currentKeyAliases.add(new KeyAlias()); + keyAliasMap.put(KeymanagerConstant.CURRENTKEYALIAS, currentKeyAliases); + + when(dbHelper.getKeyAliases(any(), any(), any(LocalDateTime.class))).thenReturn(keyAliasMap); + Mono healthMono = hsmHealthCheck.health(); + Health health = healthMono.block(); + assertEquals(Status.DOWN, health.getStatus()); + assertEquals("NO_UNIQUE_KEY_ALIAS_FOUND", health.getDetails().get("Error: ")); + } + + @Test + public void testHealthUpWhenReadKeySuccess() throws Exception { + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEnabled", true); + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEncryptEnabled", false); + + Map> keyAliasMap = new HashMap<>(); + List currentKeyAliases = new ArrayList<>(); + KeyAlias keyAlias = new KeyAlias(); + keyAlias.setAlias("test-alias"); + currentKeyAliases.add(keyAlias); + keyAliasMap.put(KeymanagerConstant.CURRENTKEYALIAS, currentKeyAliases); + + when(dbHelper.getKeyAliases(any(), any(), any(LocalDateTime.class))).thenReturn(keyAliasMap); + Key key = new SecretKeySpec(new byte[16], "AES"); + when(keyStore.getSymmetricKey("test-alias")).thenReturn((SecretKey) key); + + Mono healthMono = hsmHealthCheck.health(); + Health health = healthMono.block(); + assertEquals(Status.UP, health.getStatus()); + assertEquals("READ_KEY_SUCCESS", health.getDetails().get("Info: ")); + } + + @Test + public void testHealthUpWhenEncryptOpsSuccess() throws Exception { + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEnabled", true); + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEncryptEnabled", true); + + Map> keyAliasMap = new HashMap<>(); + List currentKeyAliases = new ArrayList<>(); + KeyAlias keyAlias = new KeyAlias(); + keyAlias.setAlias("test-alias"); + currentKeyAliases.add(keyAlias); + keyAliasMap.put(KeymanagerConstant.CURRENTKEYALIAS, currentKeyAliases); + + when(dbHelper.getKeyAliases(any(), any(), any(LocalDateTime.class))).thenReturn(keyAliasMap); + Key key = new SecretKeySpec(new byte[16], "AES"); + when(keyStore.getSymmetricKey("test-alias")).thenReturn((SecretKey) key); + + Mono healthMono = hsmHealthCheck.health(); + Health health = healthMono.block(); + assertEquals(Status.UP, health.getStatus()); + assertEquals("ENCRYPT_OPS_SUCCESS", health.getDetails().get("Info: ")); + } + + @Test + public void testHealthDownWhenKeyStoreThrowsException() throws Exception { + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEnabled", true); + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEncryptEnabled", false); + + Map> keyAliasMap = new HashMap<>(); + List currentKeyAliases = new ArrayList<>(); + KeyAlias keyAlias = new KeyAlias(); + keyAlias.setAlias("test-alias"); + currentKeyAliases.add(keyAlias); + keyAliasMap.put(KeymanagerConstant.CURRENTKEYALIAS, currentKeyAliases); + + when(dbHelper.getKeyAliases(any(), any(), any(LocalDateTime.class))).thenReturn(keyAliasMap); + when(keyStore.getSymmetricKey("test-alias")).thenThrow(new RuntimeException("Keystore error")); + + Mono healthMono = hsmHealthCheck.health(); + Health health = healthMono.block(); + assertEquals(Status.DOWN, health.getStatus()); + assertEquals("Keystore error", health.getDetails().get("Error: ")); + } + + @Test + public void testHealthDownWhenEncryptionFails() throws Exception { + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEnabled", true); + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEncryptEnabled", true); + + Map> keyAliasMap = new HashMap<>(); + List currentKeyAliases = new ArrayList<>(); + KeyAlias keyAlias = new KeyAlias(); + keyAlias.setAlias("test-alias"); + currentKeyAliases.add(keyAlias); + keyAliasMap.put(KeymanagerConstant.CURRENTKEYALIAS, currentKeyAliases); + + when(dbHelper.getKeyAliases(any(), any(), any(LocalDateTime.class))).thenReturn(keyAliasMap); + // Using a key with a different algorithm to cause an encryption error + Key key = new SecretKeySpec(new byte[16], "DES"); + when(keyStore.getSymmetricKey("test-alias")).thenReturn((SecretKey) key); + + Mono healthMono = hsmHealthCheck.health(); + Health health = healthMono.block(); + assertEquals(Status.UP, health.getStatus()); + } + + @Test + public void testHealthUpWithCachedAlias() throws Exception { + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEnabled", true); + ReflectionTestUtils.setField(hsmHealthCheck, "healthCheckEncryptEnabled", false); + ReflectionTestUtils.setField(hsmHealthCheck, "cachedKeyAlias", "cached-alias"); + + Key key = new SecretKeySpec(new byte[16], "AES"); + when(keyStore.getSymmetricKey("cached-alias")).thenReturn((SecretKey) key); + + Mono healthMono = hsmHealthCheck.health(); + Health health = healthMono.block(); + assertEquals(Status.UP, health.getStatus()); + assertEquals("READ_KEY_SUCCESS", health.getDetails().get("Info: ")); + } +} diff --git a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/keymanagerservice/test/controller/KeymanagerControllerTest.java b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/keymanagerservice/test/controller/KeymanagerControllerTest.java index 9797af73..daae2aeb 100644 --- a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/keymanagerservice/test/controller/KeymanagerControllerTest.java +++ b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/keymanagerservice/test/controller/KeymanagerControllerTest.java @@ -192,9 +192,14 @@ public void testRevokeKeyStatus() throws Exception { keyPairGenRequestDto.setReferenceId(""); keymanagerService.generateMasterKey("CSR", keyPairGenRequestDto); + CSRGenerateRequestDto csrGenerateRequestDto = new CSRGenerateRequestDto(); + csrGenerateRequestDto.setApplicationId("REGISTRATION"); + csrGenerateRequestDto.setReferenceId("test001"); + keymanagerService.generateCSR(csrGenerateRequestDto); + RevokeKeyRequestDto revokeKeyRequestDto = new RevokeKeyRequestDto(); - revokeKeyRequestDto.setApplicationId("PRE_REGISTRATION"); - revokeKeyRequestDto.setReferenceId(""); + revokeKeyRequestDto.setApplicationId("REGISTRATION"); + revokeKeyRequestDto.setReferenceId("test001"); revokeKeyRequestDto.setDisableAutoGen(false); revokeKeyRequest.setRequest(revokeKeyRequestDto); mockMvc.perform(put("/revokeKey") @@ -271,18 +276,6 @@ public void testGetCertificateChain() { } } - @Test - public void testGetCertificateChainStatus() throws Exception { - KeyPairGenerateRequestDto keyPairGenRequestDto = new KeyPairGenerateRequestDto(); - keyPairGenRequestDto.setApplicationId("RESIDENT"); - keyPairGenRequestDto.setReferenceId(""); - keyPairGenRequest.setRequest(keyPairGenRequestDto); - mockMvc.perform(get("/getCertificateChain") - .param("applicationId", "RESIDENT") - .param("referenceId", "")) - .andExpect(status().isOk()); - } - @Test public void testGetCertificateChainWithReferenceId() { KeyPairGenerateRequestDto keyPairGenRequestDto = new KeyPairGenerateRequestDto(); diff --git a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/keymanagerservice/test/util/KeymanagerUtilTest.java b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/keymanagerservice/test/util/KeymanagerUtilTest.java index fa19e302..b8f50857 100644 --- a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/keymanagerservice/test/util/KeymanagerUtilTest.java +++ b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/keymanagerservice/test/util/KeymanagerUtilTest.java @@ -1,9 +1,14 @@ package io.mosip.kernel.keymanagerservice.test.util; import static org.hamcrest.CoreMatchers.isA; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static org.junit.jupiter.api.Assertions.assertThrows; +import java.io.ByteArrayInputStream; import java.io.IOException; +import java.io.InputStream; +import java.io.UnsupportedEncodingException; import java.security.KeyPair; import java.security.KeyPairGenerator; import java.security.NoSuchAlgorithmException; @@ -13,7 +18,10 @@ import java.security.cert.X509Certificate; import java.time.LocalDateTime; +import io.mosip.kernel.core.util.CryptoUtil; +import io.mosip.kernel.keymanager.hsm.constant.KeymanagerErrorCode; import io.mosip.kernel.keymanagerservice.exception.KeymanagerServiceException; +import io.mosip.kernel.signature.util.SignatureUtil; import org.bouncycastle.jce.provider.BouncyCastleProvider; import org.junit.Before; import org.junit.Test; @@ -57,8 +65,10 @@ public class KeymanagerUtilTest { private KeyPair keyPair; private X509Certificate[] chain; + @Autowired + private SignatureUtil signatureUtil; - @Before + @Before public void setupKey() throws NoSuchAlgorithmException { BouncyCastleProvider provider = new BouncyCastleProvider(); Security.addProvider(provider); @@ -337,4 +347,27 @@ public void testGetCSRException() throws NoSuchAlgorithmException { certParams.setCountry("IN"); keymanagerUtil.getCSR(keyPair2.getPrivate(), keyPair.getPublic(), certParams, "RSA"); } + + @Test + public void testPrivateKeyExtractor() throws NoSuchAlgorithmException, UnsupportedEncodingException { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + byte[] keyBytes = keyPair.getPrivate().getEncoded(); + String b64String = CryptoUtil.encodeToURLSafeBase64(keyBytes); + keymanagerUtil.destoryKey(keyPair.getPrivate()); + + InputStream inputStream = new ByteArrayInputStream(b64String.getBytes("UTF-8")); + PrivateKey privateKey = keymanagerUtil.privateKeyExtractor(inputStream); + assertThat(privateKey, isA(PrivateKey.class)); + assertEquals(privateKey.getAlgorithm(), "RSA"); + + b64String = "Invalid Base64 Key Bytes"; + InputStream invalidInputStream = new ByteArrayInputStream(b64String.getBytes()); + KeystoreProcessingException exception = assertThrows(KeystoreProcessingException.class, () -> { + keymanagerUtil.privateKeyExtractor(invalidInputStream); + }); + assertThat(exception, isA(KeystoreProcessingException.class)); + assertEquals(KeymanagerErrorCode.KEYSTORE_PROCESSING_ERROR.getErrorCode(), exception.getErrorCode()); + } } diff --git a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/signature/test/controller/SignatureControllerTest.java b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/signature/test/controller/SignatureControllerTest.java index fe26639a..ade9c0f8 100644 --- a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/signature/test/controller/SignatureControllerTest.java +++ b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/signature/test/controller/SignatureControllerTest.java @@ -183,6 +183,8 @@ public void testCwtVerifyStatusOk() throws Exception { signDto.setApplicationId("ID_REPO"); signDto.setReferenceId(""); signDto.setPayload("eyAibW9kdWxlIjogImtleW1hbmFnZXIiLCAicHVycG9zZSI6ICJ0ZXN0IGNhc2UiIH0"); + signDto.setSubject("Mosip"); + signDto.setIssuer("Keymanager"); CoseSignResponseDto signed = coseSignatureService.cwtSign(signDto); RequestWrapper req = new RequestWrapper<>(); @@ -190,6 +192,8 @@ public void testCwtVerifyStatusOk() throws Exception { verifyDto.setApplicationId("ID_REPO"); verifyDto.setReferenceId(""); verifyDto.setCoseSignedData(signed.getSignedData()); + verifyDto.setIssuer("Keymanager"); + verifyDto.setSubject("Mosip"); req.setRequest(verifyDto); String content = mockMvc.perform(post("/cwtVerify") @@ -270,23 +274,26 @@ public void testPdfSignStatusHandled() throws Exception { key.setReferenceId(""); keymanagerService.generateMasterKey("CSR", key); + String pdfData = "JVBERi0xLjQKMSAwIG9iago8PAovVHlwZSAvQ2F0YWxvZwovUGFnZXMgMiAwIFIKPj4KZW5kb2JqCjIgMCBvYmoKPDwKL1R5cGUgL1BhZ2VzCi9LaWRzIFszIDAgUl0KL0NvdW50IDEKPD4KZW5kb2JqCjMgMCBvYmoKPDwKL1R5cGUgL1BhZ2UKL1BhcmVudCAyIDAgUgovTWVkaWFCb3ggWzAgMCA2MTIgNzkyXQo+PgplbmRvYmoKeHJlZgowIDQKMDAwMDAwMDAwMCA2NTUzNSBmIAowMDAwMDAwMDA5IDAwMDAwIG4gCjAwMDAwMDAwNTggMDAwMDAgbiAKMDAwMDAwMDExNSAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9TaXplIDQKL1Jvb3QgMSAwIFIKPj4Kc3RhcnR4cmVmCjE3NAolJUVPRg=="; RequestWrapper req = new RequestWrapper<>(); PDFSignatureRequestDto dto = new PDFSignatureRequestDto(); dto.setApplicationId("TEST"); dto.setReferenceId(""); - dto.setData("ZHVtbXkgcGRmIGNvbnRlbnQ="); + dto.setData(pdfData); dto.setTimeStamp(io.mosip.kernel.core.util.DateUtils.getUTCCurrentDateTimeString()); dto.setPageNumber(1); - dto.setLowerLeftX(10); - dto.setLowerLeftY(10); - dto.setUpperRightX(100); - dto.setUpperRightY(100); + dto.setLowerLeftX(100); + dto.setLowerLeftY(100); + dto.setUpperRightX(200); + dto.setUpperRightY(150); + dto.setReason("Test"); + dto.setPassword("1234"); req.setRequest(dto); String content = mockMvc.perform(post("/pdf/sign") .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(req))) - .andExpect(status().is2xxSuccessful()) + .andExpect(status().isOk()) .andReturn().getResponse().getContentAsString(); com.fasterxml.jackson.databind.JsonNode root = objectMapper.readTree(content); diff --git a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/signature/test/service/CoseSignatureServiceTest.java b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/signature/test/service/CoseSignatureServiceTest.java index 18ba863c..33be2f01 100644 --- a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/signature/test/service/CoseSignatureServiceTest.java +++ b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/signature/test/service/CoseSignatureServiceTest.java @@ -7,6 +7,7 @@ import io.mosip.kernel.keymanagerservice.repository.KeyAliasRepository; import io.mosip.kernel.keymanagerservice.service.KeymanagerService; import io.mosip.kernel.keymanagerservice.test.KeymanagerTestBootApplication; +import io.mosip.kernel.signature.constant.SignatureErrorCode; import io.mosip.kernel.signature.dto.*; import io.mosip.kernel.signature.exception.RequestException; import io.mosip.kernel.signature.exception.SignatureFailureException; @@ -539,4 +540,46 @@ public void testCoseSign1WithES256KAlgorithm() { Assert.assertNotNull(response); Assert.assertNotNull(response.getSignedData()); } + + @Test + public void testCwtVerifyChecksException() { + KeyPairGenerateRequestDto keyPairGenRequestDto = new KeyPairGenerateRequestDto(); + keyPairGenRequestDto.setApplicationId("ID_REPO"); + keyPairGenRequestDto.setReferenceId("EC_SECP256K1_SIGN"); + keymanagerService.generateECSignKey("CSR", keyPairGenRequestDto); + + CWTSignRequestDto cwtSignRequestDto = new CWTSignRequestDto(); + cwtSignRequestDto.setApplicationId("ID_REPO"); + cwtSignRequestDto.setReferenceId("EC_SECP256K1_SIGN"); + cwtSignRequestDto.setPayload("eyAibW9kdWxlIjogImtleW1hbmFnZXIiLCAicHVycG9zZSI6ICJ0ZXN0IGNhc2UiIH0"); + cwtSignRequestDto.setIssuer("keymgr"); + cwtSignRequestDto.setSubject("signature"); + CoseSignResponseDto signResponse = coseSignatureService.cwtSign(cwtSignRequestDto); + + CWTVerifyRequestDto cwtVerifyRequestDto = new CWTVerifyRequestDto(); + cwtVerifyRequestDto.setApplicationId("ID_REPO"); + cwtVerifyRequestDto.setReferenceId("EC_SECP256K1_SIGN"); + cwtVerifyRequestDto.setCoseSignedData(signResponse.getSignedData()); + RequestException exception = assertThrows(RequestException.class, () -> { + coseSignatureService.cwtVerify(cwtVerifyRequestDto); + }); + Assert.assertEquals(SignatureErrorCode.CLAIM_NOT_MATCHED.getErrorCode(), exception.getErrorCode()); + + cwtSignRequestDto.setSubject(null); + signResponse = coseSignatureService.cwtSign(cwtSignRequestDto); + cwtVerifyRequestDto.setCoseSignedData(signResponse.getSignedData()); + cwtVerifyRequestDto.setIssuer("keymgr"); + exception = assertThrows(RequestException.class, () -> { + coseSignatureService.cwtVerify(cwtVerifyRequestDto); + }); + Assert.assertEquals(SignatureErrorCode.CLAIM_NOT_FOUND.getErrorCode(), exception.getErrorCode()); + + cwtSignRequestDto.setSubject("sign"); + signResponse = coseSignatureService.cwtSign(cwtSignRequestDto); + cwtVerifyRequestDto.setCoseSignedData(signResponse.getSignedData()); + exception = assertThrows(RequestException.class, () -> { + coseSignatureService.cwtVerify(cwtVerifyRequestDto); + }); + Assert.assertEquals(SignatureErrorCode.CLAIM_NOT_MATCHED.getErrorCode(), exception.getErrorCode()); + } } \ No newline at end of file diff --git a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/signature/test/service/SignatureServiceTest.java b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/signature/test/service/SignatureServiceTest.java index 48b8b45a..a52567da 100644 --- a/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/signature/test/service/SignatureServiceTest.java +++ b/kernel/kernel-keymanager-service/src/test/java/io/mosip/kernel/signature/test/service/SignatureServiceTest.java @@ -9,8 +9,11 @@ import io.mosip.kernel.keymanagerservice.repository.KeyAliasRepository; import io.mosip.kernel.keymanagerservice.service.KeymanagerService; import io.mosip.kernel.keymanagerservice.test.KeymanagerTestBootApplication; +import io.mosip.kernel.signature.constant.SignatureProviderEnum; import io.mosip.kernel.signature.dto.*; import io.mosip.kernel.signature.exception.RequestException; +import io.mosip.kernel.signature.exception.SignatureFailureException; +import io.mosip.kernel.signature.service.SignatureProvider; import io.mosip.kernel.signature.service.SignatureService; import io.mosip.kernel.signature.service.SignatureServicev2; import org.junit.After; @@ -22,6 +25,9 @@ import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; +import java.security.KeyPair; +import java.security.KeyPairGenerator; +import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; @@ -546,4 +552,118 @@ public void testValidateException() { timestampRequestDto.setTimestamp(DateUtils.getUTCCurrentDateTime()); signatureService.validate(timestampRequestDto); } + + @Test(expected = SignatureFailureException.class) + public void testPS256Exception() { + SignatureProvider signatureProvider = SignatureProviderEnum.getSignatureProvider("PS256"); + signatureProvider.sign(null, null, "Invalid Provider"); + } + + @Test(expected = SignatureFailureException.class) + public void testRS256Exception() { + SignatureProvider signatureProvider = SignatureProviderEnum.getSignatureProvider("RS256"); + signatureProvider.sign(null, null, "Invalid Provider"); + } + + @Test(expected = SignatureFailureException.class) + public void testEC256Exception() { + SignatureProvider signatureProvider = SignatureProviderEnum.getSignatureProvider("ES256"); + signatureProvider.sign(null, null, "Invalid Provider"); + } + + @Test(expected = SignatureFailureException.class) + public void testEd25519Exception() throws NoSuchAlgorithmException { + KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA"); + keyPairGenerator.initialize(2048); + KeyPair keyPair = keyPairGenerator.generateKeyPair(); + + SignatureProvider signatureProvider = SignatureProviderEnum.getSignatureProvider("EdDSA"); + signatureProvider.sign(keyPair.getPrivate(), null, "Invalid Provider"); + } + + @Test + public void testValidateTrustV2() { + KeyPairGenerateRequestDto keyPairGenRequestDto = new KeyPairGenerateRequestDto(); + keyPairGenRequestDto.setApplicationId("TEST"); + keyPairGenRequestDto.setReferenceId(""); + keymanagerService.generateMasterKey("CSR", keyPairGenRequestDto); + + JWTSignatureVerifyRequestDto jwtVerifyRequestDto = new JWTSignatureVerifyRequestDto(); + jwtVerifyRequestDto.setValidateTrust(false); + + String trustResult = signatureService.validateTrustV2(jwtVerifyRequestDto, null, null); + Assert.assertEquals("TRUST_NOT_VERIFIED", trustResult); + } + + @Test + public void testJwtVerifyV2() { + KeyPairGenerateRequestDto keyPairGenRequestDto = new KeyPairGenerateRequestDto(); + keyPairGenRequestDto.setApplicationId("TEST"); + keyPairGenRequestDto.setReferenceId(""); + keymanagerService.generateMasterKey("CSR", keyPairGenRequestDto); + + // First sign + JWTSignatureRequestDtoV2 jwtSignRequestDtoV2 = new JWTSignatureRequestDtoV2(); + jwtSignRequestDtoV2.setApplicationId("TEST"); + jwtSignRequestDtoV2.setReferenceId(""); + jwtSignRequestDtoV2.setDataToSign(CryptoUtil.encodeToURLSafeBase64("{\"test\":\"data\"}".getBytes())); + jwtSignRequestDtoV2.setIncludePayload(true); + jwtSignRequestDtoV2.setIncludeCertificateChain(true); + jwtSignRequestDtoV2.setIncludeCertHash(true); + jwtSignRequestDtoV2.setCertificateUrl("https://test.com/cert"); + JWTSignatureResponseDto signResponse = signatureService.jwtSignV2(jwtSignRequestDtoV2); + + // Then verify + JWTSignatureVerifyRequestDto verifyRequestDto = new JWTSignatureVerifyRequestDto(); + verifyRequestDto.setApplicationId("TEST"); + verifyRequestDto.setReferenceId(""); + verifyRequestDto.setJwtSignatureData(signResponse.getJwtSignedData()); + JWTSignatureVerifyResponseDto verifyResponse = signatureService.jwtVerifyV2(verifyRequestDto); + + Assert.assertNotNull(verifyResponse); + Assert.assertTrue(verifyResponse.isSignatureValid()); + Assert.assertEquals("Validation Successful", verifyResponse.getMessage()); + } + + @Test + public void testJwsSignV2() { + KeyPairGenerateRequestDto keyPairGenRequestDto = new KeyPairGenerateRequestDto(); + keyPairGenRequestDto.setApplicationId("TEST"); + keyPairGenRequestDto.setReferenceId(""); + keymanagerService.generateMasterKey("CSR", keyPairGenRequestDto); + + keyPairGenRequestDto.setApplicationId("KERNEL"); + keyPairGenRequestDto.setReferenceId("SIGN"); + keymanagerService.generateMasterKey("CSR", keyPairGenRequestDto); + + Map addtionalHeader = new HashMap<>(); + addtionalHeader.put("test", "header"); + addtionalHeader.put("test2", "header2"); + addtionalHeader.put("iss", "test"); + addtionalHeader.put("aud", "test"); + addtionalHeader.put("sub", "test"); + + JWSSignatureRequestDtoV2 jwsSignRequestDtoV2 = new JWSSignatureRequestDtoV2(); + jwsSignRequestDtoV2.setApplicationId("TEST"); + jwsSignRequestDtoV2.setReferenceId(""); + jwsSignRequestDtoV2.setDataToSign(CryptoUtil.encodeToURLSafeBase64("{\"test\":\"data\"}".getBytes())); + jwsSignRequestDtoV2.setIncludePayload(true); + jwsSignRequestDtoV2.setIncludeCertificateChain(true); + jwsSignRequestDtoV2.setB64JWSHeaderParam(false); + jwsSignRequestDtoV2.setValidateJson(true); + jwsSignRequestDtoV2.setAdditionalHeaders(addtionalHeader); + + JWTSignatureResponseDto response = signatureService.jwsSignV2(jwsSignRequestDtoV2); + Assert.assertNotNull(response); + Assert.assertNotNull(response.getJwtSignedData()); + + jwsSignRequestDtoV2.setApplicationId("KERNEL"); + jwsSignRequestDtoV2.setReferenceId("SIGN"); + jwsSignRequestDtoV2.setIncludePayload(false); + jwsSignRequestDtoV2.setIncludeCertificateChain(false); + jwsSignRequestDtoV2.setB64JWSHeaderParam(true); + jwsSignRequestDtoV2.setCertificateUrl("https:://test/certificate.com"); + response = signatureService.jwsSignV2(jwsSignRequestDtoV2); + Assert.assertNotNull(response); + } } \ No newline at end of file