Добрый день! Есть необходимость использовать подпись CAdES-BES, сгенерированную с помощью закрытого ключа, чтобы ее можно было верифицировать только с помощью соответствующего открытого ключа.
Была реализована следующая логика генерации и проверки подписи, но столкнулись с проблемой, что метод CAdESSignature.verify игнорирует переданную в него цепочку сертификатов и успешно валидирует подпись вне зависимости от того, какой открытый ключ передан и работает даже если вместо цепочки передать null.
Вопрос, реализована ли в библиотеке JCP нужная нам проверка, которая бы валидировала подпись успешно, только соответствующим открытым ключом?
override fun sign(source: String): String {
try {
val data = source.toByteArray(Charset.forName("UTF-8"))
val signerPrivateKey = privateKey as PrivateKey
val signerCert = openCertificates["OUR_PUBLIC_KEY"]!!
// Создание цепочки сертификатов подписанта из одного сертификата.
val signerCertificateChain = Collections.singletonList(signerCert)
// Создание подписи открепленного типа (detached), о чем говорит параметр true.
val cadesSignature = CAdESSignature(true)
// Добавление сертификата подписи в подпись открепленного типа.
val certHolderList: MutableList<X509CertificateHolder> = mutableListOf()
certHolderList.add(X509CertificateHolder(signerCert.encoded))
val certStore = CollectionStore(certHolderList)
cadesSignature.setCertificateStore(certStore)
// Добавление подписанта CAdES-BES.
cadesSignature.addSigner(
JCP.PROVIDER_NAME, // Имя провайдера, который будет использоваться для создания подписи.
null, // Идентификатор алгоритма хэширования, который будет использоваться для вычисления дайджеста (хэша) подписываемых данных.
JCP.GOST_SIGN_2012_512_NAME, // Идентификатор алгоритма подписи, который будет использоваться для создания электронной подписи.
signerPrivateKey, // Приватный ключ подписанта.
signerCertificateChain, // Цепочка сертификатов подписанта.
CAdESType.CAdES_BES, // Тип CAdES подписи.
null, // Адрес TSA службы.
false, // Заверяющая ли подпись.
null, // Таблица подписанных аттрибутов для добавления в подпись.
null, // Таблица неподписанных аттрибутов для добавления в подпись.
null, // CRL (списков отзыва сертификатов), связанных с подписью.
false // Добавить ли цепочку подписанта в подпись.
)
// Поток для получения сформированной подписи.
val outSignatureStream = ByteArrayOutputStream()
cadesSignature.open(outSignatureStream)
// Подпись данных.
cadesSignature.update(data)
cadesSignature.close()
outSignatureStream.close()
// CAdES-BES подпись.
val signature = outSignatureStream.toByteArray()
return Base64.getEncoder().encodeToString(signature)
} catch (e: Exception) {
logger.error("Error signing data", e)
throw Exception(e.message ?: "Ошибка при подписании данных")
}
}
override fun verify(data: String, signatureBase64: String, publicKeyAlias: String) =
try {
val source: ByteArray = data.toByteArray(Charset.forName("UTF-8"))
val byteSign = Base64.getDecoder().decode(signatureBase64)
val openCert = openCertificates[publicKeyAlias]
?: throw IllegalArgumentException("Не найден открытый ключ для systemId $publicKeyAlias")
//делаем цепочку сертификатов из одного открытого ключа
val signerCertificateChain = setOf(openCert)
val cadesSignature = CAdESSignature(
byteSign, source,
CAdESType.CAdES_BES, false
)
// cadesSignature.verify(null) //так пробовал, ничего не меняется
cadesSignature.verify(signerCertificateChain)
Pair(true, openCert.serialNumber.toString(16).uppercase())
} catch (e: Exception) {
logger.error("Произошла ошибка при проверке подписи запроса. Msg: ", e)
Pair(false, null)
}