logo Обзор КриптоПро NGate для защищённого доступа к корпоративным ресурсам
Добро пожаловать, Гость! Чтобы использовать все возможности Вход или Регистрация.

Уведомление

Icon
Error

Опции
К последнему сообщению К первому непрочитанному
Offline rmussalimov  
#1 Оставлено : 9 декабря 2019 г. 9:55:35(UTC)
rmussalimov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 05.08.2019(UTC)
Сообщений: 48

Сказал(а) «Спасибо»: 4 раз
Добрый день!

Имеется КриптоПро JCP и CSP.

В CSP существует добавлен контейнер с алиасом внутри которого находится личный сертификат и приватный ключ.

Проблема в том, что сертификат только один и доверия к нему нет.

Соответственно, во время создания открепленной подписи добавляется только один сертификат.

Как мы можем импортировать еще один сертификат, чтобы когда мы вызываем нативный java метод

Цитата:
keyStore.getCertificateChain(String alias)


По данному алиасу находились как и сертификат подписанта, так и выщестоящие сертификаты для того, чтобы позже добавить их в подпись

Заранее спасибо

Отредактировано пользователем 9 декабря 2019 г. 9:56:08(UTC)  | Причина: Не указана

Offline Евгений Афанасьев  
#2 Оставлено : 9 декабря 2019 г. 11:01:43(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 2,949
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 14 раз
Поблагодарили: 441 раз в 431 постах
Здравствуйте.
Автор: rmussalimov Перейти к цитате


Имеется КриптоПро JCP и CSP.

В CSP существует добавлен контейнер с алиасом внутри которого находится личный сертификат и приватный ключ.

Проблема в том, что сертификат только один и доверия к нему нет.

Соответственно, во время создания открепленной подписи добавляется только один сертификат.

Как мы можем импортировать еще один сертификат, чтобы когда мы вызываем нативный java метод

Цитата:
keyStore.getCertificateChain(String alias)


По данному алиасу находились как и сертификат подписанта, так и выщестоящие сертификаты для того, чтобы позже добавить их в подпись

Заранее спасибо

До того, как сертификат(ы) попал(и) в контейнер, это можно сделать, получив в УЦ, который выпустил сертификат подписи, всю цепочку в формате p7b и установив еще в контейнер (в панели управления JCP или программно с помощью keyStore.setCertificateEntry(alias, certs[])).
Если контейнер уже есть и в нем один сертификат подписи, а нужна вся цепочка, то остается один путь: построить ее. На форуме это уже неоднократно описывалось, можно поискать по слову enableAIAcaIssuers.
Как построить цепочку, можно увидеть в примере CRLValidateCert в userSamples в samples-sources.jar в дистрибутиве jcp.
Обязательным является список доверенных корневых и target-сертификат (для которого строим цепочку, сертификат подписи). Все некорневые сертификаты можно поместить в список и передать в параметры в addCertStore. Если в сертификате подписи есть ссылки на промежуточный сертификат и есть доступ в сеть, то этот сертификат (как и другие, кроме корневого) может быть скачан, если включена настройка:
Код:

System.setProperty("com.sun.security.enableAIAcaIssuers", "true");
System.setProperty("ru.CryptoPro.reprov.enableAIAcaIssuers", "true");

Бывает, что ссылок (или/и доступа) нет, тогда промежуточные придется качать и хранить отдельно и передавать их в addCertStore.

Отредактировано пользователем 9 декабря 2019 г. 11:03:00(UTC)  | Причина: Не указана

Техническую поддержку оказываем тут
Наша база знаний
Offline rmussalimov  
#3 Оставлено : 9 декабря 2019 г. 11:21:33(UTC)
rmussalimov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 05.08.2019(UTC)
Сообщений: 48

Сказал(а) «Спасибо»: 4 раз
А возможно добавить сразу их в keyStore java, а потом вызывать метод keyStore.getCertificateChain(String alias) и в нем сразу будут все сертификаты? Т.е. нужно в keyStore JCP "HDImageStore" добавить сертификат с тем же алиасом, но без контейнера, т.к. нет приватного ключа
Offline two_oceans  
#4 Оставлено : 9 декабря 2019 г. 12:37:36(UTC)
two_oceans

Статус: Эксперт

Группы: Участники
Зарегистрирован: 05.03.2015(UTC)
Сообщений: 825
Российская Федерация
Откуда: Иркутская область

Сказал(а) «Спасибо»: 52 раз
Поблагодарили: 175 раз в 165 постах
del

Отредактировано пользователем 10 декабря 2019 г. 4:38:00(UTC)  | Причина: Не указана

Offline Евгений Афанасьев  
#5 Оставлено : 9 декабря 2019 г. 13:16:32(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 2,949
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 14 раз
Поблагодарили: 441 раз в 431 постах
Автор: rmussalimov Перейти к цитате
А возможно добавить сразу их в keyStore java, а потом вызывать метод keyStore.getCertificateChain(String alias) и в нем сразу будут все сертификаты? Т.е. нужно в keyStore JCP "HDImageStore" добавить сертификат с тем же алиасом, но без контейнера, т.к. нет приватного ключа

Да, если построить цепочку и с помощью keyStore.setCertificateEntry добавить цепочку в контейнер. Тогда в расширения в контейнере попадут промежуточные и корневой сертификаты. После этого keyStore.getCertificateChain() станет возвращать каждый раз цепочку.

Техническую поддержку оказываем тут
Наша база знаний
Offline rmussalimov  
#6 Оставлено : 10 декабря 2019 г. 9:54:26(UTC)
rmussalimov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 05.08.2019(UTC)
Сообщений: 48

Сказал(а) «Спасибо»: 4 раз
Спасибо большое за ответ.

Выяснилось, что у нас очень много "движущихся частей", поэтому менять то, что возвращает keyStore довольно опасно.

Необходимо каким-то другим образом генерировать pkcs7 подпись таким образом, чтобы внутри была цепочка. В итоге модифицировал метод из CMS_samples.CMS#CMSSign(byte[],
* PrivateKey, Certificate, boolean


Теперь он выглядит так:

Цитата:
/**
* Функция формирования простой отсоединенной подписи формата PKCS#7
* по хешу сообщения.
* Пример подписи взят из {@link CMS_samples.CMS#CMSSign(byte[],
* PrivateKey, Certificate, boolean)}.
*
* @param data Данные для подписи.
* @param privateKey Закрытый ключ для создания ЭЦП.
* @param certificate Сертификат подписи.
* @param chainCertificates Цепочка сертификатов для включения в подпись.
* @return ЭЦП.
* @throws Exception
*/
public static byte[] createPKCS7(byte[] data, PrivateKey privateKey,
X509Certificate certificate, X509Certificate [] chainCertificates) throws Exception
{

// Получаем бинарную подпись длиной 64 байта.

final Signature signature = Signature.getInstance(AlgorithmUtils.getSignatureInstanceForJCP(certificate)); //hardcoded JCP.GOST_DHEL_SIGN_NAME
signature.initSign(privateKey);
signature.update(data);

final byte[] sign = signature.sign();

// Формируем контекст подписи формата PKCS7.

final ContentInfo all = new ContentInfo();
all.contentType = new Asn1ObjectIdentifier(
new OID(CMStools.STR_CMS_OID_SIGNED).value);

final SignedData cms = new SignedData();
all.content = cms;
cms.version = new CMSVersion(1);

// Идентификатор алгоритма хеширования.

String [] digestAndSignatureAlgorithms = AlgorithmUtils.getDigestSignatureAlgorithmOIDs(certificate);

cms.digestAlgorithms = new DigestAlgorithmIdentifiers(1);
final DigestAlgorithmIdentifier a = new DigestAlgorithmIdentifier(
new OID(digestAndSignatureAlgorithms[0]).value); //hardcoded CMStools.DIGEST_OID
a.parameters = new Asn1Null();
cms.digestAlgorithms.elements[0] = a;

// Т.к. подпись отсоединенная, то содержимое отсутствует.

cms.encapContentInfo = new EncapsulatedContentInfo(
new Asn1ObjectIdentifier(new OID(CMStools.STR_CMS_OID_DATA).value), null);


boolean isChainPresentAndNotEmpty = chainCertificates != null && chainCertificates.length > 0;

if (isChainPresentAndNotEmpty) // Цепочка есть, размер равен кол-во эл-ов + 1 (серт подписанта)
{
cms.certificates = new CertificateSet(chainCertificates.length + 1);
cms.certificates.elements = new CertificateChoices[chainCertificates.length + 1];
}
else // Если нет, то в подписи только сертификат подписанта
{
cms.certificates = new CertificateSet(1);
cms.certificates.elements = new CertificateChoices[1];
}

// Добавляем сертификат подписи.

//cms.certificates = new CertificateSet(1);
final ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate asnSignerCertificate =
new ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate();

final Asn1BerDecodeBuffer decodeSignerBuffer =
new Asn1BerDecodeBuffer(certificate.getEncoded());
asnSignerCertificate.decode(decodeSignerBuffer);

//cms.certificates.elements = new CertificateChoices[1];

cms.certificates.elements[0] = new CertificateChoices();
cms.certificates.elements[0].set_certificate(asnSignerCertificate);

// Добавляем цепочные сертификаты в подпись

if (isChainPresentAndNotEmpty)
{
for (int i = 0; i < chainCertificates.length; i++)
{
final ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate asnCertificate =
new ru.CryptoPro.JCP.ASN.PKIX1Explicit88.Certificate();

final Asn1BerDecodeBuffer decodeBuffer =
new Asn1BerDecodeBuffer(chainCertificates[i].getEncoded());
asnCertificate.decode(decodeBuffer);

//cms.certificates.elements = new CertificateChoices[1];

cms.certificates.elements[i + 1] = new CertificateChoices();
cms.certificates.elements[i + 1].set_certificate(asnCertificate);
}
}

// Добавялем информацию о подписанте.

cms.signerInfos = new SignerInfos(1);
cms.signerInfos.elements[0] = new SignerInfo();
cms.signerInfos.elements[0].version = new CMSVersion(1);
cms.signerInfos.elements[0].sid = new SignerIdentifier();

final byte[] encodedName = certificate.getIssuerX500Principal().getEncoded();
final Asn1BerDecodeBuffer nameBuf = new Asn1BerDecodeBuffer(encodedName);
final Name name = new Name();
name.decode(nameBuf);

final CertificateSerialNumber num = new CertificateSerialNumber(
certificate.getSerialNumber());

cms.signerInfos.elements[0].sid.set_issuerAndSerialNumber(
new IssuerAndSerialNumber(name, num));
cms.signerInfos.elements[0].digestAlgorithm =
new DigestAlgorithmIdentifier(new OID(digestAndSignatureAlgorithms[0]).value); // hardcoded CMStools.DIGEST_OID
cms.signerInfos.elements[0].digestAlgorithm.parameters = new Asn1Null();
cms.signerInfos.elements[0].signatureAlgorithm =
new SignatureAlgorithmIdentifier(new OID(digestAndSignatureAlgorithms[1]).value); //hardcoded CMStools.SIGN_OID
cms.signerInfos.elements[0].signatureAlgorithm.parameters = new Asn1Null();
cms.signerInfos.elements[0].signature = new SignatureValue(sign);

// Получаем закодированную подпись.

final Asn1BerEncodeBuffer asnBuf = new Asn1BerEncodeBuffer();
all.encode(asnBuf, true);

return asnBuf.getMsgCopy();
}


В общем, certificate это сертификат подписанта (который всегда включается в подпись без проблем) а chainCertificates это сертификаты уровнем выше (т.е. промежуточный1 -> промежуточный2 -> ... -> корневой).

Начинаю сомневаться, что так можно делать (просто добавлять в cms.certificates) "цепочку" и все типо работает. Хотя размер файла увеличился, сначала думал, что хороший знак, но все сервисы проверок "видят" только сертификат подписанта.

Подскажите, пожалуйста, куда копать
Offline Евгений Афанасьев  
#7 Оставлено : 10 декабря 2019 г. 10:23:12(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 2,949
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 14 раз
Поблагодарили: 441 раз в 431 постах
Автор: rmussalimov Перейти к цитате

Начинаю сомневаться, что так можно делать (просто добавлять в cms.certificates) "цепочку" и все типо работает. Хотя размер файла увеличился, сначала думал, что хороший знак, но все сервисы проверок "видят" только сертификат подписанта.

certificates как раз предназначен для того, чтобы передать те сертификаты, которые могут быть использованы при проверке подписи. Например, может быть включен один сертификат подписи для проверки подписи, если у проверяющей стороны его нет. Другие сертификаты также могут быть добавлены и использованы проверяющей стороной (если это требуется проверяющей стороной) на свое усмотрение (например, для построения и проверки цепочки сертификатов подписанта). Также в подписи могут быть и CRL'и (для проверки цепочки сертификатов, если такое предусмотрено и требуется проверяющей стороной).
Техническую поддержку оказываем тут
Наша база знаний
Offline rmussalimov  
#8 Оставлено : 10 декабря 2019 г. 10:58:44(UTC)
rmussalimov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 05.08.2019(UTC)
Сообщений: 48

Сказал(а) «Спасибо»: 4 раз
То есть никак не добавить промежуточные и корневые сертификаты?
Offline Евгений Афанасьев  
#9 Оставлено : 10 декабря 2019 г. 11:09:08(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 2,949
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 14 раз
Поблагодарили: 441 раз в 431 постах
Вы ведь добавили, судя по коду, в подпись. Про контейнер я писал ранее: если надо добавить в него, то постройте цепочку и выполните setCertificateEntry на контейнере, промежуточные и корневые установятся в расширения контейнера.
Техническую поддержку оказываем тут
Наша база знаний
Offline rmussalimov  
#10 Оставлено : 10 декабря 2019 г. 11:13:47(UTC)
rmussalimov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 05.08.2019(UTC)
Сообщений: 48

Сказал(а) «Спасибо»: 4 раз
Нужно добавить именно в подпись. И каким образом низкоуровневый ASN поймет, что включается вся цепочка вместо одного сертификата? Я ожидаю что-то наподобие этого https://stackoverflow.co...ms-container-in-c-sharp.

Просто addCertificate и все
Offline rmussalimov  
#11 Оставлено : 10 декабря 2019 г. 11:25:27(UTC)
rmussalimov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 05.08.2019(UTC)
Сообщений: 48

Сказал(а) «Спасибо»: 4 раз
Что я заметил, в примере CMSSign, метод createHashCMSEx есть возможность передать массив приватных ключей вместо одного. Очевидно, это сделано из-за того, что подпись может быть встроенная.

А сертификаты также добавляются, идет обход массива и добавление в cms.certificates.elements[i]

Отредактировано пользователем 10 декабря 2019 г. 11:26:11(UTC)  | Причина: Не указана

Offline Евгений Афанасьев  
#12 Оставлено : 10 декабря 2019 г. 11:51:59(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 2,949
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 14 раз
Поблагодарили: 441 раз в 431 постах
Автор: rmussalimov Перейти к цитате
Нужно добавить именно в подпись. И каким образом низкоуровневый ASN поймет, что включается вся цепочка вместо одного сертификата? Я ожидаю что-то наподобие этого https://stackoverflow.co...ms-container-in-c-sharp.
Просто addCertificate и все

Подпись ничего не знает о сертификатах, это просто средство их передачи. Как-то использовать сертификаты может только получающая/проверяющая сторона. Она может вообще не проверять подпись (тогда сертификат не нужен), проверять только подпись (тогда нужен сертификат подписи), строить цепочку (тогда нужна цепочка) или строить и проверять цепочку (тогда нужна цепочка и, возможно, CRL). Что класть в подпись, нужно обговаривать с проверяющей стороной (обычно на это есть документация и образцы). В примере, который вы привели, делается то же самое, что и вы: в certificates помещаются какие-то сертификаты. Проверяющая сторона должна по SID или signingCeritifcate понять, кто подписант, проверить подпись и построить для него (подписанта) цепочку (и, возможно, проверить ее).

Автор: rmussalimov Перейти к цитате
Что я заметил, в примере CMSSign, метод createHashCMSEx есть возможность передать массив приватных ключей вместо одного. Очевидно, это сделано из-за того, что подпись может быть встроенная.
А сертификаты также добавляются, идет обход массива и добавление в cms.certificates.elements[i]

В примере массив ключей соответствуют массиву сертификатов, это пары "ключ=сертификат", подписанты. В примере используется 1 ключ и 1 сертификат, т.е. 1 подписант, но можно передать 2 ключа и 2 сертификата, тогда это будут 2 подписанта. В примере для каждого подписанта кладется 1 сертификат, но сертификатов может быть и больше. В подписи раздел "сертификаты" (ceritificates) - это любые сертификаты, которые могут понадобиться для проверки подписи.

Отредактировано пользователем 10 декабря 2019 г. 11:52:46(UTC)  | Причина: Не указана

Техническую поддержку оказываем тут
Наша база знаний
Offline rmussalimov  
#13 Оставлено : 10 декабря 2019 г. 12:10:42(UTC)
rmussalimov

Статус: Активный участник

Группы: Участники
Зарегистрирован: 05.08.2019(UTC)
Сообщений: 48

Сказал(а) «Спасибо»: 4 раз
Понимаете в чем проблема:

Несмотря на то, что сертификаты очевидно добавляются (файл весит больше), проверяющие стороны, например, https://www.gosuslugi.ru/pgu/eds не видят, что сертификат подписанта был выдан промежуточным, они вообще его не видят никакие сертификаты, кроме подписанта (при загрузке открепленной подписи). Только если распарсить ASN, тогда можно понять то, что в подписи лежит еще один сертификат(-ы). В то же время, если подписать файл в КриптоПро CSP, то все хорошо, все сервисы видят все сертификаты

Мой первоначальный вопрос заключался в том как добавить сертификаты таким образом, чтобы проверяющая сторона знала, что Z был выдан Y, а Y был выдан X. Очевидно, что структура ASN должна отличаться. Но как именно и какие методы нужно вызывать - этого никто знать не может, кроме криптопро

Хотел сделать это программно, но, видимо, не судьба.

Если, например, сравнить это все с BC https://www.bouncycastle...SignedDataGenerator.html

То у них все работает верхнеуровнево - в gen.addCertificates(certs); в лист certs просто добавляем нужные сертификаты от меньшего к большему и цепь строится (но это не точно)

Отредактировано пользователем 10 декабря 2019 г. 12:17:31(UTC)  | Причина: Не указана

Offline Евгений Афанасьев  
#14 Оставлено : 10 декабря 2019 г. 12:33:25(UTC)
Евгений Афанасьев

Статус: Сотрудник

Группы: Участники
Зарегистрирован: 06.12.2008(UTC)
Сообщений: 2,949
Российская Федерация
Откуда: Крипто-Про

Сказал(а) «Спасибо»: 14 раз
Поблагодарили: 441 раз в 431 постах
Высокоуровневое API - это, например, использовать CAdES.jar и его примеры в CAdES-пакете. У него в методе addSigner есть параметр addCertificateChain для включения цепочки сертификатов в подпись. Документация в CAdES-javadoc.jar в папке javadoc дистрибутива. Или вместо addSigner с параметром addCertificateChain использовать setCertificateStore. Отличие его от первого варианта в том, что addCertificateChain добавляет цепочку подписанта, а с помощью setCertificateStore можно добавить любые сертификаты.
В <JRE>/lib/security/cacerts потребуется добавить корневой сертификат цепочки подписанта.

Отредактировано пользователем 10 декабря 2019 г. 14:32:02(UTC)  | Причина: Не указана

Техническую поддержку оказываем тут
Наша база знаний
RSS Лента  Atom Лента
Пользователи, просматривающие эту тему
Быстрый переход  
Вы не можете создавать новые темы в этом форуме.
Вы не можете отвечать в этом форуме.
Вы не можете удалять Ваши сообщения в этом форуме.
Вы не можете редактировать Ваши сообщения в этом форуме.
Вы не можете создавать опросы в этом форуме.
Вы не можете голосовать в этом форуме.