diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerConstant.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerConstant.java index b5ef146e..74a60e57 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerConstant.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerConstant.java @@ -63,6 +63,17 @@ private CryptomanagerConstant() { public static final String CACHE_AES_KEY = "cacheAESKey"; public static final String CACHE_INT_COUNTER = "cacheIntCounter"; - + + public static final byte[] VERSION_EC256_R1 = "VER_E2".getBytes(); // secp256R1 curve header + + public static final byte[] VERSION_EC256_K1 = "VER_K2".getBytes(); // secp256K1 curve header + + public static final byte[] VERSION_EC_X25519 = "VER_X2".getBytes(); // X25519 curve header + + public static final String EC_SECP256R1 = "SECP256R1"; + + public static final String EC_SECP256K1 = "SECP256K1"; + + public static final String EC_X25519 = "X25519"; } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerErrorCode.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerErrorCode.java index 094a0d69..baa606a1 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerErrorCode.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/constant/CryptomanagerErrorCode.java @@ -67,6 +67,8 @@ public enum CryptomanagerErrorCode { JWE_DECRYPTION_INTERNAL_ERROR("KER-CRY-015", "Internal Error while decrypting data using JWE."), + UNSUPPORTED_EC_CURVE("KER-CRY-016", "Unsupported EC Curve Provided. Please check the curve name."), + INTERNAL_SERVER_ERROR("KER-CRY-500", "Internal server error"); diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/EcCryptomanagerService.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/EcCryptomanagerService.java new file mode 100644 index 00000000..00b256c2 --- /dev/null +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/EcCryptomanagerService.java @@ -0,0 +1,42 @@ +package io.mosip.kernel.cryptomanager.service; + +import java.security.PrivateKey; +import java.security.PublicKey; + +public interface EcCryptomanagerService { + + /** + * + * Encrypts data using an asymmetric EC public key. + * + * @param publicKey the public key to use for encryption + * @param data the data to encrypt + * @param iv the initialization vector (IV) for encryption + * @param aad additional authenticated data (AAD) + * @return the encrypted data + */ + public byte[] asymmetricEcEncrypt(PublicKey publicKey, byte[] data, byte[] iv, byte[] aad, String algorithmName); + + /** + * + * Encrypts data using an asymmetric EC public key with a specified curve name. + * + * @param publicKey the public key to use for encryption + * @param data the data to encrypt + * @param curveName the name of the elliptic curve used + * @return the encrypted data + */ + public byte[] asymmetricEcEncrypt(PublicKey publicKey, byte[] data, String curveName); + + /** + * + * Decrypts data using an asymmetric EC private key. + * + * @param privateKey the private key to use for decryption + * @param data the data to decrypt + * @param aad additional authenticated data (AAD) + * @param curveName the name of the elliptic curve used + * @return the decrypted data + */ + public byte[] asymmetricEcDecrypt(PrivateKey privateKey, byte[] data, byte[] aad, String curveName); +} \ No newline at end of file diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/CryptomanagerServiceImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/CryptomanagerServiceImpl.java index 713df76a..ae1a5559 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/CryptomanagerServiceImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/CryptomanagerServiceImpl.java @@ -16,9 +16,12 @@ import java.security.cert.X509Certificate; import java.util.Arrays; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import io.mosip.kernel.cryptomanager.service.EcCryptomanagerService; +import io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant; import jakarta.annotation.PostConstruct; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -118,6 +121,9 @@ public class CryptomanagerServiceImpl implements CryptomanagerService { @Value("${mosip.keymanager.argon2.hash.generate.parallelism:2}") private int argon2Parallelism; + @Value("${mosip.kernel.keygenerator.ecc-curve-name:SECP256R1}") + private String ecCurveName; + private static SecureRandom secureRandom = null; /** @@ -144,6 +150,9 @@ public class CryptomanagerServiceImpl implements CryptomanagerService { @Autowired KeymanagerUtil keymanagerUtil; + @Autowired + EcCryptomanagerService ecCryptomanagerService; + private Cache saltGenParamsCache = null; @PostConstruct @@ -186,56 +195,83 @@ public void init() { * kernel.cryptography.dto.CryptographyRequestDto) */ @Override - public CryptomanagerResponseDto encrypt(CryptomanagerRequestDto cryptoRequestDto) { - LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, - "Request for data encryption."); - - cryptomanagerUtil.validateKeyIdentifierIds(cryptoRequestDto.getApplicationId(), cryptoRequestDto.getReferenceId()); - SecretKey secretKey = keyGenerator.getSymmetricKey(); - final byte[] encryptedData; - byte[] headerBytes = new byte[0]; - if (cryptomanagerUtil.isValidSalt(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt()))) { - encryptedData = cryptoCore.symmetricEncrypt(secretKey, cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()), - cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt())), - cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad()))); - } else { - byte[] aad = cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad())); - if (aad == null || aad.length == 0){ - encryptedData = generateAadAndEncryptData(secretKey, cryptoRequestDto.getData()); - headerBytes = CryptomanagerConstant.VERSION_RSA_2048; - } else { - encryptedData = cryptoCore.symmetricEncrypt(secretKey, cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()), - aad); - } - } - - Certificate certificate = cryptomanagerUtil.getCertificate(cryptoRequestDto); - LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, - "Found the cerificate, proceeding with session key encryption."); - PublicKey publicKey = certificate.getPublicKey(); - final byte[] encryptedSymmetricKey = cryptoCore.asymmetricEncrypt(publicKey, secretKey.getEncoded()); - LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, - "Session key encryption completed."); - //boolean prependThumbprint = cryptoRequestDto.getPrependThumbprint() == null ? false : cryptoRequestDto.getPrependThumbprint(); - CryptomanagerResponseDto cryptoResponseDto = new CryptomanagerResponseDto(); - // support of 1.1.3 no thumbprint is configured as true & encryption request with no thumbprint - // request thumbprint flag will not be considered if support no thumbprint is set to false. - //------------------- - // no thumbprint flag will not be required to consider at the time of encryption. So commented the below code. - // from 1.2.0.1 version, support of no thumbprint flag will be removed in case of data encryption. + public CryptomanagerResponseDto encrypt(CryptomanagerRequestDto cryptoRequestDto) { + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, + "Request for data encryption."); + + cryptomanagerUtil.validateKeyIdentifierIds(cryptoRequestDto.getApplicationId(), cryptoRequestDto.getReferenceId()); + + Certificate certificate = cryptomanagerUtil.getCertificate(cryptoRequestDto); + PublicKey publicKey = certificate.getPublicKey(); + byte[] certThumbprint = cryptomanagerUtil.getCertificateThumbprint(certificate); + + CryptomanagerResponseDto cryptoResponseDto = new CryptomanagerResponseDto(); + + if (publicKey.getAlgorithm().equalsIgnoreCase(io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant.RSA)) { + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant.RSA, + "Encrypting the Data Using RSA key."); + SecretKey secretKey = keyGenerator.getSymmetricKey(); + final byte[] encryptedData; + byte[] headerBytes = new byte[0]; + if (cryptomanagerUtil.isValidSalt(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt()))) { + encryptedData = cryptoCore.symmetricEncrypt(secretKey, cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()), + cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt())), + cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad()))); + } else { + byte[] aad = cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad())); + if (aad == null || aad.length == 0){ + encryptedData = generateAadAndEncryptData(secretKey, cryptoRequestDto.getData()); + headerBytes = CryptomanagerConstant.VERSION_RSA_2048; + } else { + encryptedData = cryptoCore.symmetricEncrypt(secretKey, cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()), + aad); + } + } + + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, + "Found the cerificate, proceeding with session key encryption."); + final byte[] encryptedSymmetricKey = cryptoCore.asymmetricEncrypt(publicKey, secretKey.getEncoded()); + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, + "Session key encryption completed."); + //boolean prependThumbprint = cryptoRequestDto.getPrependThumbprint() == null ? false : cryptoRequestDto.getPrependThumbprint(); + // support of 1.1.3 no thumbprint is configured as true & encryption request with no thumbprint + // request thumbprint flag will not be considered if support no thumbprint is set to false. + //------------------- + // no thumbprint flag will not be required to consider at the time of encryption. So commented the below code. + // from 1.2.0.1 version, support of no thumbprint flag will be removed in case of data encryption. /* if (noThumbprint && !prependThumbprint) { byte[] finalEncKeyBytes = cryptomanagerUtil.concatByteArrays(headerBytes, encryptedSymmetricKey); cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(CryptoUtil.combineByteArray(encryptedData, finalEncKeyBytes, keySplitter))); return cryptoResponseDto; - } */ - //--------------------- - byte[] certThumbprint = cryptomanagerUtil.getCertificateThumbprint(certificate); - byte[] concatedData = cryptomanagerUtil.concatCertThumbprint(certThumbprint, encryptedSymmetricKey); - byte[] finalEncKeyBytes = cryptomanagerUtil.concatByteArrays(headerBytes, concatedData); - cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(CryptoUtil.combineByteArray(encryptedData, - finalEncKeyBytes, keySplitter))); - return cryptoResponseDto; - } + } */ + //--------------------- + byte[] concatedData = cryptomanagerUtil.concatCertThumbprint(certThumbprint, encryptedSymmetricKey); + byte[] finalEncKeyBytes = cryptomanagerUtil.concatByteArrays(headerBytes, concatedData); + cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(CryptoUtil.combineByteArray(encryptedData, + finalEncKeyBytes, keySplitter))); + } else { + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, KeymanagerConstant.EC_KEY_TYPE, + "Encrypting the Data Using ECC key."); + + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, + "Found the cerificate, proceeding with ecc key encryption."); + + byte[] aad = cryptomanagerUtil.generateRandomBytes(CryptomanagerConstant.GCM_AAD_LENGTH); + String algName = ecCurveName.equals(KeymanagerConstant.ED25519_KEY_TYPE) ? KeymanagerConstant.X25519_KEY_TYPE : ecCurveName; + byte[] encryptedData = ecCryptomanagerService.asymmetricEcEncrypt(publicKey, cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()), null, aad, algName); + byte[] encryptedDataWithIv = cryptomanagerUtil.concatByteArrays(aad, encryptedData); + + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, + "ECC key encryption completed."); + + byte[] headerBytes = cryptomanagerUtil.getHeaderByte(algName); + + byte[] concatedData = cryptomanagerUtil.concatCertThumbprint(certThumbprint, encryptedDataWithIv); + byte[] finalEncKeyBytes = CryptoUtil.combineByteArray(concatedData, headerBytes, keySplitter); + cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(finalEncKeyBytes)); + } + return cryptoResponseDto; + } private byte[] generateAadAndEncryptData(SecretKey secretKey, String data){ LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, @@ -255,48 +291,72 @@ private byte[] generateAadAndEncryptData(SecretKey secretKey, String data){ * kernel.cryptography.dto.CryptographyRequestDto) */ @Override - public CryptomanagerResponseDto decrypt(CryptomanagerRequestDto cryptoRequestDto) { - LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, - "Request for data decryption."); - - boolean hasAcccess = cryptomanagerUtil.hasKeyAccess(cryptoRequestDto.getApplicationId()); - if (!hasAcccess) { - LOGGER.error(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, - "Data Decryption is not allowed for the authenticated user for the provided application id."); - throw new CryptoManagerSerivceException(CryptomanagerErrorCode.DECRYPT_NOT_ALLOWED_ERROR.getErrorCode(), - CryptomanagerErrorCode.DECRYPT_NOT_ALLOWED_ERROR.getErrorMessage()); - } - int keyDemiliterIndex = 0; - byte[] encryptedHybridData = cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()); - keyDemiliterIndex = CryptoUtil.getSplitterIndex(encryptedHybridData, keyDemiliterIndex, keySplitter); - byte[] encryptedKey = copyOfRange(encryptedHybridData, 0, keyDemiliterIndex); - byte[] encryptedData = copyOfRange(encryptedHybridData, keyDemiliterIndex + keySplitter.length(), - encryptedHybridData.length); - - byte[] headerBytes = cryptomanagerUtil.parseEncryptKeyHeader(encryptedKey); - cryptoRequestDto.setData(CryptoUtil.encodeToURLSafeBase64(copyOfRange(encryptedKey, headerBytes.length, encryptedKey.length))); - SecretKey decryptedSymmetricKey = cryptomanagerUtil.getDecryptedSymmetricKey(cryptoRequestDto); - LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, - "Session Key Decryption completed."); - final byte[] decryptedData; - if (cryptomanagerUtil.isValidSalt(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt()))) { - decryptedData = cryptoCore.symmetricDecrypt(decryptedSymmetricKey, encryptedData, - cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt())), - cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad()))); - } else { - if (Arrays.equals(headerBytes, CryptomanagerConstant.VERSION_RSA_2048)) { - decryptedData = splitAadAndDecryptData(decryptedSymmetricKey, encryptedData); - } else { - decryptedData = cryptoCore.symmetricDecrypt(decryptedSymmetricKey, encryptedData, - cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad()))); - } - } - LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, - "Data decryption completed."); - CryptomanagerResponseDto cryptoResponseDto = new CryptomanagerResponseDto(); - cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(decryptedData)); - return cryptoResponseDto; - } + public CryptomanagerResponseDto decrypt(CryptomanagerRequestDto cryptoRequestDto) { + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, + "Request for data decryption."); + + boolean hasAcccess = cryptomanagerUtil.hasKeyAccess(cryptoRequestDto.getApplicationId()); + if (!hasAcccess) { + LOGGER.error(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, + "Data Decryption is not allowed for the authenticated user for the provided application id."); + throw new CryptoManagerSerivceException(CryptomanagerErrorCode.DECRYPT_NOT_ALLOWED_ERROR.getErrorCode(), + CryptomanagerErrorCode.DECRYPT_NOT_ALLOWED_ERROR.getErrorMessage()); + } + int keyDemiliterIndex = 0; + byte[] encryptedHybridData = cryptomanagerUtil.decodeBase64Data(cryptoRequestDto.getData()); + keyDemiliterIndex = CryptoUtil.getSplitterIndex(encryptedHybridData, keyDemiliterIndex, keySplitter); + String algorithmName = cryptomanagerUtil.getAlgorithmNameFromHeader(encryptedHybridData); + CryptomanagerResponseDto cryptoResponseDto = new CryptomanagerResponseDto(); + + if (algorithmName.equalsIgnoreCase(io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant.RSA)) { + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, KeymanagerConstant.RSA, + "Decrytping the data with RSA Key."); + + byte[] encryptedKey = copyOfRange(encryptedHybridData, 0, keyDemiliterIndex); + byte[] encryptedData = copyOfRange(encryptedHybridData, keyDemiliterIndex + keySplitter.length(), + encryptedHybridData.length); + + byte[] headerBytes = cryptomanagerUtil.parseEncryptKeyHeader(encryptedKey); + cryptoRequestDto.setData(CryptoUtil.encodeToURLSafeBase64(copyOfRange(encryptedKey, headerBytes.length, encryptedKey.length))); + SecretKey decryptedSymmetricKey = cryptomanagerUtil.getDecryptedSymmetricKey(cryptoRequestDto); + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, + "Session Key Decryption completed."); + final byte[] decryptedData; + if (cryptomanagerUtil.isValidSalt(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt()))) { + decryptedData = cryptoCore.symmetricDecrypt(decryptedSymmetricKey, encryptedData, + cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getSalt())), + cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad()))); + } else { + if (Arrays.equals(headerBytes, CryptomanagerConstant.VERSION_RSA_2048)) { + decryptedData = splitAadAndDecryptData(decryptedSymmetricKey, encryptedData); + } else { + decryptedData = cryptoCore.symmetricDecrypt(decryptedSymmetricKey, encryptedData, + cryptomanagerUtil.decodeBase64Data(CryptomanagerUtils.nullOrTrim(cryptoRequestDto.getAad()))); + } + } + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, CryptomanagerConstant.DECRYPT, + "Data decryption completed."); + cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(decryptedData)); + } else { + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.DECRYPT, KeymanagerConstant.EC_KEY_TYPE, + "Decrytping the data with EC Key."); + String ecCurveName = algorithmName; + byte[] thumbprint = copyOfRange(encryptedHybridData, keyDemiliterIndex + keySplitter.length(), keyDemiliterIndex + keySplitter.length() + CryptomanagerConstant.THUMBPRINT_LENGTH); + byte[] encryptedDataWithIv = copyOfRange(encryptedHybridData, keyDemiliterIndex + keySplitter.length() + CryptomanagerConstant.THUMBPRINT_LENGTH, + encryptedHybridData.length); + + String certThumbprintHex = Hex.toHexString(thumbprint).toUpperCase(); + PrivateKey privateKey = (PrivateKey) cryptomanagerUtil.getEncryptedPrivateKey(cryptoRequestDto.getApplicationId(), + Optional.ofNullable(cryptoRequestDto.getReferenceId()), certThumbprintHex)[0]; + + byte[] aad = Arrays.copyOfRange(encryptedDataWithIv, 0, CryptomanagerConstant.GCM_AAD_LENGTH); + byte[] encryptedData = Arrays.copyOfRange(encryptedDataWithIv, CryptomanagerConstant.GCM_AAD_LENGTH,encryptedDataWithIv.length); + + byte[] decryptedData = ecCryptomanagerService.asymmetricEcDecrypt(privateKey, encryptedData, aad, ecCurveName); + cryptoResponseDto.setData(CryptoUtil.encodeToURLSafeBase64(decryptedData)); + } + return cryptoResponseDto; + } private byte[] splitAadAndDecryptData(SecretKey symmetricKey, byte[] encryptedData) { @@ -445,13 +505,20 @@ private String jwtRsaOaep256AesGcmEncrypt(String dataToEncrypt, Certificate cert LOGGER.info(CryptomanagerConstant.SESSIONID, this.getClass().getSimpleName(), CryptomanagerConstant.JWT_ENCRYPT, "JWE Encryption Started."); + + String algName = certificate.getPublicKey().getAlgorithm(); JsonWebEncryption jsonWebEncrypt = new JsonWebEncryption(); jsonWebEncrypt.setHeader(CryptomanagerConstant.JSON_CONTENT_TYPE_KEY, CryptomanagerConstant.JSON_CONTENT_TYPE_VALUE); jsonWebEncrypt.setHeader(CryptomanagerConstant.JSON_HEADER_TYPE_KEY, CryptomanagerConstant.JSON_CONTENT_TYPE_VALUE); - jsonWebEncrypt.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.RSA_OAEP_256); - jsonWebEncrypt.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_256_GCM); + + if (algName.equalsIgnoreCase(KeymanagerConstant.RSA)) + jsonWebEncrypt.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.RSA_OAEP_256); + else + jsonWebEncrypt.setAlgorithmHeaderValue(KeyManagementAlgorithmIdentifiers.ECDH_ES_A256KW); + + jsonWebEncrypt.setEncryptionMethodHeaderParameter(ContentEncryptionAlgorithmIdentifiers.AES_256_GCM); jsonWebEncrypt.setKey(certificate.getPublicKey()); String certThumbprint = CryptoUtil.encodeToURLSafeBase64(cryptomanagerUtil.getCertificateThumbprint(certificate)); jsonWebEncrypt.setKeyIdHeaderValue(certThumbprint); diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptomanagerServiceImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptomanagerServiceImpl.java new file mode 100644 index 00000000..449aba80 --- /dev/null +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/service/impl/EcCryptomanagerServiceImpl.java @@ -0,0 +1,319 @@ +package io.mosip.kernel.cryptomanager.service.impl; + +import io.mosip.kernel.core.exception.NoSuchAlgorithmException; +import io.mosip.kernel.core.logger.spi.Logger; +import io.mosip.kernel.core.util.CryptoUtil; +import io.mosip.kernel.crypto.jce.constant.SecurityExceptionCodeConstant; +import io.mosip.kernel.crypto.jce.util.CryptoUtils; +import io.mosip.kernel.cryptomanager.constant.CryptomanagerConstant; +import io.mosip.kernel.cryptomanager.service.EcCryptomanagerService; +import io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant; +import io.mosip.kernel.keymanagerservice.logger.KeymanagerLogger; +import io.mosip.kernel.core.crypto.exception.InvalidKeyException; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; + +import javax.crypto.*; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.security.*; +import java.security.spec.ECGenParameterSpec; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.NamedParameterSpec; +import java.security.spec.X509EncodedKeySpec; +import java.util.Arrays; +import java.util.Objects; + +@Service +public class EcCryptomanagerServiceImpl implements EcCryptomanagerService { + + private static final String AES = "AES"; + + @Value("${mosip.kernel.data-key-splitter}") + private String keySplitter; + + @Value("${mosip.kernel.crypto.gcm-tag-length:128}") + private int tagLength; + + @Value("${mosip.kernel.crypto.symmetric-algorithm-name:AES/GCM/NoPadding}") + private String symmetricAlgorithmName; + + private static final Logger LOGGER = KeymanagerLogger.getLogger(EcCryptomanagerServiceImpl.class); + + private static final String reason = "CryptoManager"; + + private static final int AES_KEY_LENGTH = 32; // AES-256 + + private static final String HMAC_SHA_256 = "HmacSHA256"; + + private static final String EC_ALGORITHM = "EC"; + + private static final String ECDH = "ECDH"; + + private static final String BC_PROVIDER = "BC"; + + + @Override + public byte[] asymmetricEcEncrypt(PublicKey key, byte[] data, String curveName) { + Objects.requireNonNull(key, SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorMessage()); + CryptoUtils.verifyData(data); + return asymmetricEcEncrypt(key, data, null, null, curveName); + } + + @Override + public byte[] asymmetricEcEncrypt(PublicKey key, byte[] data, byte[] randomIV, byte[] aad, String curveName) { + byte[] output; + Cipher cipher; + SecretKey aesKey = null; + byte[] ephemeralPublicKey = null; + KeyPair ephemeralKeyPair = null; + + try { + ephemeralKeyPair = generateAlgorithmBasedEphemeralKeyPair(curveName); + KeyAgreement keyAgreement = getKeyAgreementAlorithmBased(key, ephemeralKeyPair.getPrivate(), curveName); + byte[] sharedSecret = keyAgreement.generateSecret(); + + if (randomIV == null || randomIV.length == 0) { + randomIV = generateIV(CryptomanagerConstant.GCM_NONCE_LENGTH); // Default IV length for AES + } + + byte[] aesKeyBytes = getHkdfKeyBytes(sharedSecret, randomIV, reason.getBytes(), AES_KEY_LENGTH); + aesKey = new SecretKeySpec(aesKeyBytes, 0, AES_KEY_LENGTH, AES); + + GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(tagLength, randomIV); + cipher = Cipher.getInstance(symmetricAlgorithmName); + cipher.init(Cipher.ENCRYPT_MODE, aesKey, gcmParameterSpec); + if (aad != null && aad.length != 0) { + cipher.updateAAD(aad); + } + + byte[] encryptedData = cipher.doFinal(data); + + byte[] encryptedDataWithIv = new byte[encryptedData.length + randomIV.length]; + ephemeralPublicKey = ephemeralKeyPair.getPublic().getEncoded(); + + System.arraycopy(encryptedData, 0, encryptedDataWithIv, 0, encryptedData.length); + System.arraycopy(randomIV, 0, encryptedDataWithIv, encryptedData.length, randomIV.length); + + byte[] keySplitterBytes = keySplitter.getBytes(); + output = new byte[encryptedDataWithIv.length + keySplitterBytes.length + ephemeralPublicKey.length]; + + System.arraycopy(encryptedDataWithIv, 0, output, 0, encryptedDataWithIv.length); + System.arraycopy(keySplitterBytes, 0, output, encryptedDataWithIv.length, keySplitterBytes.length); + System.arraycopy(ephemeralPublicKey, 0, output, encryptedDataWithIv.length + keySplitterBytes.length, ephemeralPublicKey.length); + + } catch (java.security.NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException e) { + throw new NoSuchAlgorithmException( + SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(), + SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage(), e); + } catch (java.security.InvalidKeyException | IllegalBlockSizeException e) { + throw new InvalidKeyException( + SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorCode(), + SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorMessage(), e); + } catch (InvalidAlgorithmParameterException e) { + throw new InvalidKeyException( + SecurityExceptionCodeConstant.MOSIP_INVALID_PARAM_SPEC_EXCEPTION.getErrorCode(), + SecurityExceptionCodeConstant.MOSIP_INVALID_PARAM_SPEC_EXCEPTION.getErrorMessage(), e); + } finally { + if (aesKey != null) { + destroyKey(aesKey.getEncoded()); + } + if (ephemeralPublicKey != null) { + destroyKey(ephemeralPublicKey); + } + if (ephemeralKeyPair != null) { + destroyKey(ephemeralKeyPair.getPrivate().getEncoded()); + } + if (ephemeralKeyPair.getPrivate() != null) destroyKey(ephemeralKeyPair.getPublic().getEncoded()); + } + return output; + } + + @Override + public byte[] asymmetricEcDecrypt(PrivateKey privateKey, byte[] data, byte[] aad, String algorithmName) { + Objects.requireNonNull(privateKey, SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorMessage()); + CryptoUtils.verifyData(data); + byte[] decryptedData = null; + + try { + byte[] keySplitterBytes = keySplitter.getBytes(); + + int splitterIndex = 0; + splitterIndex = CryptoUtil.getSplitterIndex(data, splitterIndex, keySplitter); + + // Extract encrypted data and ephemeral public key bytes + byte[] encryptedData = Arrays.copyOfRange(data, 0, splitterIndex); + byte[] ephemeralPublicKeyBytes = Arrays.copyOfRange(data, splitterIndex + keySplitterBytes.length, data.length); + + // Extract IV from the end of encryptedData + int ivLength = CryptomanagerConstant.GCM_NONCE_LENGTH; + byte[] iv = Arrays.copyOfRange(encryptedData, encryptedData.length - ivLength, encryptedData.length); + byte[] cipherText = Arrays.copyOfRange(encryptedData, 0, encryptedData.length - ivLength); + + PublicKey ephemeralPublicKey = getAlgorithmBasedEphemeralPublicKey(ephemeralPublicKeyBytes, privateKey.getAlgorithm()); + KeyAgreement keyAgreement = getKeyAgreementAlorithmBased(ephemeralPublicKey, privateKey, privateKey.getAlgorithm()); + byte[] sharedSecret = keyAgreement.generateSecret(); + + byte[] aesKeyBytes = getHkdfKeyBytes(sharedSecret, iv, reason.getBytes(), AES_KEY_LENGTH); + SecretKey aesKey = new SecretKeySpec(aesKeyBytes, 0, AES_KEY_LENGTH, AES); + + Cipher aesCipher = Cipher.getInstance(symmetricAlgorithmName); + GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(tagLength, iv); + aesCipher.init(Cipher.DECRYPT_MODE, aesKey, gcmParameterSpec); + if (aad != null && aad.length != 0) { + aesCipher.updateAAD(aad); + } + decryptedData = aesCipher.doFinal(cipherText); + + } catch (java.security.NoSuchAlgorithmException | NoSuchPaddingException | BadPaddingException e) { + throw new NoSuchAlgorithmException( + SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(), + SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage(), e); + } catch (java.security.InvalidKeyException | IllegalBlockSizeException e) { + throw new InvalidKeyException( + SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorCode(), + SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorMessage(), e); + } catch (InvalidAlgorithmParameterException e) { + throw new InvalidKeyException( + SecurityExceptionCodeConstant.MOSIP_INVALID_PARAM_SPEC_EXCEPTION.getErrorCode(), + SecurityExceptionCodeConstant.MOSIP_INVALID_PARAM_SPEC_EXCEPTION.getErrorMessage(), e); + } + return decryptedData; + } + + /** + * Generator for IV (Initialization Vector) + * + * @param blockSize blocksize of current cipher + * @return generated IV + */ + private byte[] generateIV(int blockSize) { + byte[] byteIV = new byte[blockSize]; + SecureRandom secureRandom = new SecureRandom(); + secureRandom.nextBytes(byteIV); + return byteIV; + } + + /** + * Destroys the key by filling it with zeros. + * + * @param key The key to be destroyed. + */ + private void destroyKey(byte[] key) { + if (Objects.nonNull(key)) { + Arrays.fill(key, (byte) 0); + } + } + + /** + * Generates HKDF key bytes using the provided secret, salt, reason, and key length. + * + * @param ikm The Input Key Material (IKM) to derive the key from. + * @param salt The salt to use in the HKDF process. + * @param reason The reason for generating the key, used as additional data. + * @param keyLength The desired length of the generated key in bytes. + * @return The derived key bytes. + */ + private byte[] getHkdfKeyBytes(byte[] ikm, byte[] salt, byte[] reason, int keyLength) { + LOGGER.info(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.WHITESPACE, CryptomanagerConstant.WHITESPACE, + "Generating HKDF key bytes."); + + try { + Mac mac = Mac.getInstance(HMAC_SHA_256); + SecretKeySpec secretKeySpec = new SecretKeySpec(salt, HMAC_SHA_256); + mac.init(secretKeySpec); + byte[] prk = mac.doFinal(ikm); + + byte[] result = new byte[keyLength]; + byte[] previousBlock = new byte[0]; + int bytegenerated = 0; + int iteration = (int) Math.ceil((double) keyLength / mac.getMacLength()); + + for (int i = 0; i < iteration; i++) { + mac.init(new SecretKeySpec(prk, HMAC_SHA_256)); + mac.update(previousBlock); + mac.update(reason); + mac.update((byte) (i + 1)); + byte[] block = mac.doFinal(); + + int bytesToCopy = Math.min(block.length, keyLength - bytegenerated); + System.arraycopy(block, 0, result, bytegenerated, bytesToCopy); + bytegenerated += bytesToCopy; + + previousBlock = block; + System.out.println("Number of iterations: " + (i + 1) + ", Bytes generated so far: " + bytegenerated); + } + return result; + + } catch (java.security.NoSuchAlgorithmException e) { + throw new NoSuchAlgorithmException( + SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(), + SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage(), e); + } catch (java.security.InvalidKeyException e) { + throw new InvalidKeyException( + SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorCode(), + SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorMessage(), e); + } + } + + private KeyPair generateAlgorithmBasedEphemeralKeyPair(String curveName) { + KeyPairGenerator ephemeralKeyPairGen; + try { + if (curveName.equals(KeymanagerConstant.X25519_KEY_TYPE) || curveName.equals(KeymanagerConstant.XDH_ALGORITHM)) { + ephemeralKeyPairGen = KeyPairGenerator.getInstance(KeymanagerConstant.X25519_KEY_TYPE); + NamedParameterSpec x25519GenParameterSpec = new NamedParameterSpec(KeymanagerConstant.X25519_KEY_TYPE); + ephemeralKeyPairGen.initialize(x25519GenParameterSpec); + return ephemeralKeyPairGen.generateKeyPair(); + } else { + ephemeralKeyPairGen = KeyPairGenerator.getInstance(EC_ALGORITHM, BC_PROVIDER); + ECGenParameterSpec ecGenParameterSpec = new ECGenParameterSpec(curveName); + ephemeralKeyPairGen.initialize(ecGenParameterSpec); + return ephemeralKeyPairGen.generateKeyPair(); + } + } catch (InvalidAlgorithmParameterException | java.security.NoSuchAlgorithmException | NoSuchProviderException e) { + throw new NoSuchAlgorithmException( + SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(), + SecurityExceptionCodeConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage(), e); + } + } + + public KeyAgreement getKeyAgreementAlorithmBased(PublicKey key, PrivateKey privateKey, String curveName) { + if (curveName.equals(KeymanagerConstant.X25519_KEY_TYPE) || curveName.equals(KeymanagerConstant.XDH_ALGORITHM)) + return getKeyAgreement(key, privateKey, KeymanagerConstant.X25519_KEY_TYPE); + else + return getKeyAgreement(key, privateKey, ECDH); + } + + private KeyAgreement getKeyAgreement(PublicKey publicKey, PrivateKey privateKey, String algorithm) { + KeyAgreement keyAgreement; + try { + keyAgreement = KeyAgreement.getInstance(algorithm, BC_PROVIDER); + keyAgreement.init(privateKey); + keyAgreement.doPhase(publicKey, true); + } catch (java.security.NoSuchAlgorithmException | java.security.InvalidKeyException | NoSuchProviderException e) { + throw new InvalidKeyException( + SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorCode(), + SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorMessage(), e); + } + return keyAgreement; + } + + public PublicKey getAlgorithmBasedEphemeralPublicKey(byte[] ephemeralPublicKeyBytes, String curveName) { + if (curveName.equals(KeymanagerConstant.X25519_KEY_TYPE) || curveName.equals(KeymanagerConstant.XDH_ALGORITHM)) + return getEphemeralPublicKey(ephemeralPublicKeyBytes, KeymanagerConstant.X25519_KEY_TYPE); + else + return getEphemeralPublicKey(ephemeralPublicKeyBytes, EC_ALGORITHM); + } + + private PublicKey getEphemeralPublicKey(byte[] ephemeralPublicKeyBytes, String algo) { + try { + KeyFactory keyFactory = KeyFactory.getInstance(algo, BC_PROVIDER); + X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(ephemeralPublicKeyBytes); + return keyFactory.generatePublic(publicKeySpec); + } catch (java.security.NoSuchAlgorithmException | InvalidKeySpecException | NoSuchProviderException e) { + throw new InvalidKeyException( + SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorCode(), + SecurityExceptionCodeConstant.MOSIP_INVALID_KEY_EXCEPTION.getErrorMessage(), e); + } + } +} \ No newline at end of file diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/util/CryptomanagerUtils.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/util/CryptomanagerUtils.java index a6838b8d..e227a662 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/util/CryptomanagerUtils.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/cryptomanager/util/CryptomanagerUtils.java @@ -7,11 +7,12 @@ package io.mosip.kernel.cryptomanager.util; import java.io.IOException; -import java.security.PublicKey; -import java.security.SecureRandom; +import java.security.*; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.interfaces.RSAPublicKey; +import java.security.spec.InvalidKeySpecException; +import java.security.spec.PKCS8EncodedKeySpec; import java.time.LocalDateTime; import java.time.format.DateTimeFormatter; import java.util.*; @@ -24,6 +25,13 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.json.JsonMapper; import com.fasterxml.jackson.module.afterburner.AfterburnerModule; +import io.mosip.kernel.core.keymanager.spi.ECKeyStore; +import io.mosip.kernel.core.util.DateUtils; +import io.mosip.kernel.keymanagerservice.constant.KeyReferenceIdConsts; +import io.mosip.kernel.keymanagerservice.constant.KeymanagerErrorConstant; +import io.mosip.kernel.keymanagerservice.entity.KeyAlias; +import io.mosip.kernel.keymanagerservice.exception.NoUniqueAliasException; +import io.mosip.kernel.keymanagerservice.helper.PrivateKeyDecryptorHelper; import io.mosip.kernel.signature.constant.SignatureConstant; import org.apache.commons.codec.digest.DigestUtils; import org.bouncycastle.util.encoders.Hex; @@ -93,6 +101,17 @@ public class CryptomanagerUtils { @Value("${mosip.kernel.keymanager.jwtEncrypt.validate.json:true}") private boolean confValidateJson; + /** The sign applicationid. */ + @Value("${mosip.sign.applicationid:KERNEL}") + private String signApplicationid; + + @Value("${mosip.sign-certificate-refid:SIGN}") + private String certificateSignRefID; + + /** Flag to generate and store Ed25519 key in real HSM. */ + @Value("${mosip.kernel.keymanager.ed25519.hsm.support.enabled:false}") + private boolean ed25519SupportFlag; + /** The key manager. */ @Autowired private KeymanagerService keyManager; @@ -103,6 +122,12 @@ public class CryptomanagerUtils { @Autowired private KeymanagerDBHelper dbHelper; + @Autowired + private ECKeyStore keyStore; + + @Autowired + private PrivateKeyDecryptorHelper privateKeyDecryptorHelper; + /** * Calls Key-Manager-Service to get public key of an application. * @@ -123,7 +148,7 @@ public Certificate getCertificate(CryptomanagerRequestDto cryptomanagerRequestDt * @param refId the ref id * @return the certificate data from key manager */ - private String getCertificateFromKeyManager(String appId, String refId) { + public String getCertificateFromKeyManager(String appId, String refId) { return keyManager.getCertificate(appId, Optional.ofNullable(refId)).getCertificate(); } @@ -322,13 +347,16 @@ public Certificate getCertificate(String applicationId, String referenceId) { public void validateEncKeySize(Certificate encCert) { if (validateKeySize) { - RSAPublicKey rsaPublicKey = (RSAPublicKey) encCert.getPublicKey(); - if (rsaPublicKey.getModulus().bitLength() != 2048) { - LOGGER.error(CryptomanagerConstant.SESSIONID, this.getClass().getSimpleName(), CryptomanagerConstant.JWT_ENCRYPT, - "Not Allowed to preform encryption with Key size not equal to 2048 bit."); - throw new CryptoManagerSerivceException(CryptomanagerErrorCode.ENCRYPT_NOT_ALLOWED_ERROR.getErrorCode(), - CryptomanagerErrorCode.ENCRYPT_NOT_ALLOWED_ERROR.getErrorMessage()); - } + String algorithmName = encCert.getPublicKey().getAlgorithm(); + if (algorithmName.equalsIgnoreCase(KeymanagerConstant.RSA)) { + RSAPublicKey rsaPublicKey = (RSAPublicKey) encCert.getPublicKey(); + if (rsaPublicKey.getModulus().bitLength() != 2048) { + LOGGER.error(CryptomanagerConstant.SESSIONID, this.getClass().getSimpleName(), CryptomanagerConstant.JWT_ENCRYPT, + "Not Allowed to preform encryption with Key size not equal to 2048 bit."); + throw new CryptoManagerSerivceException(CryptomanagerErrorCode.ENCRYPT_NOT_ALLOWED_ERROR.getErrorCode(), + CryptomanagerErrorCode.ENCRYPT_NOT_ALLOWED_ERROR.getErrorMessage()); + } + } } } @@ -397,4 +425,126 @@ public boolean isJWSData(String data) { } return true; } + + public String getAlgorithmNameFromHeader(byte[] encryptedData) { + int keyDelimiterIndex = 0; + keyDelimiterIndex = CryptoUtil.getSplitterIndex(encryptedData, keyDelimiterIndex, keySplitter); + byte[] algorithmBytes = Arrays.copyOfRange(encryptedData, 0, keyDelimiterIndex); + String algorithmName; + + if (Arrays.equals(algorithmBytes, CryptomanagerConstant.VERSION_EC256_R1)) { + algorithmName = CryptomanagerConstant.EC_SECP256R1; + } else if (Arrays.equals(algorithmBytes, CryptomanagerConstant.VERSION_EC256_K1)) { + algorithmName = CryptomanagerConstant.EC_SECP256K1; + } else if (Arrays.equals(algorithmBytes, CryptomanagerConstant.VERSION_EC_X25519)) { + algorithmName = CryptomanagerConstant.EC_X25519; + } else { + algorithmName = KeymanagerConstant.RSA; + } + return algorithmName; + } + + public Object[] getEncryptedPrivateKey(String appId, Optional refId, String certThumbprint) { + + LocalDateTime localDateTime = DateUtils.getUTCCurrentDateTime(); + Map> keyAliasMap = dbHelper.getKeyAliases(appId, refId.get(), localDateTime); + KeyAlias keyAlias = keyAliasMap.get(KeymanagerConstant.CURRENTKEYALIAS).getFirst(); + String ksAlias = keyAlias.getAlias(); + + if (!refId.isPresent() || refId.get().trim().isEmpty()) { + LOGGER.info(KeymanagerConstant.SESSIONID, KeymanagerConstant.EMPTY, KeymanagerConstant.EMPTY, + "Not valid reference Id. Getting private key from HSM."); + KeyStore.PrivateKeyEntry masterKeyEntry = keyStore.getAsymmetricKey(ksAlias); + PrivateKey masterPrivateKey = masterKeyEntry.getPrivateKey(); + Certificate masterCert = masterKeyEntry.getCertificate(); + return new Object[] {masterPrivateKey, masterCert}; + + } else if ((appId.equalsIgnoreCase(signApplicationid) && refId.isPresent() + && refId.get().equals(certificateSignRefID)) || + (refId.isPresent() && refId.get().equals(KeyReferenceIdConsts.EC_SECP256K1_SIGN.name())) || + (refId.isPresent() && refId.get().equals(KeyReferenceIdConsts.EC_SECP256R1_SIGN.name())) || + (refId.isPresent() && refId.get().equals(KeyReferenceIdConsts.ED25519_SIGN.name()) + && ed25519SupportFlag)) { + LOGGER.info(KeymanagerConstant.SESSIONID, KeymanagerConstant.EMPTY, KeymanagerConstant.EMPTY, + "Reference Id is present and it is " + refId.get() + " Signature Key ref Id. Getting private key from HSM."); + KeyStore.PrivateKeyEntry masterKeyEntry = keyStore.getAsymmetricKey(ksAlias); + PrivateKey masterPrivateKey = masterKeyEntry.getPrivateKey(); + Certificate masterCert = masterKeyEntry.getCertificate(); + return new Object[] {masterPrivateKey, masterCert}; + } else { + LOGGER.info(KeymanagerConstant.SESSIONID, KeymanagerConstant.EMPTY, KeymanagerConstant.EMPTY, + "Reference Id is present. Will get Certificate from DB store"); + + String referenceId = refId.get(); + io.mosip.kernel.keymanagerservice.entity.KeyStore dbKeyStore = privateKeyDecryptorHelper.getDBKeyStoreData(certThumbprint, + appId, referenceId); + if (dbKeyStore.getAlias().isEmpty()) { + LOGGER.error(KeymanagerConstant.SESSIONID, KeymanagerConstant.KEYFROMDB, dbKeyStore.toString(), + "Key in DBStore does not exist for this alias. Throwing exception"); + throw new NoUniqueAliasException(KeymanagerErrorConstant.NO_UNIQUE_ALIAS.getErrorCode(), + KeymanagerErrorConstant.NO_UNIQUE_ALIAS.getErrorMessage()); + } + String masterKeyAlias = dbKeyStore.getMasterAlias(); + String privateKeyObj = dbKeyStore.getPrivateKey(); + + if (ksAlias.equals(masterKeyAlias) || privateKeyObj.equals(KeymanagerConstant.KS_PK_NA)) { + LOGGER.error(KeymanagerConstant.SESSIONID, KeymanagerConstant.APPLICATIONID, null, + "Not Allowed to perform decryption with other domain key."); + throw new KeymanagerServiceException(KeymanagerErrorConstant.DECRYPTION_NOT_ALLOWED.getErrorCode(), + KeymanagerErrorConstant.DECRYPTION_NOT_ALLOWED.getErrorMessage()); + } + + KeyStore.PrivateKeyEntry masterKeyEntry = keyStore.getAsymmetricKey(dbKeyStore.getMasterAlias()); + PrivateKey masterPrivateKey = masterKeyEntry.getPrivateKey(); + PublicKey masterPublicKey = masterKeyEntry.getCertificate().getPublicKey(); + /** + * If the private key is in dbstore, then it will be first decrypted with + * application's master private key from softhsm's/HSM's keystore + */ + try { + return getObjects(dbKeyStore, masterPrivateKey, masterPublicKey); + } catch (Exception e) { + // need confirm the error message and code + LOGGER.error(KeymanagerConstant.SESSIONID, KeymanagerConstant.APPLICATIONID, null, + "Error while decrypting private key from DBStore. Throwing exception", e); + throw new KeymanagerServiceException(KeymanagerErrorConstant.NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(), + KeymanagerErrorConstant.NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage()); + } + } + } + + public Object[] getObjects(io.mosip.kernel.keymanagerservice.entity.KeyStore dbKeyStore, PrivateKey masterPrivateKey, PublicKey masterPublicKey) { + byte[] decryptedPrivateKey = keymanagerUtil.decryptKey(CryptoUtil.decodeURLSafeBase64(dbKeyStore.getPrivateKey()), + masterPrivateKey, masterPublicKey); + + PublicKey publicKey = keymanagerUtil.convertToCertificate(dbKeyStore.getCertificateData()).getPublicKey(); + String algorithmName = publicKey.getAlgorithm(); + KeyFactory keyFactory = null; + PrivateKey privateKey = null; + try { + keyFactory = KeyFactory.getInstance(algorithmName); + privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decryptedPrivateKey)); + } catch (InvalidKeySpecException | NoSuchAlgorithmException e) { + throw new RuntimeException(e); + } + Certificate certificate = keymanagerUtil.convertToCertificate(dbKeyStore.getCertificateData()); + return new Object[]{privateKey, certificate}; + } + + public byte[] getHeaderByte(String ecCurveName) { + byte[] headerBytes = new byte[0]; + if (ecCurveName.equalsIgnoreCase(CryptomanagerConstant.EC_SECP256R1)) { + headerBytes = CryptomanagerConstant.VERSION_EC256_R1; + } else if (ecCurveName.equalsIgnoreCase(CryptomanagerConstant.EC_SECP256K1)) { + headerBytes = CryptomanagerConstant.VERSION_EC256_K1; + } else if (ecCurveName.equalsIgnoreCase(CryptomanagerConstant.EC_X25519)) { + headerBytes = CryptomanagerConstant.VERSION_EC_X25519; + } else { + LOGGER.error(CryptomanagerConstant.SESSIONID, CryptomanagerConstant.ENCRYPT, CryptomanagerConstant.ENCRYPT, + "Unsupported EC Curve Name: " + ecCurveName); + throw new CryptoManagerSerivceException(CryptomanagerErrorCode.UNSUPPORTED_EC_CURVE.getErrorCode(), + CryptomanagerErrorCode.UNSUPPORTED_EC_CURVE.getErrorMessage() + ecCurveName); + } + return headerBytes; + } } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/KeyGenerator.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/KeyGenerator.java index a3db18cc..3e4ea942 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/KeyGenerator.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/KeyGenerator.java @@ -67,6 +67,10 @@ public class KeyGenerator { @Value("${mosip.kernel.keygenerator.asymmetric.ed25519.algorithm-name:Ed25519}") private String asymmetricEDKeyAlgorithm; + /** ECC algorithm curve name */ + @Value("${mosip.kernel.keygenerator.ecc-curve-name:SECP256R1}") + private String eccCurve; + @Autowired private ECKeyStore keyStore; @@ -84,7 +88,7 @@ public SecretKey getSymmetricKey() { /** * This method generated Asymmetric key pairs * - * @return {@link KeyPair} which contain public nad private key + * @return {@link KeyPair} which contain public and private key */ public KeyPair getAsymmetricKey() { KeyPairGenerator generator = KeyGeneratorUtils.getKeyPairGenerator(asymmetricKeyAlgorithm, asymmetricKeyLength, @@ -119,4 +123,23 @@ private SecureRandom getSecureRandom() { return secureRandom; } + /** + * This method generated Asymmetric key pairs for ECC + * + * @return {@link KeyPair} which contain public and private key + */ + public KeyPair getECKeyPair() { + KeyPairGenerator generator = KeyGeneratorUtils.getECKeyPairGenerator(asymmetricKeyAlgorithm, eccCurve, getSecureRandom()); + return generator.generateKeyPair(); + } + + /** + * This method generated Asymmetric key pairs for X25519 + * + * @return {@link java.security.KeyPair} which contain public and private + */ + public KeyPair getX25519KeyPair() { + KeyPairGenerator generator = KeyGeneratorUtils.getX25519KeyPairGenerator(getSecureRandom()); + return generator.generateKeyPair(); + } } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/util/KeyGeneratorUtils.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/util/KeyGeneratorUtils.java index 25062736..ca55386d 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/util/KeyGeneratorUtils.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keygenerator/bouncycastle/util/KeyGeneratorUtils.java @@ -7,10 +7,7 @@ import java.security.PublicKey; import java.security.SecureRandom; import java.security.Security; -import java.security.spec.ECGenParameterSpec; -import java.security.spec.InvalidKeySpecException; -import java.security.spec.PKCS8EncodedKeySpec; -import java.security.spec.X509EncodedKeySpec; +import java.security.spec.*; import javax.crypto.KeyGenerator; @@ -137,4 +134,31 @@ private static BouncyCastleProvider init() { Security.addProvider(provider); return provider; } + + public static KeyPairGenerator getECKeyPairGenerator(String algorithmName, String eccCurve, SecureRandom secureRandom) { + KeyPairGenerator generator = null; + try { + generator = KeyPairGenerator.getInstance(algorithmName, provider); + generator.initialize(new ECGenParameterSpec(eccCurve), secureRandom); + return generator; + } catch (java.security.NoSuchAlgorithmException | InvalidAlgorithmParameterException e) { + throw new NoSuchAlgorithmException( + KeyGeneratorExceptionConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(), + KeyGeneratorExceptionConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage(), e); + } + } + + public static KeyPairGenerator getX25519KeyPairGenerator(SecureRandom secureRandom) { + KeyPairGenerator generator = null; + try { + generator = KeyPairGenerator.getInstance(KeymanagerConstant.X25519_KEY_TYPE, provider); + NamedParameterSpec namedParameterSpec = new NamedParameterSpec(KeymanagerConstant.X25519_KEY_TYPE); + generator.initialize(namedParameterSpec, secureRandom); + return generator; + } catch (java.security.NoSuchAlgorithmException | InvalidAlgorithmParameterException e) { + throw new NoSuchAlgorithmException( + KeyGeneratorExceptionConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(), + KeyGeneratorExceptionConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage(), e); + } + } } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/constant/KeymanagerConstant.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/constant/KeymanagerConstant.java index 2679602e..4965acf5 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/constant/KeymanagerConstant.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/constant/KeymanagerConstant.java @@ -66,4 +66,10 @@ private KeymanagerConstant() { public static final String ASYM_KEY_ED_ALGORITHM = "ASYM_KEY_ED_ALGORITHM"; + public static final String RSA_SIGN_ALGORITHM = "SHA256withRSA"; + + public static final String EC_SIGN_ALGORITHM = "SHA256withECDSA"; + + public static final String ED_SIGN_ALGORITHM = "Ed25519"; + } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/impl/KeyStoreImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/impl/KeyStoreImpl.java index da6e96b6..be79a8c2 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/impl/KeyStoreImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/impl/KeyStoreImpl.java @@ -117,6 +117,12 @@ public class KeyStoreImpl implements ECKeyStore, InitializingBean { @Value("${mosip.kernel.keygenerator.asymmetric.ec.algorithm-name:EC}") private String asymmetricECKeyAlgorithm; + /** + * Ed25519 Asymmetric key algorithm Name + */ + @Value("${mosip.kernel.keygenerator.asymmetric.ed.algorithm-name:Ed25519}") + private String asymmetricEdKeyAlgorithm; + /** * JCE Implementation Clazz Name and other required information. * @@ -175,6 +181,7 @@ private void setAlgorithmProperties() { keystoreParams.put(KeymanagerConstant.CERT_SIGN_ALGORITHM, signAlgorithm); keystoreParams.put(KeymanagerConstant.FLAG_KEY_REF_CACHE, Boolean.toString(enableKeyReferenceCache)); keystoreParams.put(KeymanagerConstant.ASYM_KEY_EC_ALGORITHM, asymmetricECKeyAlgorithm); + keystoreParams.put(KeymanagerConstant.ASYM_KEY_ED_ALGORITHM, asymmetricEdKeyAlgorithm); } private void addPKCSParams() { diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/impl/pkcs/PKCS12KeyStoreImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/impl/pkcs/PKCS12KeyStoreImpl.java index 5e2a11a7..ff2f9383 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/impl/pkcs/PKCS12KeyStoreImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/impl/pkcs/PKCS12KeyStoreImpl.java @@ -8,24 +8,11 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; -import java.security.InvalidAlgorithmParameterException; -import java.security.Key; -import java.security.KeyPair; -import java.security.KeyPairGenerator; -import java.security.KeyStore; +import java.security.*; import java.security.KeyStore.PasswordProtection; import java.security.KeyStore.PrivateKeyEntry; import java.security.KeyStore.ProtectionParameter; import java.security.KeyStore.SecretKeyEntry; -import java.security.KeyStoreException; -import java.security.NoSuchAlgorithmException; -import java.security.PrivateKey; -import java.security.Provider; -import java.security.PublicKey; -import java.security.SecureRandom; -import java.security.Security; -import java.security.UnrecoverableEntryException; -import java.security.UnrecoverableKeyException; import java.security.cert.Certificate; import java.security.cert.CertificateException; import java.security.cert.X509Certificate; @@ -146,6 +133,7 @@ public PKCS12KeyStoreImpl(Map params) throws Exception { this.signAlgorithm = params.get(KeymanagerConstant.CERT_SIGN_ALGORITHM); this.enableKeyReferenceCache = Boolean.parseBoolean(params.get(KeymanagerConstant.FLAG_KEY_REF_CACHE)); this.asymmetricECKeyAlgorithm = params.get(KeymanagerConstant.ASYM_KEY_EC_ALGORITHM); + this.asymmetricEdKeyAlgorithm = params.get(KeymanagerConstant.ASYM_KEY_ED_ALGORITHM); this.secureRandom = new SecureRandom(); initKeystore(); initKeyReferenceCache(); @@ -256,7 +244,7 @@ private KeyStore getKeystoreInstance(String keystoreType, String p12FilePath, Pr KeyStore mosipKeyStore = null; try { // Not adding Provider because BC provider is not allowing to add symmetric key in keystore file. - mosipKeyStore = KeyStore.getInstance(keystoreType); + mosipKeyStore = KeyStore.getInstance(keystoreType, provider); Path path = Paths.get(p12FilePath); // if file is not available, it will get created when new key get created. if (!Files.exists(path)){ @@ -270,7 +258,7 @@ private KeyStore getKeystoreInstance(String keystoreType, String p12FilePath, Pr throw new KeystoreProcessingException(KeymanagerErrorCode.KEYSTORE_PROCESSING_ERROR.getErrorCode(), KeymanagerErrorCode.KEYSTORE_PROCESSING_ERROR.getErrorMessage() + e.getMessage(), e); } - } + } /* * (non-Javadoc) @@ -480,6 +468,8 @@ else if (ecCurvesList.contains(keyType)) return generateECKeyPair(keyType); else if (KeymanagerConstant.ED25519_KEY_TYPE.equals(keyType)) return generateEd25519KeyPair(); + else if (io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant.X25519_KEY_TYPE.equals(keyType)) + return generateX25519KeyPair(); throw new io.mosip.kernel.core.exception.NoSuchAlgorithmException( KeyGeneratorExceptionConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(), @@ -488,7 +478,7 @@ else if (KeymanagerConstant.ED25519_KEY_TYPE.equals(keyType)) private KeyPair generateRSAKeyPair() { try { - KeyPairGenerator generator = KeyPairGenerator.getInstance(asymmetricKeyAlgorithm, provider); + KeyPairGenerator generator = KeyPairGenerator.getInstance(KeymanagerConstant.RSA_KEY_TYPE, provider); generator.initialize(asymmetricKeyLength, secureRandom); return generator.generateKeyPair(); } catch (java.security.NoSuchAlgorithmException e) { @@ -627,5 +617,16 @@ public void generateAndStoreAsymmetricKey(String alias, String signKeyAlias, Cer public void generateAndStoreEDAsymmetricKey(String alias, String signKeyAlias, CertificateParameters certParams) { generateAndStoreAsymmetricKey(alias, signKeyAlias, certParams, KeymanagerConstant.ED25519_KEY_TYPE); } */ + + private KeyPair generateX25519KeyPair() { + try { + KeyPairGenerator generator = KeyPairGenerator.getInstance(io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant.X25519_KEY_TYPE, provider); + return generator.generateKeyPair(); + } catch (java.security.NoSuchAlgorithmException e) { + throw new io.mosip.kernel.core.exception.NoSuchAlgorithmException( + KeyGeneratorExceptionConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorCode(), + KeyGeneratorExceptionConstant.MOSIP_NO_SUCH_ALGORITHM_EXCEPTION.getErrorMessage(), e); + } + } } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/util/CertificateUtility.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/util/CertificateUtility.java index 93c6ae93..8ebc953e 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/util/CertificateUtility.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanager/hsm/util/CertificateUtility.java @@ -102,10 +102,10 @@ public static X509Certificate generateX509Certificate(PrivateKey signPrivateKey, ExtendedCertificateParameters extendedCertParams = (ExtendedCertificateParameters) certParams; List sanDtoList = extendedCertParams.getSubjectAlternativeNames(); GeneralName[] sanArray = getCertificateSAN(sanDtoList, publicKey); - return generateX509Certificate(signPrivateKey, publicKey, certIssuer, certSubject, signAlgorithm, providerName, + return generateX509Certificate(signPrivateKey, publicKey, certIssuer, certSubject, getSignatureAlgorithm(signPrivateKey), providerName, certParams.getNotBefore(), certParams.getNotAfter(), keyUsage, basicConstraints, sanArray); }else { - return generateX509Certificate(signPrivateKey, publicKey, certIssuer, certSubject, signAlgorithm, providerName, + return generateX509Certificate(signPrivateKey, publicKey, certIssuer, certSubject, getSignatureAlgorithm(signPrivateKey), providerName, certParams.getNotBefore(), certParams.getNotAfter(), keyUsage, basicConstraints); } } @@ -116,7 +116,7 @@ private static X509Certificate generateX509Certificate(PrivateKey signPrivateKey try { BigInteger certSerialNum = new BigInteger(Long.toString(new SecureRandom().nextLong())); - ContentSigner certContentSigner = new JcaContentSignerBuilder(signAlgorithm).setProvider(providerName).build(signPrivateKey); + ContentSigner certContentSigner = new JcaContentSignerBuilder(getSignatureAlgorithm(signPrivateKey)).setProvider(providerName).build(signPrivateKey); X509v3CertificateBuilder certBuilder = new JcaX509v3CertificateBuilder(certIssuer, certSerialNum, getDateFromLocalDateTime(notBefore), getDateFromLocalDateTime(notAfter), certSubject, publicKey); JcaX509ExtensionUtils certExtUtils = new JcaX509ExtensionUtils(); @@ -124,7 +124,7 @@ private static X509Certificate generateX509Certificate(PrivateKey signPrivateKey certBuilder.addExtension(Extension.subjectKeyIdentifier, false, certExtUtils.createSubjectKeyIdentifier(publicKey)); certBuilder.addExtension(Extension.keyUsage, true, keyUsage); X509CertificateHolder certHolder = certBuilder.build(certContentSigner); - return new JcaX509CertificateConverter().getCertificate(certHolder); + return new JcaX509CertificateConverter().setProvider(providerName).getCertificate(certHolder); } catch (OperatorCreationException | NoSuchAlgorithmException | CertificateException | IOException e) { throw new KeystoreProcessingException(KeymanagerErrorCode.CERTIFICATE_PROCESSING_ERROR.getErrorCode(), KeymanagerErrorCode.CERTIFICATE_PROCESSING_ERROR.getErrorMessage() + e.getMessage(), e); @@ -148,7 +148,7 @@ private static X509Certificate generateX509Certificate(PrivateKey signPrivateKey certBuilder.addExtension(Extension.subjectAlternativeName, false, new GeneralNames(altNames)); } X509CertificateHolder certHolder = certBuilder.build(certContentSigner); - return new JcaX509CertificateConverter().getCertificate(certHolder); + return new JcaX509CertificateConverter().setProvider(providerName).getCertificate(certHolder); } catch (OperatorCreationException | NoSuchAlgorithmException | CertificateException | IOException e) { throw new KeystoreProcessingException(KeymanagerErrorCode.CERTIFICATE_PROCESSING_ERROR.getErrorCode(), KeymanagerErrorCode.CERTIFICATE_PROCESSING_ERROR.getErrorMessage() + e.getMessage(), e); @@ -286,4 +286,19 @@ private static GeneralName[] getCertificateSAN(List throw new RuntimeException(e); } } + + private static String getSignatureAlgorithm(PrivateKey privateKey) { + + String keyAlgorithm = privateKey.getAlgorithm(); + if (keyAlgorithm.equals(KeymanagerConstant.EC_KEY_TYPE)) + return io.mosip.kernel.keymanager.hsm.constant.KeymanagerConstant.EC_SIGN_ALGORITHM; + else if (keyAlgorithm.equals(KeymanagerConstant.ED25519_KEY_TYPE) || + keyAlgorithm.equals(KeymanagerConstant.ED25519_ALG_OID) || + keyAlgorithm.equals(KeymanagerConstant.EDDSA_KEY_TYPE)) + return io.mosip.kernel.keymanager.hsm.constant.KeymanagerConstant.ED_SIGN_ALGORITHM; + else if (keyAlgorithm.equals(KeymanagerConstant.X25519_KEY_TYPE)) + return KeymanagerConstant.X25519_KEY_TYPE; + + return io.mosip.kernel.keymanager.hsm.constant.KeymanagerConstant.RSA_SIGN_ALGORITHM; + } } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeyReferenceIdConsts.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeyReferenceIdConsts.java index 7819e808..fbe06252 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeyReferenceIdConsts.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeyReferenceIdConsts.java @@ -4,5 +4,6 @@ public enum KeyReferenceIdConsts { EC_SECP256K1_SIGN, EC_SECP256R1_SIGN, - ED25519_SIGN + ED25519_SIGN, + RSA_2048_SIGN } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeymanagerConstant.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeymanagerConstant.java index b261840a..725c7456 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeymanagerConstant.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeymanagerConstant.java @@ -248,4 +248,16 @@ private KeymanagerConstant() { public static final String GET_CERTIFICATE_CHAIN = "Get Certificate Trust Chain"; public static final String DEFAULT_VALUE = "default"; + + public static final String EC_SECP256R1_OID = "1.2.840.10045.3.1.7"; + + public static final String EC_SECP256K1_OID = "1.3.132.0.10"; + + public static final String X25519_KEY_TYPE = "X25519"; + + public static final String XDH_ALGORITHM = "XDH"; + + public static final String X25519_ENC_KEY_REF_ID = "X25519_ENC_KEY"; + + public static final String GENERATE_RSA_SIGN_KEY = "Request received to generate the RSA Signature Key pair."; } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeymanagerErrorConstant.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeymanagerErrorConstant.java index 3d4b053b..585140e0 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeymanagerErrorConstant.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/constant/KeymanagerErrorConstant.java @@ -81,6 +81,8 @@ public enum KeymanagerErrorConstant { INVALID_FORMAT_ERROR("KER-KMS-036", "Unsupported output format for the signature"), + X25519_KEY_CSR_NOT_SUPPORTED("KER-KMS-037", "CSR Certificate generation is Not Supported for X25519 Algorithm"), + INTERNAL_SERVER_ERROR("KER-KMS-500", "Internal server error"); /** diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/controller/KeymanagerController.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/controller/KeymanagerController.java index 84bb9a0f..8e143378 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/controller/KeymanagerController.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/controller/KeymanagerController.java @@ -306,4 +306,33 @@ public ResponseWrapper getCertificateChain( @ApiPar response.setResponse(keymanagerService.getCertificateChain(applicationId, referenceId)); return response; } + + /** + * Request to generate component Signature RSA Key pair & Certificate for the Provided APP ID & REF ID. + * Supported KeySize 2048. + * + * @param objectType response Object Type. Support types are Certificate/CSR. + * @param rsaKeyPairGenRequestDto {@link KeyPairGenerateRequestDto} request + * @return {@link KeyPairGenerateResponseDto} instance + */ + @Operation(summary = "Request to generate component Signature RSA Key pair & Certificate for the Provided APP ID & REF ID.", + description = "Request to generate component Signature RSA Key pair & Certificate for the Provided APP ID & REF ID. " + + "Supported Key Size 2048", + tags = { "keymanager" }) + @ApiResponses(value = { + @ApiResponse(responseCode = "200", description = "Success or you may find errors in error array in response"), + @ApiResponse(responseCode = "401", description = "Unauthorized", content = @Content(schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "403", description = "Forbidden", content = @Content(schema = @Schema(hidden = true))), + @ApiResponse(responseCode = "404", description = "Not Found", content = @Content(schema = @Schema(hidden = true))) }) + @PreAuthorize("hasAnyRole(@KeyManagerAuthRoles.getGetgetcertificate())") + @ResponseFilter + @PostMapping(value = "/generateRSASignKey/{objectType}") + public ResponseWrapper generateRSASignKey( + @ApiParam("Response Type CERTIFICATE/CSR") @PathVariable("objectType") String objectType, + @RequestBody @Valid RequestWrapper rsaKeyPairGenRequestDto) { + + ResponseWrapper response = new ResponseWrapper<>(); + response.setResponse(keymanagerService.generateRSASignKey(objectType, rsaKeyPairGenRequestDto.getRequest())); + return response; + } } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/helper/PrivateKeyDecryptorHelper.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/helper/PrivateKeyDecryptorHelper.java index 4e9e5705..b9a5adf7 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/helper/PrivateKeyDecryptorHelper.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/helper/PrivateKeyDecryptorHelper.java @@ -121,7 +121,7 @@ public Object[] getKeyObjects(KeyStore dbKeyStore, boolean fetchMasterKey) { try { byte[] decryptedPrivateKey = keymanagerUtil.decryptKey(CryptoUtil.decodeURLSafeBase64(dbKeyStore.getPrivateKey()), masterPrivateKey, masterPublicKey); - KeyFactory keyFactory = KeyFactory.getInstance(KeymanagerConstant.RSA); + KeyFactory keyFactory = KeyFactory.getInstance(masterPrivateKey.getAlgorithm()); PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decryptedPrivateKey)); Certificate certificate = keymanagerUtil.convertToCertificate(dbKeyStore.getCertificateData()); return new Object[] {privateKey, certificate}; diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/helper/SessionKeyDecrytorHelper.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/helper/SessionKeyDecrytorHelper.java index 923f3337..60fade1e 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/helper/SessionKeyDecrytorHelper.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/helper/SessionKeyDecrytorHelper.java @@ -378,7 +378,7 @@ private Object[] getPrivateKey(String referenceId, KeyAlias fetchedKeyAlias) { try { byte[] decryptedPrivateKey = keymanagerUtil.decryptKey(CryptoUtil.decodeURLSafeBase64(dbKeyStore.get().getPrivateKey()), masterPrivateKey, masterPublicKey); - KeyFactory keyFactory = KeyFactory.getInstance(KeymanagerConstant.RSA); + KeyFactory keyFactory = KeyFactory.getInstance(masterPrivateKey.getAlgorithm()); PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decryptedPrivateKey)); Certificate certificate = keymanagerUtil.convertToCertificate(dbKeyStore.get().getCertificateData()); return new Object[] {privateKey, certificate}; diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/service/KeymanagerService.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/service/KeymanagerService.java index aa6aca91..a71a37e5 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/service/KeymanagerService.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/service/KeymanagerService.java @@ -145,6 +145,14 @@ public SignatureCertificate getSignatureCertificate(String applicationId, Option * @return {@link CertificateChainResponseDto} instance */ public CertificateChainResponseDto getCertificateChain(String applicationId, Optional referenceId); - + + /** + * Function to generate RSA key for the provided app id and ref id. + * + * @param objectType - return Object type can be a certificate or CSR + * @param request - request details like appId, refIds, etc. + * @return {@link KeyPairGenerateResponseDto} instance + */ + public KeyPairGenerateResponseDto generateRSASignKey(String objectType, KeyPairGenerateRequestDto request); } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/service/impl/KeymanagerServiceImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/service/impl/KeymanagerServiceImpl.java index ca395dce..869c61af 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/service/impl/KeymanagerServiceImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymanagerservice/service/impl/KeymanagerServiceImpl.java @@ -123,6 +123,14 @@ public class KeymanagerServiceImpl implements KeymanagerService { @Value("${mosip.kernel.keymanager.ed25519.hsm.support.enabled:false}") private boolean ed25519SupportFlag; + /** Master Key generation algorithm */ + @Value("${mosip.kernel.keygenerator.asymmetric-algorithm-name:RSA}") + private String masterKeyAlgorithm; + + /** ECC algorithm curve name */ + @Value("${mosip.kernel.keygenerator.ecc-curve-name:SECP256R1}") + private String eccCurve; + /** * Keystore instance to handles and store cryptographic keys. */ @@ -162,7 +170,7 @@ public class KeymanagerServiceImpl implements KeymanagerService { @Autowired SubjectAlternativeNamesHelper sanHelper; - private static Map ecRefIdsAlgoNamesMap = new HashMap<>(); + private static final Map ecRefIdsAlgoNamesMap = new HashMap<>(); static { ecRefIdsAlgoNamesMap.put(KeyReferenceIdConsts.EC_SECP256K1_SIGN.name(), ECCurves.SECP256K1.name()); @@ -234,21 +242,29 @@ private ImmutablePair generateKeyPairInHSM(String alias certParams = keymanagerUtil.getCertificateParameters(latestCertPrincipal, generationDateTime, expiryDateTime); } - if (keymanagerUtil.isValidReferenceId(referenceId) && - (Arrays.stream(KeyReferenceIdConsts.values()).anyMatch((rId) -> rId.name().equals(referenceId)))) { - if (referenceId.equals(KeyReferenceIdConsts.EC_SECP256K1_SIGN.name()) || - referenceId.equals(KeyReferenceIdConsts.EC_SECP256R1_SIGN.name()) || - (referenceId.equals(KeyReferenceIdConsts.ED25519_SIGN.name()) && ed25519SupportFlag)) { - keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams, ecRefIdsAlgoNamesMap.get(referenceId).toLowerCase()); - } else if (referenceId.equals(KeyReferenceIdConsts.ED25519_SIGN.name())) { - Object[] ed25519KeyDetailsArr = generateEd25519KeyPairDetails(applicationId, referenceId, timeStamp, keyAlias); - X509Certificate x509Certificate = (X509Certificate) ed25519KeyDetailsArr[1]; - String uniqueIdentifier = (String) ed25519KeyDetailsArr[2]; - return ImmutablePair.of(uniqueIdentifier, x509Certificate); - } - } else { - keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams); - } + if (!masterKeyAlgorithm.equals(KeymanagerConstant.RSA) || (Arrays.stream(KeyReferenceIdConsts.values()) + .noneMatch((rId) -> rId.name().equals(referenceId)))) { + keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams, eccCurve); + } else { + keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams); + } + +// if (keymanagerUtil.isValidReferenceId(referenceId) && +// (Arrays.stream(KeyReferenceIdConsts.values()).anyMatch((rId) -> rId.name().equals(referenceId)))) { +// if (referenceId.equals(KeyReferenceIdConsts.EC_SECP256K1_SIGN.name()) || +// referenceId.equals(KeyReferenceIdConsts.EC_SECP256R1_SIGN.name()) || +// (referenceId.equals(KeyReferenceIdConsts.ED25519_SIGN.name()) && ed25519SupportFlag)) { +// keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams, ecRefIdsAlgoNamesMap.get(referenceId).toLowerCase()); +// } else if (referenceId.equals(KeyReferenceIdConsts.ED25519_SIGN.name())) { +// Object[] ed25519KeyDetailsArr = generateEd25519KeyPairDetails(applicationId, referenceId, timeStamp, keyAlias); +// X509Certificate x509Certificate = (X509Certificate) ed25519KeyDetailsArr[1]; +// String uniqueIdentifier = (String) ed25519KeyDetailsArr[2]; +// return ImmutablePair.of(uniqueIdentifier, x509Certificate); +// } +// } else { +// keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams); +// } + X509Certificate x509Cert = (X509Certificate) keyStore.getCertificate(alias); String certThumbprint = cryptomanagerUtil.getCertificateThumbprintInHex(x509Cert); String uniqueValue = applicationId + KeymanagerConstant.UNDER_SCORE + referenceId + KeymanagerConstant.UNDER_SCORE + @@ -367,17 +383,30 @@ private CertificateInfo getCertificateFromDBStore(String applic String encryptedPrivateKey; alias = UUID.randomUUID().toString(); KeyPair keypair = null; + + CertificateInfo certInfo; if (referenceId.equals(KeyReferenceIdConsts.ED25519_SIGN.name()) && isSignKey) { - keypair = keyGenerator.getEd25519KeyPair(); + if (eccCurve.equals(KeymanagerConstant.ED25519_KEY_TYPE)) { + keypair = keyGenerator.getEd25519KeyPair(); + certInfo = getCertificateFromHSM(applicationId, timeStamp, KeymanagerConstant.X25519_ENC_KEY_REF_ID); + } else { + keypair = keyGenerator.getEd25519KeyPair(); + certInfo = getCertificateFromHSM(applicationId, timeStamp, KeymanagerConstant.EMPTY); + } + } else if (!masterKeyAlgorithm.equals(KeymanagerConstant.RSA)) { + if (eccCurve.equals(KeymanagerConstant.ED25519_KEY_TYPE)) { + keypair = keyGenerator.getX25519KeyPair(); + certInfo = getCertificateFromHSM(applicationId, timeStamp, KeymanagerConstant.X25519_ENC_KEY_REF_ID); + } else { + keypair = keyGenerator.getECKeyPair(); + certInfo = getCertificateFromHSM(applicationId, timeStamp, KeymanagerConstant.EMPTY); + } } else { keypair = keyGenerator.getAsymmetricKey(); + certInfo = getCertificateFromHSM(applicationId, timeStamp, KeymanagerConstant.EMPTY); } PrivateKey privateKey = keypair.getPrivate(); - /** - * Will get application's master key information from HSM. On first request for - * an applicationId and duration, will create a new keypair. - */ - CertificateInfo certInfo = getCertificateFromHSM(applicationId, timeStamp, KeymanagerConstant.EMPTY); + X509Certificate hsmX509Cert = certInfo.getCertificate(); PublicKey masterPublicKey = hsmX509Cert.getPublicKey(); @@ -395,7 +424,15 @@ private CertificateInfo getCertificateFromDBStore(String applic throw new CryptoException(KeymanagerErrorConstant.CRYPTO_EXCEPTION.getErrorCode(), KeymanagerErrorConstant.CRYPTO_EXCEPTION.getErrorMessage() + e.getErrorText()); } - PrivateKeyEntry signKeyEntry = keyStore.getAsymmetricKey(masterAlias); + + PrivateKeyEntry signKeyEntry; + if (masterPublicKey.getAlgorithm().equals(KeymanagerConstant.X25519_KEY_TYPE)) { + CertificateInfo ed25519CertInfo = getCertificateFromHSM(applicationId, timeStamp, KeymanagerConstant.EMPTY); + String edSignMasterAlias = ed25519CertInfo.getAlias(); + signKeyEntry = keyStore.getAsymmetricKey(edSignMasterAlias); + } else { + signKeyEntry = keyStore.getAsymmetricKey(masterAlias); + } PrivateKey signPrivateKey = signKeyEntry.getPrivateKey(); X509Certificate signCert = (X509Certificate) signKeyEntry.getCertificate(); X500Principal signerPrincipal = signCert.getSubjectX500Principal(); @@ -644,21 +681,31 @@ private KeyPairGenerateResponseDto generateAndBuildResponse(String responseObjec LocalDateTime timestamp, Map> keyAliasMap, KeyPairGenerateRequestDto request) { String alias = UUID.randomUUID().toString(); - LocalDateTime generationDateTime = timestamp; - LocalDateTime expiryDateTime = dbHelper.getExpiryPolicy(appId, generationDateTime, keyAliasMap.get(KeymanagerConstant.KEYALIAS)); - String rootKeyAlias = getRootKeyAlias(appId, timestamp); - CertificateParameters certParams; - if (sanHelper.hasSANappIdAndRefId(appId, refId)) { - Map altNamesMap = keymanagerUtil.getSanValues(appId, refId); - certParams = keymanagerUtil.getCertificateParametersIncludeSAN(request, generationDateTime, expiryDateTime, appId, altNamesMap); - } else { - certParams = keymanagerUtil.getCertificateParameters(request, generationDateTime, expiryDateTime, appId); - } - //keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams); - CertificateInfo certificateInfo = generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams, request, generationDateTime, expiryDateTime, keyAliasMap); - return buildResponseObject(responseObjectType, appId, refId, timestamp, certificateInfo.getAlias(), generationDateTime, - expiryDateTime, request, certificateInfo.getCertificate()); - } + LocalDateTime generationDateTime = timestamp; + LocalDateTime expiryDateTime = dbHelper.getExpiryPolicy(appId, generationDateTime, keyAliasMap.get(KeymanagerConstant.KEYALIAS)); + String rootKeyAlias = getRootKeyAlias(appId, timestamp); + CertificateParameters certParams; + if (sanHelper.hasSANappIdAndRefId(appId, refId)) { + Map altNamesMap = keymanagerUtil.getSanValues(appId, refId); + certParams = keymanagerUtil.getCertificateParametersIncludeSAN(request, generationDateTime, expiryDateTime, appId, altNamesMap); + } else { + certParams = keymanagerUtil.getCertificateParameters(request, generationDateTime, expiryDateTime, appId); + } + //keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams); + CertificateInfo certificateInfo = generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams, request, generationDateTime, expiryDateTime, keyAliasMap); + String algName = certificateInfo.getCertificate().getPublicKey().getAlgorithm(); + if (!appId.equals(KeymanagerConstant.ROOT) && !refId.equals(KeyReferenceIdConsts.ED25519_SIGN.name()) && + (algName.equals(KeymanagerConstant.ED25519_KEY_TYPE) || algName.equals(KeymanagerConstant.EDDSA_KEY_TYPE))) { + String encAlias = UUID.randomUUID().toString(); + KeyPairGenerateRequestDto x25519Request = new KeyPairGenerateRequestDto(); + x25519Request.setApplicationId(request.getApplicationId()); + x25519Request.setReferenceId(KeymanagerConstant.X25519_ENC_KEY_REF_ID); + x25519Request.setForce(request.getForce()); + generateAndStoreAsymmetricKey(encAlias, rootKeyAlias, certParams, x25519Request, generationDateTime, expiryDateTime, keyAliasMap); + } + return buildResponseObject(responseObjectType, appId, refId, timestamp, certificateInfo.getAlias(), generationDateTime, + expiryDateTime, request, certificateInfo.getCertificate()); + } private String getRootKeyAlias(String appId, LocalDateTime timestamp) { Map> rootKeyAliasMap = dbHelper.getKeyAliases(rootKeyApplicationId, KeymanagerConstant.EMPTY, timestamp); @@ -712,10 +759,22 @@ private CertificateInfo generateAndStoreAsymmetricKey(String al localDateTimeStamp, request.getReferenceId(), true); x509Cert = certificateInfo.getCertificate(); genAlias = certificateInfo.getAlias(); - } - return new CertificateInfo<>(genAlias, x509Cert); - } - keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams); + } else if (refId.equals(KeyReferenceIdConsts.RSA_2048_SIGN.name())) { + keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams); + x509Cert = (X509Certificate) keyStore.getCertificate(alias); + storeAsymmetricKey(alias, applicationId, refId, keyAliasMap, x509Cert, generationDateTime, expiryDateTime); + } + return new CertificateInfo<>(genAlias, x509Cert); + } + if (!masterKeyAlgorithm.trim().equals(KeymanagerConstant.RSA)) { + if (refId.equals(KeymanagerConstant.X25519_ENC_KEY_REF_ID)) { + keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams, KeymanagerConstant.X25519_KEY_TYPE); + } else { + keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams, eccCurve); + } + } else { + keyStore.generateAndStoreAsymmetricKey(alias, rootKeyAlias, certParams); + } x509Cert = (X509Certificate) keyStore.getCertificate(alias); storeAsymmetricKey(alias, applicationId, refId, keyAliasMap, x509Cert, generationDateTime, expiryDateTime); return new CertificateInfo<>(genAlias, x509Cert); @@ -868,7 +927,11 @@ public KeyPairGenerateResponseDto generateCSR(CSRGenerateRequestDto csrGenReques Object[] keyDetailsArr = getKeyDetails(keyFromDBStore, keyAlias); PrivateKey signPrivateKey = (PrivateKey) keyDetailsArr[0]; X509Certificate x509Cert = (X509Certificate) keyDetailsArr[1]; - + + if (signPrivateKey.getAlgorithm().equals(KeymanagerConstant.X25519_KEY_TYPE) || signPrivateKey.getAlgorithm().equalsIgnoreCase(KeymanagerConstant.XDH_ALGORITHM)) { + throw new KeymanagerServiceException(KeymanagerErrorConstant.X25519_KEY_CSR_NOT_SUPPORTED.getErrorCode(), + KeymanagerErrorConstant.X25519_KEY_CSR_NOT_SUPPORTED.getErrorMessage()); + } LocalDateTime generationDateTime = DateUtils.parseDateToLocalDateTime(x509Cert.getNotBefore()); LocalDateTime expiryDateTime = DateUtils.parseDateToLocalDateTime(x509Cert.getNotAfter()); CertificateParameters certParams = keymanagerUtil.getCertificateParameters(csrGenRequestDto, generationDateTime, expiryDateTime); @@ -945,7 +1008,7 @@ private Object[] getKeyDetails(Optional keyAliasTrustAnchorsCache = null; @@ -304,10 +314,18 @@ public T setMetaData(T entity) { * @return encrypted key */ public byte[] encryptKey(PrivateKey privateKey, PublicKey masterKey) { - SecretKey symmetricKey = keyGenerator.getSymmetricKey(); - byte[] encryptedPrivateKey = cryptoCore.symmetricEncrypt(symmetricKey, privateKey.getEncoded(), null); - byte[] encryptedSymmetricKey = cryptoCore.asymmetricEncrypt(masterKey, symmetricKey.getEncoded()); - return CryptoUtil.combineByteArray(encryptedPrivateKey, encryptedSymmetricKey, keySplitter); + byte[] encryptedSymmetricKey; + byte[] encryptedKey = null; + + if (masterKey.getAlgorithm().equalsIgnoreCase(KeymanagerConstant.RSA)) { + SecretKey symmetricKey = keyGenerator.getSymmetricKey(); + byte[] encryptedPrivateKey = cryptoCore.symmetricEncrypt(symmetricKey, privateKey.getEncoded(), null); + encryptedSymmetricKey = cryptoCore.asymmetricEncrypt(masterKey, symmetricKey.getEncoded()); + encryptedKey = CryptoUtil.combineByteArray(encryptedPrivateKey, encryptedSymmetricKey, keySplitter); + } else { + encryptedKey = ecCryptomanagerService.asymmetricEcEncrypt(masterKey, privateKey.getEncoded(), getEcCurveName(masterKey)); + } + return encryptedKey; } /** @@ -322,17 +340,20 @@ public byte[] decryptKey(byte[] key, PrivateKey privateKey, PublicKey publicKey) } public byte[] decryptKey(byte[] key, PrivateKey privateKey, PublicKey publicKey, String keystoreType) { - - int keyDemiliterIndex = 0; - final int cipherKeyandDataLength = key.length; - final int keySplitterLength = keySplitter.length(); - keyDemiliterIndex = CryptoUtil.getSplitterIndex(key, keyDemiliterIndex, keySplitter); - byte[] encryptedKey = copyOfRange(key, 0, keyDemiliterIndex); - byte[] encryptedData = copyOfRange(key, keyDemiliterIndex + keySplitterLength, cipherKeyandDataLength); - byte[] decryptedSymmetricKey = cryptoCore.asymmetricDecrypt(privateKey, publicKey, encryptedKey, keystoreType); - SecretKey symmetricKey = new SecretKeySpec(decryptedSymmetricKey, 0, decryptedSymmetricKey.length, - symmetricAlgorithmName); - return cryptoCore.symmetricDecrypt(symmetricKey, encryptedData, null); + if (privateKey.getAlgorithm().equalsIgnoreCase(KeymanagerConstant.RSA)) { + int keyDemiliterIndex = 0; + final int cipherKeyandDataLength = key.length; + final int keySplitterLength = keySplitter.length(); + keyDemiliterIndex = CryptoUtil.getSplitterIndex(key, keyDemiliterIndex, keySplitter); + byte[] encryptedKey = copyOfRange(key, 0, keyDemiliterIndex); + byte[] encryptedData = copyOfRange(key, keyDemiliterIndex + keySplitterLength, cipherKeyandDataLength); + byte[] decryptedSymmetricKey = cryptoCore.asymmetricDecrypt(privateKey, publicKey, encryptedKey, keystoreType); + SecretKey symmetricKey = new SecretKeySpec(decryptedSymmetricKey, 0, decryptedSymmetricKey.length, + symmetricAlgorithmName); + return cryptoCore.symmetricDecrypt(symmetricKey, encryptedData, null); + } else { + return ecCryptomanagerService.asymmetricEcDecrypt(privateKey, key, null, getEcCurveName(publicKey)); + } } /** @@ -594,7 +615,10 @@ public String getCSR(PrivateKey privateKey, PublicKey publicKey, CertificatePara ", O=" + certParams.getOrganization() + ", L=" + certParams.getLocation() + ", S=" + certParams.getState() + ", C=" + certParams.getCountry()); ContentSigner contentSigner; - if (privateKey.getAlgorithm().equals(KeymanagerConstant.ED25519_KEY_TYPE)) { + String privateKeyAlgo = privateKey.getAlgorithm(); + if (privateKeyAlgo.equals(KeymanagerConstant.ED25519_KEY_TYPE) || + privateKeyAlgo.equals(KeymanagerConstant.X25519_KEY_TYPE) || + keyAlgorithm.equals(KeymanagerConstant.X25519_KEY_TYPE)) { contentSigner = new JcaContentSignerBuilder(edSignAlgorithm).build(privateKey); } else { contentSigner = new JcaContentSignerBuilder(getSignatureAlgorithm(keyAlgorithm)).setProvider(keyStore.getKeystoreProviderName()).build(privateKey); @@ -614,7 +638,8 @@ private String getSignatureAlgorithm(String keyAlgorithm) { return ecSignAlgorithm; else if (keyAlgorithm.equals(KeymanagerConstant.ED25519_KEY_TYPE) || keyAlgorithm.equals(KeymanagerConstant.ED25519_ALG_OID) || - keyAlgorithm.equals(KeymanagerConstant.EDDSA_KEY_TYPE)) + keyAlgorithm.equals(KeymanagerConstant.EDDSA_KEY_TYPE) || + keyAlgorithm.equals(KeymanagerConstant.X25519_KEY_TYPE)) return edSignAlgorithm; return signAlgorithm; @@ -776,4 +801,28 @@ public void purgeKeyAliasTrustAnchorsCache() { "Purging Key alias Trust Anchors Cache because new key generated or new certificate uploaded."); keyAliasTrustAnchorsCache.expireAt("default", Expiry.NOW); } + + public String getEcCurveName(PublicKey publicKey) { + if (publicKey.getAlgorithm().equals(KeymanagerConstant.ED25519_KEY_TYPE) || + publicKey.getAlgorithm().equals(KeymanagerConstant.EDDSA_KEY_TYPE)) + return KeymanagerConstant.ED25519_KEY_TYPE; + + if (publicKey.getAlgorithm().equals(KeymanagerConstant.X25519_KEY_TYPE)) + return KeymanagerConstant.X25519_KEY_TYPE; + + SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()); + ASN1ObjectIdentifier oid = (ASN1ObjectIdentifier) subjectPublicKeyInfo.getAlgorithm().getParameters(); + String curveName; + if (KeymanagerConstant.EC_SECP256R1_OID.equals(oid.getId())) { + curveName = ECCurves.SECP256R1.name(); + } else if (KeymanagerConstant.EC_SECP256K1_OID.equals(oid.getId())) { + curveName = ECCurves.SECP256K1.name(); + } else { + throw new io.mosip.kernel.core.exception.NoSuchAlgorithmException( + KeymanagerErrorConstant.NOT_SUPPORTED_CURVE_VALUE.getErrorCode(), + KeymanagerErrorConstant.NOT_SUPPORTED_CURVE_VALUE.getErrorMessage() + ); + } + return curveName; + } } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymigrate/service/impl/KeyMigratorServiceImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymigrate/service/impl/KeyMigratorServiceImpl.java index c786c2b2..50191d92 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymigrate/service/impl/KeyMigratorServiceImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/keymigrate/service/impl/KeyMigratorServiceImpl.java @@ -22,6 +22,7 @@ import javax.crypto.NoSuchPaddingException; import javax.crypto.SecretKey; +import io.mosip.kernel.cryptomanager.service.EcCryptomanagerService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Lazy; @@ -88,6 +89,13 @@ public class KeyMigratorServiceImpl implements KeyMigratorService { @Value("${mosip.kernel.zkcrypto.wrap.algorithm-name:AES/ECB/NoPadding}") private String aesECBTransformation; + /** Master Key generation algorithm */ + @Value("${mosip.kernel.keygenerator.asymmetric-algorithm-name:RSA}") + private String keyAlgorithm; + + @Value("${mosip.kernel.keygenerator.ecc-curve-name:SECP256R1}") + private String ecCurveName; + /** * KeymanagerDBHelper instance to handle all DB operations */ @@ -118,6 +126,9 @@ public class KeyMigratorServiceImpl implements KeyMigratorService { @Autowired KeyAliasRepository keyAliasRepository; + @Autowired + EcCryptomanagerService ecCrypto; + @Override public KeyMigrateBaseKeyResponseDto migrateBaseKey(KeyMigrateBaseKeyRequestDto baseKeyMigrateRequest){ LOGGER.info(KeyMigratorConstants.SESSIONID, KeyMigratorConstants.BASE_KEY, @@ -283,7 +294,13 @@ public ZKKeyMigrateCertficateResponseDto getZKTempCertificate() { LocalDateTime expiryDateTime = localDateTimeStamp.plusDays(1); CertificateParameters certParams = keymanagerUtil.getCertificateParameters(KeyMigratorConstants.ZK_CERT_COMMON_NAME, localDateTimeStamp, expiryDateTime); - keyStore.generateAndStoreAsymmetricKey(alias, null, certParams); + + if (keyAlgorithm.equalsIgnoreCase(KeymanagerConstant.RSA)) { + keyStore.generateAndStoreAsymmetricKey(alias, null, certParams); + } else { + keyStore.generateAndStoreAsymmetricKey(alias, null, certParams, ecCurveName); + } + X509Certificate x509Cert = (X509Certificate) keyStore.getCertificate(alias); String certThumbprint = cryptomanagerUtil.getCertificateThumbprintInHex(x509Cert); // Using certThumbprint not generation time because in case more than one migration master key may be @@ -378,18 +395,32 @@ private String getKeyAlias(String keyAppId, String keyRefId, LocalDateTime local } private byte[] encryptRandomKey(byte[] encryptedKeyBytes, Key zkMasterKey, PrivateKey tempPrivateKey, PublicKey tempPublicKey) { - try { - byte[] secretDataBytes = cryptoCore.asymmetricDecrypt(tempPrivateKey, tempPublicKey, encryptedKeyBytes); - Cipher cipher = Cipher.getInstance(aesECBTransformation); - - cipher.init(Cipher.ENCRYPT_MODE, zkMasterKey); - return cipher.doFinal(secretDataBytes, 0, secretDataBytes.length); - } catch(NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException - | IllegalBlockSizeException | BadPaddingException | IllegalArgumentException - | InvalidDataException | io.mosip.kernel.core.crypto.exception.InvalidKeyException e) { - LOGGER.error(KeyMigratorConstants.SESSIONID, KeyMigratorConstants.ZK_KEYS, - KeyMigratorConstants.EMPTY, "Error in encrypting random Key in key migration process.", e); - } + if (tempPublicKey.getAlgorithm().equalsIgnoreCase(KeymanagerConstant.RSA)) { + try { + byte[] secretDataBytes = cryptoCore.asymmetricDecrypt(tempPrivateKey, tempPublicKey, encryptedKeyBytes); + Cipher cipher = Cipher.getInstance(aesECBTransformation); + + cipher.init(Cipher.ENCRYPT_MODE, zkMasterKey); + return cipher.doFinal(secretDataBytes, 0, secretDataBytes.length); + } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException + | IllegalBlockSizeException | BadPaddingException | IllegalArgumentException + | InvalidDataException | io.mosip.kernel.core.crypto.exception.InvalidKeyException e) { + LOGGER.error(KeyMigratorConstants.SESSIONID, KeyMigratorConstants.ZK_KEYS, + KeyMigratorConstants.EMPTY, "Error in encrypting random Key in key migration process.", e); + } + } else { + try { + byte[] secreteDataBytes = ecCrypto.asymmetricEcDecrypt(tempPrivateKey, encryptedKeyBytes, null, keymanagerUtil.getEcCurveName(tempPublicKey)); + Cipher cipher = Cipher.getInstance(aesECBTransformation); + cipher.init(Cipher.ENCRYPT_MODE, zkMasterKey); + return cipher.doFinal(secreteDataBytes, 0, secreteDataBytes.length); + } catch (NoSuchAlgorithmException | InvalidKeyException | NoSuchPaddingException + | IllegalBlockSizeException | BadPaddingException | IllegalArgumentException + | InvalidDataException | io.mosip.kernel.core.crypto.exception.InvalidKeyException e) { + LOGGER.error(KeyMigratorConstants.SESSIONID, KeyMigratorConstants.ZK_KEYS, + KeyMigratorConstants.EMPTY, "Error in encrypting random Key in key migration process.", e); + } + } return null; } diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/constant/SignatureAlgorithmIdentifyEnum.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/constant/SignatureAlgorithmIdentifyEnum.java index 1322e7c8..e788992e 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/constant/SignatureAlgorithmIdentifyEnum.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/constant/SignatureAlgorithmIdentifyEnum.java @@ -1,7 +1,9 @@ package io.mosip.kernel.signature.constant; import io.mosip.kernel.core.exception.IllegalArgumentException; +import io.mosip.kernel.keymanagerservice.constant.ECCurves; import io.mosip.kernel.keymanagerservice.constant.KeyReferenceIdConsts; +import io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant; import io.mosip.kernel.keymanagerservice.constant.KeymanagerErrorConstant; import lombok.Getter; import org.jose4j.jws.AlgorithmIdentifiers; @@ -10,9 +12,14 @@ public enum SignatureAlgorithmIdentifyEnum { BLANK(SignatureConstant.BLANK, AlgorithmIdentifiers.RSA_USING_SHA256), REF(SignatureConstant.REF_ID_SIGN_CONST, AlgorithmIdentifiers.RSA_USING_SHA256), - SECP256K1(KeyReferenceIdConsts.EC_SECP256K1_SIGN.name(), AlgorithmIdentifiers.ECDSA_USING_SECP256K1_CURVE_AND_SHA256), - SECP256R1(KeyReferenceIdConsts.EC_SECP256R1_SIGN.name(), AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256), - ED25519(KeyReferenceIdConsts.ED25519_SIGN.name(), AlgorithmIdentifiers.EDDSA); + SECP256K1_SIGN(KeyReferenceIdConsts.EC_SECP256K1_SIGN.name(), AlgorithmIdentifiers.ECDSA_USING_SECP256K1_CURVE_AND_SHA256), + SECP256R1_SIGN(KeyReferenceIdConsts.EC_SECP256R1_SIGN.name(), AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256), + ED25519(KeyReferenceIdConsts.ED25519_SIGN.name(), AlgorithmIdentifiers.EDDSA), + RSA(KeymanagerConstant.RSA, AlgorithmIdentifiers.RSA_USING_SHA256), + ES256(AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256, AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256), + ES256K(AlgorithmIdentifiers.ECDSA_USING_SECP256K1_CURVE_AND_SHA256, AlgorithmIdentifiers.ECDSA_USING_SECP256K1_CURVE_AND_SHA256), + EDDSA(AlgorithmIdentifiers.EDDSA, AlgorithmIdentifiers.EDDSA), + RS256(AlgorithmIdentifiers.RSA_USING_SHA256, AlgorithmIdentifiers.RSA_USING_SHA256); private final String referenceId; private final String algoIdent; diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/constant/SignatureProviderEnum.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/constant/SignatureProviderEnum.java index ac86ba85..7a225c52 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/constant/SignatureProviderEnum.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/constant/SignatureProviderEnum.java @@ -1,6 +1,7 @@ package io.mosip.kernel.signature.constant; import io.mosip.kernel.core.exception.IllegalArgumentException; +import io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant; import io.mosip.kernel.signature.service.SignatureProvider; import io.mosip.kernel.signature.service.impl.EC256SignatureProviderImpl; import io.mosip.kernel.signature.service.impl.Ed25519SignatureProviderImpl; @@ -14,7 +15,10 @@ public enum SignatureProviderEnum { RS256(SignatureConstant.JWS_RS256_SIGN_ALGO_CONST, new RS256SignatureProviderImpl()), ES256(SignatureConstant.JWS_ES256_SIGN_ALGO_CONST, new EC256SignatureProviderImpl()), ES256K(SignatureConstant.JWS_ES256K_SIGN_ALGO_CONST, new EC256SignatureProviderImpl()), - EDDSA(SignatureConstant.JWS_EDDSA_SIGN_ALGO_CONST, new Ed25519SignatureProviderImpl()); + EDDSA(SignatureConstant.JWS_EDDSA_SIGN_ALGO_CONST, new Ed25519SignatureProviderImpl()), + ECDSA(KeymanagerConstant.EC_KEY_TYPE, new EC256SignatureProviderImpl()), + ED25519(KeymanagerConstant.ED25519_KEY_TYPE, new Ed25519SignatureProviderImpl()), + RSA(KeymanagerConstant.RSA, new RS256SignatureProviderImpl()),; private final String algo; private final SignatureProvider provider; diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/service/impl/CoseSignatureServiceImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/service/impl/CoseSignatureServiceImpl.java index 94742534..eb1cb051 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/service/impl/CoseSignatureServiceImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/service/impl/CoseSignatureServiceImpl.java @@ -137,8 +137,11 @@ public CoseSignResponseDto coseSign1(CoseSignRequestDto coseSignRequestDto) { private String signCose1(byte[] cosePayload, SignatureCertificate certificateResponse, String referenceId, CoseSignRequestDto requestDto, boolean isCwt) { try { + String algStr = SignatureUtil.isDataValid(requestDto.getAlgorithm()) + ? requestDto.getAlgorithm() + : SignatureUtil.getAlgorithmString(certificateResponse.getCertificateEntry().getChain()[0], referenceId); String algorithm = (requestDto.getAlgorithm() == null || requestDto.getAlgorithm().isEmpty()) ? - SignatureAlgorithmIdentifyEnum.getAlgorithmIdentifier(referenceId) : requestDto.getAlgorithm(); + SignatureAlgorithmIdentifyEnum.getAlgorithmIdentifier(algStr) : requestDto.getAlgorithm(); COSEProtectedHeaderBuilder protectedHeaderBuilder = coseHeaderBuilder.buildProtectedHeader(certificateResponse, requestDto, getCoseAlgorithm(algorithm), signatureUtil); COSEUnprotectedHeaderBuilder unprotectedHeaderBuilder = coseHeaderBuilder.buildUnprotectedHeader(certificateResponse, requestDto, signatureUtil); String keyId = getKeyId(kidPrepend, certificateResponse, requestDto, includeKeyId); diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/service/impl/SignatureServiceImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/service/impl/SignatureServiceImpl.java index 6a0afa2e..a8729703 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/service/impl/SignatureServiceImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/service/impl/SignatureServiceImpl.java @@ -120,6 +120,9 @@ public class SignatureServiceImpl implements SignatureService, SignatureServicev @Value("${mosip.kernel.keymanager.signature.kid.prepend:}") private String kidPrepend; + @Value("${mosip.sign-certificate-refid:SIGN}") + private String certificateSignRefID; + /** * Utility to generate Metadata */ @@ -328,8 +331,10 @@ private String sign(String dataToSign, SignatureCertificate certificateResponse, if (includeKeyId && Objects.nonNull(keyId)) jwSign.setKeyIdHeaderValue(kidPrefix.concat(keyId)); + String algoString = (referenceId.equals(KeymanagerConstant.EMPTY) || referenceId.equals(certificateSignRefID)) ? + SignatureUtil.getJwtSignAlgorithm(x509Certificate) : SignatureAlgorithmIdentifyEnum.getAlgorithmIdentifier(referenceId); + jwSign.setPayload(dataToSign); - String algoString = SignatureAlgorithmIdentifyEnum.getAlgorithmIdentifier(referenceId); if (!KeyReferenceIdConsts.ED25519_SIGN.name().equals(referenceId)) { ProviderContext provContext = new ProviderContext(); provContext.getSuppliedKeyProviderContext().setSignatureProvider(ecKeyStore.getKeystoreProviderName()); @@ -578,13 +583,18 @@ public JWTSignatureResponseDto jwsSign(JWSSignatureRequestDto jwsSignRequestDto) String certificateUrl = SignatureUtil.isDataValid( jwsSignRequestDto.getCertificateUrl()) ? jwsSignRequestDto.getCertificateUrl(): null; boolean b64JWSHeaderParam = SignatureUtil.isIncludeAttrsValid(jwsSignRequestDto.getB64JWSHeaderParam()); - String signAlgorithm = (jwsSignRequestDto.getSignAlgorithm() == null || jwsSignRequestDto.getSignAlgorithm().isBlank()) ? - SignatureUtil.getSignAlgorithm(referenceId) : jwsSignRequestDto.getSignAlgorithm(); - +// String signAlgorithm = (jwsSignRequestDto.getSignAlgorithm() == null || jwsSignRequestDto.getSignAlgorithm().isBlank()) ? +// SignatureUtil.getSignAlgorithm(referenceId) : jwsSignRequestDto.getSignAlgorithm(); + SignatureCertificate certificateResponse = keymanagerService.getSignatureCertificate(applicationId, Optional.of(referenceId), timestamp); keymanagerUtil.isCertificateValid(certificateResponse.getCertificateEntry(), DateUtils.parseUTCToDate(timestamp)); + // Use request's sign algorithm; otherwise derive from the private key + String signAlgorithm = (jwsSignRequestDto.getSignAlgorithm() == null || jwsSignRequestDto.getSignAlgorithm().isBlank()) + ? SignatureUtil.getJwtSignAlgorithm(certificateResponse.getCertificateEntry().getChain()[0]) + : jwsSignRequestDto.getSignAlgorithm(); + PrivateKey privateKey = certificateResponse.getCertificateEntry().getPrivateKey(); X509Certificate x509Certificate = certificateResponse.getCertificateEntry().getChain()[0]; String providerName = certificateResponse.getProviderName(); @@ -663,13 +673,16 @@ public SignResponseDto signv2(SignRequestDtoV2 signatureReq) { applicationId = signApplicationid; referenceId = signRefid; } - String signAlgorithm = SignatureUtil.isDataValid(signatureReq.getSignAlgorithm()) ? - signatureReq.getSignAlgorithm() : SignatureConstant.JWS_PS256_SIGN_ALGO_CONST; +// String signAlgorithm = SignatureUtil.isDataValid(signatureReq.getSignAlgorithm()) ? +// signatureReq.getSignAlgorithm() : SignatureConstant.JWS_PS256_SIGN_ALGO_CONST; SignatureCertificate certificateResponse = keymanagerService.getSignatureCertificate(applicationId, Optional.of(referenceId), timestamp); keymanagerUtil.isCertificateValid(certificateResponse.getCertificateEntry(), DateUtils.parseUTCToDate(timestamp)); + // Use request's sign algorithm; otherwise derive from the private key + String signAlgorithm = SignatureUtil.isDataValid(signatureReq.getSignAlgorithm()) + ? signatureReq.getSignAlgorithm() : certificateResponse.getCertificateEntry().getPrivateKey().getAlgorithm(); PrivateKey privateKey = certificateResponse.getCertificateEntry().getPrivateKey(); certificateResponse.getCertificateEntry().getChain(); String providerName = certificateResponse.getProviderName(); @@ -724,13 +737,16 @@ public SignResponseDtoV2 rawSign(SignRequestDtoV2 signatureReq) { applicationId = signApplicationid; referenceId = signRefid; } - String signAlgorithm = SignatureUtil.isDataValid(signatureReq.getSignAlgorithm()) ? - signatureReq.getSignAlgorithm() : SignatureConstant.JWS_PS256_SIGN_ALGO_CONST; +// String signAlgorithm = SignatureUtil.isDataValid(signatureReq.getSignAlgorithm()) ? +// signatureReq.getSignAlgorithm() : SignatureConstant.JWS_PS256_SIGN_ALGO_CONST; SignatureCertificate certificateResponse = keymanagerService.getSignatureCertificate(applicationId, Optional.of(referenceId), timestamp); keymanagerUtil.isCertificateValid(certificateResponse.getCertificateEntry(), DateUtils.parseUTCToDate(timestamp)); + String signAlgorithm = SignatureUtil.isDataValid(signatureReq.getSignAlgorithm()) + ? signatureReq.getSignAlgorithm() + : certificateResponse.getCertificateEntry().getPrivateKey().getAlgorithm(); PrivateKey privateKey = certificateResponse.getCertificateEntry().getPrivateKey(); certificateResponse.getCertificateEntry().getChain(); String providerName = certificateResponse.getProviderName(); @@ -875,7 +891,9 @@ private String signV2(String dataToSign, SignatureCertificate certificateRespons } jwSign.setPayload(dataToSign); - String algoString = SignatureAlgorithmIdentifyEnum.getAlgorithmIdentifier(referenceId); + String algoString = (referenceId.equals(KeymanagerConstant.EMPTY) || referenceId.equals(certificateSignRefID)) + ? SignatureUtil.getJwtSignAlgorithm(x509Certificate) + : SignatureAlgorithmIdentifyEnum.getAlgorithmIdentifier(referenceId); if (!KeyReferenceIdConsts.ED25519_SIGN.name().equals(referenceId)) { ProviderContext provContext = new ProviderContext(); provContext.getSuppliedKeyProviderContext().setSignatureProvider(ecKeyStore.getKeystoreProviderName()); @@ -955,13 +973,16 @@ public JWTSignatureResponseDto jwsSignV2(JWSSignatureRequestDtoV2 jwsSignRequest String certificateUrl = SignatureUtil.isDataValid( jwsSignRequestDto.getCertificateUrl()) ? jwsSignRequestDto.getCertificateUrl(): null; boolean b64JWSHeaderParam = SignatureUtil.isIncludeAttrsValid(jwsSignRequestDto.getB64JWSHeaderParam()); - String signAlgorithm = (jwsSignRequestDto.getSignAlgorithm() == null || jwsSignRequestDto.getSignAlgorithm().isBlank()) ? - SignatureUtil.getSignAlgorithm(referenceId) : jwsSignRequestDto.getSignAlgorithm(); +// String signAlgorithm = (jwsSignRequestDto.getSignAlgorithm() == null || jwsSignRequestDto.getSignAlgorithm().isBlank()) ? +// SignatureUtil.getSignAlgorithm(referenceId) : jwsSignRequestDto.getSignAlgorithm(); SignatureCertificate certificateResponse = keymanagerService.getSignatureCertificate(applicationId, Optional.of(referenceId), timestamp); keymanagerUtil.isCertificateValid(certificateResponse.getCertificateEntry(), DateUtils.parseUTCToDate(timestamp)); + String signAlgorithm = (jwsSignRequestDto.getSignAlgorithm() == null || jwsSignRequestDto.getSignAlgorithm().isBlank()) + ? SignatureUtil.getJwtSignAlgorithm(certificateResponse.getCertificateEntry().getChain()[0]) + : jwsSignRequestDto.getSignAlgorithm(); PrivateKey privateKey = certificateResponse.getCertificateEntry().getPrivateKey(); X509Certificate x509Certificate = certificateResponse.getCertificateEntry().getChain()[0]; String providerName = certificateResponse.getProviderName(); diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/util/SignatureUtil.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/util/SignatureUtil.java index aaf4872e..c3f48a31 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/util/SignatureUtil.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/signature/util/SignatureUtil.java @@ -5,6 +5,7 @@ import java.net.URISyntaxException; import java.nio.charset.StandardCharsets; import java.security.NoSuchAlgorithmException; +import java.security.PublicKey; import java.security.cert.Certificate; import java.security.cert.CertificateEncodingException; import java.security.cert.CertificateExpiredException; @@ -28,6 +29,8 @@ import com.nimbusds.jose.util.Base64; import com.nimbusds.jose.util.Base64URL; +import io.mosip.kernel.keymanagerservice.constant.KeyReferenceIdConsts; +import io.mosip.kernel.keymanagerservice.constant.KeymanagerConstant; import io.mosip.kernel.keymanagerservice.constant.KeymanagerErrorConstant; import io.mosip.kernel.keymanagerservice.exception.KeymanagerServiceException; import io.mosip.kernel.keymanagerservice.util.KeymanagerUtil; @@ -46,6 +49,9 @@ import io.mosip.kernel.core.util.HMACUtils2; import io.mosip.kernel.keymanagerservice.logger.KeymanagerLogger; import io.mosip.kernel.signature.constant.SignatureConstant; +import org.bouncycastle.asn1.ASN1ObjectIdentifier; +import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo; +import org.jose4j.jws.AlgorithmIdentifiers; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Component; @@ -598,4 +604,36 @@ public List getCertificateTrustChain(X509Certificate x509 return certificateChain; } + + public static String getJwtSignAlgorithm(X509Certificate x509Certificate) { + PublicKey publicKey = x509Certificate.getPublicKey(); + String algorithm = publicKey.getAlgorithm(); + + if (KeymanagerConstant.EC_KEY_TYPE.equalsIgnoreCase(algorithm)) { + SubjectPublicKeyInfo subjectPublicKeyInfo = SubjectPublicKeyInfo.getInstance(publicKey.getEncoded()); + ASN1ObjectIdentifier curveOid = (ASN1ObjectIdentifier) subjectPublicKeyInfo.getAlgorithm().getParameters(); + + return mapCurveOidToCurveName(curveOid.getId()); + } else if (KeymanagerConstant.ED25519_KEY_TYPE.equalsIgnoreCase(algorithm) || KeymanagerConstant.EDDSA_KEY_TYPE.equals(algorithm)) { + return AlgorithmIdentifiers.EDDSA; + } + return AlgorithmIdentifiers.RSA_USING_SHA256; + } + + private static String mapCurveOidToCurveName(String oid) { + return switch (oid) { + case KeymanagerConstant.EC_SECP256R1_OID -> AlgorithmIdentifiers.ECDSA_USING_P256_CURVE_AND_SHA256; + case KeymanagerConstant.EC_SECP256K1_OID -> AlgorithmIdentifiers.ECDSA_USING_SECP256K1_CURVE_AND_SHA256; + default -> throw new io.mosip.kernel.core.exception.NoSuchAlgorithmException(KeymanagerErrorConstant.NOT_SUPPORTED_CURVE_VALUE.getErrorCode(), + KeymanagerErrorConstant.NOT_SUPPORTED_CURVE_VALUE.getErrorMessage()); + }; + } + + public static String getAlgorithmString(X509Certificate x509Certificate, String refId) { + if (isDataValid(refId) && + (Arrays.stream(KeyReferenceIdConsts.values()).anyMatch(rId -> rId.name().equals(refId)))) + return refId; + else + return getJwtSignAlgorithm(x509Certificate); + } } \ No newline at end of file diff --git a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/zkcryptoservice/service/impl/ZKCryptoManagerServiceImpl.java b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/zkcryptoservice/service/impl/ZKCryptoManagerServiceImpl.java index aec7adb5..d5c22946 100644 --- a/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/zkcryptoservice/service/impl/ZKCryptoManagerServiceImpl.java +++ b/kernel/kernel-keymanager-service/src/main/java/io/mosip/kernel/zkcryptoservice/service/impl/ZKCryptoManagerServiceImpl.java @@ -30,6 +30,8 @@ import javax.crypto.spec.GCMParameterSpec; import javax.crypto.spec.SecretKeySpec; +import io.mosip.kernel.cryptomanager.service.EcCryptomanagerService; +import io.mosip.kernel.keymanagerservice.repository.KeyAliasRepository; import org.bouncycastle.util.encoders.Hex; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; @@ -136,6 +138,12 @@ public class ZKCryptoManagerServiceImpl implements ZKCryptoManagerService, Initi @Autowired private CryptoCoreSpec cryptoCore; + @Autowired + EcCryptomanagerService ecCryptomanagerService; + + @Autowired + KeyAliasRepository keyAliasRepository; + @Override public void afterPropertiesSet() throws Exception { // temporary fix to resolve issue occurring for first time(softhsm)/third time(real hsm) symmetric key retrival from HSM. @@ -392,7 +400,8 @@ private String encryptRandomKey(Key secretRandomKey) { String certificateData = dbKeyStore.get().getCertificateData(); X509Certificate x509Cert = (X509Certificate) keymanagerUtil.convertToCertificate(certificateData); PublicKey publicKey = x509Cert.getPublicKey(); - byte[] encryptedRandomKey = cryptoCore.asymmetricEncrypt(publicKey, secretRandomKey.getEncoded()); + byte[] encryptedRandomKey = publicKey.getAlgorithm().equalsIgnoreCase(KeymanagerConstant.RSA) ? cryptoCore.asymmetricEncrypt(publicKey, secretRandomKey.getEncoded()) : + ecCryptomanagerService.asymmetricEcEncrypt(publicKey, secretRandomKey.getEncoded(), keymanagerUtil.getEcCurveName(publicKey)); byte[] certThumbprint = cryptomanagerUtil.getCertificateThumbprint(x509Cert); byte[] concatedData = cryptomanagerUtil.concatCertThumbprint(certThumbprint, encryptedRandomKey); encryptedRandomKeyList.add(CryptoUtil.encodeToURLSafeBase64(concatedData)); @@ -416,29 +425,46 @@ public ReEncryptRandomKeyResponseDto zkReEncryptRandomKey(String encryptedKey){ Map> keyAliasMap = dbHelper.getKeyAliases(pubKeyApplicationId, pubKeyReferenceId, localDateTimeStamp); keyAliases = keyAliasMap.get(KeymanagerConstant.KEYALIAS); } + + String kyAlias = null; String encRandomKey = null; + byte[] encRandomKeyBytes = null; + String certificateThumbprint = null; for (String encKey : encryptedKeyArr) { byte[] encKeyBytes = CryptoUtil.decodeURLSafeBase64(encKey); byte[] certThumbprint = Arrays.copyOfRange(encKeyBytes, 0, CryptomanagerConstant.THUMBPRINT_LENGTH); + encRandomKeyBytes = Arrays.copyOfRange(encKeyBytes, CryptomanagerConstant.THUMBPRINT_LENGTH, encKeyBytes.length); String certThumbprintHex = Hex.toHexString(certThumbprint).toUpperCase(); Optional keyAlias = keyAliases.stream().filter(alias -> alias.getCertThumbprint().equals(certThumbprintHex)) .findFirst(); + kyAlias = keyAlias.map(KeyAlias::getAlias).orElse(null); + certificateThumbprint = certThumbprintHex; if (!keyAlias.isPresent()) { continue; } encRandomKey = encKey; break; } + + Optional dbKeyStore = keyStoreRepository.findByAlias(kyAlias); + Optional keyAliasObj = keyAliasRepository.findById(Objects.requireNonNull(kyAlias)); + String certificateData = dbKeyStore.get().getCertificateData(); + X509Certificate x509Cert = (X509Certificate) keymanagerUtil.convertToCertificate(certificateData); + if (Objects.isNull(encRandomKey)) { LOGGER.error(ZKCryptoManagerConstants.SESSIONID, ZKCryptoManagerConstants.RE_ENCRYPT_RANDOM_KEY, ZKCryptoManagerConstants.RE_ENCRYPT_RANDOM_KEY, "Thumbprint matching key not found in DB."); throw new ZKCryptoException(ZKCryptoErrorConstants.INVALID_ENCRYPTED_RANDOM_KEY.getErrorCode(), ZKCryptoErrorConstants.INVALID_ENCRYPTED_RANDOM_KEY.getErrorMessage()); } - SymmetricKeyRequestDto symmetricKeyRequestDto = new SymmetricKeyRequestDto( - pubKeyApplicationId, localDateTimeStamp, pubKeyReferenceId, encRandomKey, true); - String randomKey = keyManagerService.decryptSymmetricKey(symmetricKeyRequestDto).getSymmetricKey(); + + PrivateKey privateKey = (PrivateKey) cryptomanagerUtil.getEncryptedPrivateKey(keyAliasObj.get().getApplicationId(), Optional.ofNullable(keyAliasObj.get().getReferenceId()), certificateThumbprint)[0]; + SymmetricKeyRequestDto symmetricKeyRequestDto = new SymmetricKeyRequestDto(pubKeyApplicationId, localDateTimeStamp, pubKeyReferenceId, encRandomKey, true); + + String randomKey = x509Cert.getPublicKey().getAlgorithm().equalsIgnoreCase(KeymanagerConstant.RSA) ? keyManagerService.decryptSymmetricKey(symmetricKeyRequestDto).getSymmetricKey() : + CryptoUtil.encodeToURLSafeBase64(ecCryptomanagerService.asymmetricEcDecrypt(privateKey, encRandomKeyBytes, null, keymanagerUtil.getEcCurveName(x509Cert.getPublicKey()))); + String encryptedRandomKey = getEncryptedRandomKey(Base64.getEncoder().encodeToString(CryptoUtil.decodeURLSafeBase64(randomKey))); ReEncryptRandomKeyResponseDto responseDto = new ReEncryptRandomKeyResponseDto(); responseDto.setEncryptedKey(encryptedRandomKey); diff --git a/kernel/keys-migrator/src/main/java/io/mosip/kernel/migrate/impl/BaseKeysMigrator.java b/kernel/keys-migrator/src/main/java/io/mosip/kernel/migrate/impl/BaseKeysMigrator.java index 85cb26cf..eeef9fcc 100755 --- a/kernel/keys-migrator/src/main/java/io/mosip/kernel/migrate/impl/BaseKeysMigrator.java +++ b/kernel/keys-migrator/src/main/java/io/mosip/kernel/migrate/impl/BaseKeysMigrator.java @@ -21,6 +21,7 @@ import java.util.stream.Collectors; import java.util.stream.Stream; +import io.mosip.kernel.cryptomanager.service.EcCryptomanagerService; import jakarta.annotation.PostConstruct; import javax.crypto.BadPaddingException; import javax.crypto.Cipher; @@ -166,6 +167,9 @@ public class BaseKeysMigrator { @Autowired private CryptoCoreSpec cryptoCore; + + @Autowired + EcCryptomanagerService ecCrypto; String token = ""; @@ -249,7 +253,8 @@ private void reEncryptAndUpload(PrivateKeyEntry masterKeyEntry, String masterKey try { byte[] decryptedPrivateKey = keymanagerUtil.decryptKey(CryptoUtil.decodeBase64(baseKey.getPrivateKey()), masterKey, masterPublicKey); - KeyFactory keyFactory = KeyFactory.getInstance(KeymanagerConstant.RSA); + PublicKey baseKeyPublicKey = keymanagerUtil.convertToCertificate(baseKey.getCertificateData()).getPublicKey(); + KeyFactory keyFactory = KeyFactory.getInstance(baseKeyPublicKey.getAlgorithm()); PrivateKey privateKey = keyFactory.generatePrivate(new PKCS8EncodedKeySpec(decryptedPrivateKey)); String encryptedPrivateKey = CryptoUtil.encodeBase64(keymanagerUtil.encryptKey(privateKey, newKeyMgrPubKey)); Optional keyAliasObj = keyAliasRepository.findById(baseKeyUuid); @@ -353,7 +358,8 @@ private void migrateZKRandomKeys() { int keyIndex = zkKey.getId(); String encryptedKey = zkKey.getKey(); byte[] decryptedZKKey = decryptRandomKey(encryptedKey, zkMasterKey); - byte[] encryptedRandomKey = cryptoCore.asymmetricEncrypt(zkPublicKey, decryptedZKKey); + byte[] encryptedRandomKey = zkPublicKey.getAlgorithm().equalsIgnoreCase(KeymanagerConstant.RSA) ? cryptoCore.asymmetricEncrypt(zkPublicKey, decryptedZKKey) : + ecCrypto.asymmetricEcEncrypt(zkPublicKey, decryptedZKKey, keymanagerUtil.getEcCurveName(zkPublicKey)); String encodedKey = CryptoUtil.encodeBase64(encryptedRandomKey); ZKKeyDataDto keyDataDto = new ZKKeyDataDto(); keyDataDto.setKeyIndex(keyIndex);