Комментарии 52
https://habrahabr.ru/post/276057/
Импорта не проверял — цель ведь сбежать с крипты, а не прибежать в неё.
Если уж на то пошло, то на Linux через админку КриптоПро JCP нету вообще никаких опций экспорта кроме одной — «Экспорт» без описания. Оно экспортит в неназванный формат без расширения имени файла, который содержит в себе только открытый ключ. А на OSX даже эта админка либо не запускается, либо сыпет багами. А если захочешь установить ключи, устанавливать их надо копированием в магическую директорию, путь который ищется на форуме, и из интефрейса админки JCP это не делается. Думаю, если тут «кто-то делает не так», искать надо начинать не с меня, а например, с самой Крипты.
Не все так просто. jailbreak
4.0/3.5 не экспортируют неэкспортируемый ГОСТ Р 34.11/34.10-2001-ГОСТ Р 34.11-94
ключ, ни через jbcert
Не удалось выполнить экспорт.
Ключ не может быть использован в указанном состоянии.
ни через jbstore -a
Error sizing blob: -2146893813
This is because jbstore2 is not working, Are you using jailbreak32/64 to launch
it?
If there are still problems please contact iSEC Partners.
mimikatz 2.1.1-20170409
же не может экспортировать ключ, так как crypto::capi
и crypto::cng
не поддерживают нужные криптопровайдеры.
Обе программы сертификат видят.
Тем не менее, если ключ хранится в реестре, то он может быть извлечен из веток HKLM\SOFTWARE\CryptoPro\Settings\Users\{SID}\Keys\
или HKLM\SOFTWARE\Wow6432Node\CryptoPro\Settings\Users\{SID}\Keys\
, а затем, например, сконвертирован утилитой privkey
для использования в OpenSSL
(прежде нужно удалить пароль с криптоконтейнера через CSP
> Сервис
> Изменить пароль...
> Выбрать контейнер
> Не вводить пароль
).
Половина уже решена средствами openssl + обёртка на питоне и есть надежда на полный успех. Сильно не хватает нормальных интерфейсов работы с openssl на питоне, с поддержкой дополнительных движков криптопровайдеров. Тот же pyopenssl не умеет пока. Но, надеюсь, в будущем ситуация улучшится, благо все возможности есть.
1. Поддержка ключевых носителей eToken, Соболь, и т.д.
2. Поддержка параметров алгоритмов.
3. Работа с аппаратными генераторами случайных чисел.
4. Экзотические грабли, но тем не менее — переход на новые шифры «Кузнечик», «Стрибог» и т.д. не факт что в Bounty Castle оперативна появится их поддержка.
Хотя если делать замену КП на BC как черного ящика, то есть нечто что шифрует, то такой способ имеет место быть.
Да, проект опубликован давно, но отнюдь не означает, что он не работает. Там идут JUnit тесты и работаю. Заметьте, работают под Linux и под Windows.
Зачем сражаться с контейнерами закрытых ключей? Покупка КриптоПро CSP по цене соизмерима со стоимостью некой утилиты. И не факт, что она сможет извлечь ключи с аналогов eToken.
Посмотрите на недавно сертифицированную CSP 4.0. Там есть куча компонентов с полюбившимся OpenSSL.
На самом деле, я хочу вам показать пример реализации с Apache CXF. Здесь нет надобности вообще каким-то образом обрабатывать XML документ. JAXB и JaxWS делают много вещей для вас. Вы используете обычные классы. Далее, поднимаем SOAP клиента на основе WSDL и вкладываем в качестве параметра нужный Java класс.
Вся работа с криптографией, прописывание подписей в XML, извлечение и проверка подписей, это удел Apache CXF. Ваш код должен быть «мягким и пушистым», а не вызывать сложные рефлексы.
Самое основное понимание XML подписи — не надо стремится сохранить текстовое представление документа. В подписи указывается алгоритм нормализации. Он убирает все отступы и упорядочивает названия атрибутов в тегах. Полученная каша, в кодировке UTF-8 поступает в хеш функцию. Значение функции находится в разделе digest. Подпись собирает все эти дайджесты вместе и уже подписывает.
Я извиняюсь, если не совсем доходчиво объясняю.
«Лицензия на право использования СКЗИ „
КриптоПро JCP“ версии 2.0 на одном
сервере с одним ядром процессора (или с 2 ядрами с отключенным Hyper
Threading)»
https://www.cryptopro.ru/sites/default/files/docs/price.pdf
То есть, если я, в тестовых целях, энсиблом пачкой зафигачу свою софтину в сотню-другую докеров, на покупку лицензий мне придется продать на черном рынке машину, кваритру, собаку, жену, и все свои внутренние органы?
> соизмерима со стоимостью некой утилиты
если когда-нибудь у меня случится отпуск, таки напишу эту утилиту прямо на гитхаб, и это будет стоить вообще ничего никому
Обратите внимание на этот вопрос. Клиенты могут воспринимать вашу систему как сервер. Но ваша система может являться промежуточным звеном на этапе передачи данных во внешнюю систему. Другими словами, вы выступаете инициатором передачи сообщения — вы клиент. Это главное понимание.
Если же ваша система является получателем, вы выступаете в качестве сервера — стоите и слушаете, когда кто-то к вам подключится.
Точно так же в установке TLS соединения. Ваш browser выступает в роли клиента и ему не нужна серверная лицензия на КриптоПро CSP.
То же самое происходит и с лицензированием КриптоПро JCP/JCSP и JTLS. Для Клиентского ПО, JTLS бесплатно — так утверждают сами сотрудники КриптоПро. JCP так же идет по лицензии клиента.
То же самое в MQ или JMS. Есть один или несколько серверов, на которые поступают сообщения и они передают их клиентам. Клиент может публиковать сообщения, может забирать корреспонденцию. Но при этом, он остается для шины клиентом.
С точки зрения, вы делаете клиента. Сервер у вас пассивный.
В рамках Java программ, мы создаем сокеты. Для понимания, о чем я говорю, можно посмотреть статью Создаем клиент-сервер на сокетах.
Если вы создаете ServerSocket, это сервер. Если создаете Socket, это клиент.
Теперь представим такую ситуацию. У нас есть SOAP сообщение от клиента. Он подписывает сообщение и отправляет на сервер. Сервер отправляет ответ. Если ответ сервера должен быть подписан, ему нужна серверная лицензия.
Еще раз повторю, что сервис в шине — это клиент.
Он спрашивает у сервера наличие сообщений и получает сообщения в ответ. То что ваш сервис, это клиент, понятно?
После получения ответа, ваше ПО отключается от сервера и может не спеша подготовить ответ на полученное сообщение. После этого, ваш сервис подключается к серверу обмена и передает туда свое сообщение для отправителя исходного сообщения. Получает ответ от сервера, что он получил сообщение. То что ваш сервис — это клиент, понятно?
В чем же главное отличие сервера от клиента? Сервер не может самостоятельно установить соединение с клиентом. А вот, клиент может установить соединение с сервером.
Вам хватит клиентской лицензии на средства криптографии.
Клиентская лицензия для КП CSP (без возможности формирования ЭП + только клиентский TLS) — бесплатна.
Кому надо можете запросить соответствующее письмо у них в офисе.
>> Со слезами — потому что это проприетарщина, и она фиг знает как работает.
Эти «Лисси» умудрились даже исходники Firefox и Thunderbird спиратить. Оправдываются тем, что «У микрософта исходники тоже закрыты».
Что, впрочем, не отменяет того факта, что «Лисси» поступает, мягко говоря, нехорошо. С linux.org.ru их за это уже шуганули после попыток пиарить там свои поделия.
Вдобавок, возникает интересный каламбур — они предлагают довериться российской криптографии, но для этого, зачем-то, надо доверится сначала самой «Лисси».
И после этого еще кто-то смеет жаловаться на проблемы безопасности! Да если для того, чтобы вся эта криптография хоть как-то заработала, нужно гуглить днями и вставлять спагетти непонятно как и почему работающего кода — неудивительно, что статьи об уязвимостях просто прут пачками.
Асимметричная криптография в основе своей проста, как два пальца, почему же ее использование сопряжено с такими трудностями? Где внятные мануалы? Примеры кода? Вот, например, у меня как раз стоит задача прочитать приходящий PKCS#7 сертификат (в виде массива байт) и проверить подписи в нем, так даже для такой элементарной задачи (если не пользоваться классом PCKS7 из пакета sun.*
) нужно наворотить такую кучу кода, что волосы дыбом встают. Причем у всех кода разный и у меня впечатление, что никто не знает, как же это делать правильно. Во всяком случае, понимания того, что происходит, я ни в одном из ответов на stackoverflow не вижу. О генерации ответа в таком же формате (отдать свой подписанный публичный ключ) я пока даже боюсь думать, настолько все запутанно и неочевидно.
В контейнер можно положить несколько сертификатов. И будет у нас хранилище сертификатов.
Можно положить CRL файлы. Можно положить подписываемое сообщение. Можно положить зашифрованное сообщение.
Отсюда и идут все сложности в понимании.
Да, в самом сертификате есть подпись издателя и сведения о сертификате издателя. Но сам сертификат не является контейнером формата PKCS#7.
Для чтения и записи сертификата и контейнера используется стандарт ASN1.
Отсюда и все сложности на этапе освоения всего этого нагромождения.
СА получает запрос, извлекает публичный ключ и используя его проверяет подпись всего запроса. Если да — добавить поля Issuer, поменять/заменить/добавить дополнительный полей и подписать все это своим приватным ключом CA. Так получается сертификат.
Далее его можно отдать как есть (bin или base64), можно спрятать в контейнер PKCS#12 под пароль и отдать в нем.
О криках про шифрование и ключи. Основная задача криптографии не в алгоритмах. Основные трудности (основной упор всех разработок) — создание ключей (надежный непредсказуемый ДСЧ, от чего и появляются аппаратные прибамбасы) и надежный/стойкий метод хранения ключей (приватных в том числе).
О какой надежности системы можно говорить, если ПРИВАТНЫЕ ключи «ходят по рукам», перекладываются и «светятся» чуть ли не в открытом виде? Алгоритмы описаны на каждом втором вебсайте — приватность именно в хранении ключей. Любой СКЗИ работает по принципу «мы вам сделаем внутри ключ, вы можете использовать его для шифрования/подписи, но сам ключ (его содержимое) будет тайной за семью печатями и для вас тоже».
Посмотрите как устроены токены? Посмотрите как сделана ваша СИМ-карта в телефоне наконец — она свой ключ Ki не светит нигде и никогда.
Но использует вовсю.
Что смотреть в этой карточке или USB token? Микроконтроллер. Разве, что, на специальном оборудовании снимать с него стружку. Эти устройства хороши, но очень медленные. Вот, вы, пишите ответ в данной статье. Обмен с сервером идет в зашифрованном протоколе TLS. Теперь, ваш поток мыслей должен пройти через эту карточку / USBToken. После этого, данные уйдут на сервер. Данных не много. А теперь представьте, что этот сервер так же, весь трафик, все HTML статьи, будет гонять через USB Token. Данная технология имеет право на жизнь в некоторых областях применения.
Проблема в том, что PKCS#7 && PKCS#12 не могут выступать в роли хранилищ сертификатов и ключей. Эти протоколы разрабатывались только как транспортные.
Для хранения — токены (и связанный с ними протокол обмена (!!) PKCS#11), или новый PKCS#15
Основной вопрос был в попытке оправдать идеологию СКЗИ хранить свою приватную информацию в закрытом ото всех виде. В том числе и от владельца ключа. Обращаться к СКЗИ для использования этого ключа можно, экспортировать и унести ключ — должно быть запрещено.
Токены я упомянул (равно как и SIM) — пример того, что ключ создан, но пользователь его не видит и не может получить. Он скрыт внутри микросхемы контроллера. Вы можете его использовать, выдавая запросы на операции с этим ключом, микроконтроллер будет отвечать.
И… давайте не будем меряться скоростями? Есть много решений, почему вы думаете что все токены работают на USB? Но я вовсе не склоняю всех использовать токены как СКЗИ, это скорее пример реализации закрытых ключей. Закрытых «совсем».
Спасибо за статью, в своё весёлое прошлое нырнул на ночь глядя. В 2014-м году использовал разные криптовайдеры. И сравнивал скорость работы КриптоПро 3.6 и Bouncy Castle .NET. КриптоПро 3.6 работал существенно быстрее. Задача — формирование отсоединённой подписи для файла в нагрузочных тестах. Другая задача — формирование ключевой пары и сертификата, для тестовых пользователей формировал 10 000 ключевых пар и сертификатов (или около того).
В результате поступил так. Ключевую пару формировал в КриптоПро, а вот сертификат со всеми нужными атрибутами и свойствами мастерил в Bouncy Castle, там полная свобода. И с помощью Bouncy Castle сделал малый УЦ — выпуск сертификатов, CRL-ответчик, OCSP-ответчик. При подписании документов, получается, снова работал КриптоПро, так как закрытый ключ в нём хранился, а Bouncy Castle трудился только чтобы CRL и OCSP отдавать для формирования усовершенствованной подписи. Никакой из действующих УЦ мне бы никогда не выдал 10 000 ключей бесплатно, и не стал бы мне OCSP-ответы с дикой скоростью отдавать. OCSP-ответчики действующих УЦ умирали от нагрузки реальных клиентов. Тут Bouncy Castle помог.
Была задумка сделать масштабное сравнение скорости работы. Так как в .NET очень удобный CryptoAPI, который для простых задач, таких как формирование и проверка подписи скрывает детали взаимодействия с криптопровайдером до 0-ля. Нужно немного смекалки и умения обходить баги, чтобы водрузить на одну машину несколько криптопровайдеров сразу, а потом можно их тестировать одним и тем же кодом, лишь используя сертификаты, ключи к которым хранятся в разных криптопровайдерах. При условии, что на ключах нет пароля и есть лишь одно хранилище, всё проходит быстро и просто, без лишних диалогов от КриптоПро или VipNet.
Скоро ожидаю, что на работе будет проект с криптографией, тогда осуществлю задуманное. Сравню, VipNet, Lissy CSP, Crypto Pro, BounsyCastle. Их можно параллельно использовать. А вот, например, белорусский ГОСТ-криптопровайдер Avest CSP использовать вместе с КриптоПро было нельзя в 2014-м году. Предполагаю, они используют один и тот же идентификатор криптопровайдера или алгоритмов, и тот что установился последним, считался криптовайдером, реализующим ГОСТ-алгоритмы первого — это частично недостаток CryptoAPI для .NET, где нельзя тонко настроить этот момент, CryptoAPI считывает из реестра кто и что реализует, и в случае, если два провайдера реализуют одно и то же, сам принимает решение, какой из них использовать.
Примечание по скорости тестовых CRL и OCSP. Ответчики, сделанные на базе Bouncy Castle, работали быстро под натиском нагрузочных тестов, во многом, потому, что всегда отвечали, что с тестовыми сертификатами всё хорошо — были заглушками. CRL генерировался нечасто и грамотно кешировался, но тут реализовал всё полностью, можно было сделать сертификат отозванным. А OCSP-ответ всегда был положительным для любых сертификатов — заглушка. Вот всё и летало, как пуля.
Сертификат и цифровая подпись — данные в формате ASN.1, которые, как видно выше, можно мастерить, используя Bouncy Castle. CRL — тоже данные в формате ASN.1, которые как и сертификат подписаны ключом УЦ. Если Bouncy Castle может прочитать ключ, то Bouncy Castle может сформировать CRL.
Есть удобный класс: X509V2CrlGenerator.
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Math;
using Org.BouncyCastle.X509;
using Org.BouncyCastle.X509.Extension;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Globalization;
using System.IO;
...
X509Crl GetCrl()
{
DateTime thisUpdate = DateTime.UtcNow;
DateTime nextUpdate = thisUpdate.AddMinutes(Settings.CrlLifeTimeInMunutes);
Org.BouncyCastle.Asn1.DerObjectIdentifier crlNextPublish = new Org.BouncyCastle.Asn1.DerObjectIdentifier("1.3.6.1.4.1.311.21.4");
Org.BouncyCastle.Asn1.DerObjectIdentifier crlNumberOid = new Org.BouncyCastle.Asn1.DerObjectIdentifier("2.5.29.20");
if (System.IO.File.Exists(Settings.CrlFilePath))
{
FileInfo crlFileInfo = new FileInfo(Settings.CrlFilePath);
X509CrlParser crlParser = new X509CrlParser();
X509Crl prevCrl = crlParser.ReadCrl(System.IO.File.ReadAllBytes(Settings.CrlFilePath));
if (DateTime.UtcNow >= prevCrl.NextUpdate.Value)
{
X509V2CrlGenerator generator = new X509V2CrlGenerator();
generator.AddCrl(prevCrl);
generator.SetThisUpdate(thisUpdate);
generator.SetNextUpdate(nextUpdate);
generator.SetSignatureAlgorithm(Settings.SigningAlgorithm);
generator.SetIssuerDN(Certificate.SubjectDN);
generator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(Settings.CACertificate));
//Установка даты следующего обновления (crlNextPublish)
generator.AddExtension(crlNextPublish, false, new Org.BouncyCastle.Asn1.DerUtcTime(nextUpdate));
//Получение текущего номера CRL (crlNumber)
if (prevCrl.GetExtensionValue(crlNumberOid) != null)
{
Org.BouncyCastle.Asn1.DerInteger crlNumber = (Org.BouncyCastle.Asn1.DerInteger)Org.BouncyCastle.Asn1.DerInteger
.FromByteArray(prevCrl.GetExtensionValue(crlNumberOid).GetOctets());
//Увеличение номера на 1
crlNumber = new Org.BouncyCastle.Asn1.DerInteger(crlNumber.Value.IntValue + 1);
//Установка нового номера CRL (crlNumber)
generator.AddExtension(crlNumberOid, false, crlNumber);
}
else
{
generator.AddExtension(crlNumberOid, false, new Org.BouncyCastle.Asn1.DerInteger(0));
}
//Получение списка уже отозванных сертификатов
List<BigInteger> revokedSerialNumbers = GetSerialNumbers(prevCrl);
//Settings.LoadGoodAndRevoked();
//Список отозванных сертификатов, которые нужно отозвать сейчас
IEnumerable<BigInteger> newRevoked = Settings.RevokedCertificateNumbers
.Except(revokedSerialNumbers);
//Добавление недавно отозванных сертификатов, в список отзыва
foreach (BigInteger serialNumber in newRevoked)
{
//Причина отзыва не указывается
generator.AddCrlEntry(serialNumber, DateTime.UtcNow, CrlReason.Unspecified);
}
//Формирование CRL
var crl = generator.Generate(PrivateKey);
TryWriteFile(Settings.CrlFilePath, crl.GetEncoded(), 100);
logger.Debug(string.Format(CultureInfo.InvariantCulture, "CRL responce: {0}", Convert.ToBase64String(crl.GetEncoded())));
return crl;
}
else
{
return prevCrl;
}
}
else
{
X509V2CrlGenerator generator = new X509V2CrlGenerator();
generator.SetThisUpdate(thisUpdate);
generator.SetNextUpdate(nextUpdate);
generator.SetSignatureAlgorithm(Settings.SigningAlgorithm);
generator.SetIssuerDN(Certificate.SubjectDN);
generator.AddExtension(X509Extensions.AuthorityKeyIdentifier, false, new AuthorityKeyIdentifierStructure(Settings.CACertificate));
generator.AddExtension(crlNextPublish, false, new Org.BouncyCastle.Asn1.DerUtcTime(nextUpdate));
generator.AddExtension(crlNumberOid, false, new Org.BouncyCastle.Asn1.DerInteger(0));
DirectoryInfo revokedCertificateFolder = new DirectoryInfo(Settings.RevokedCertificateFolder);
IEnumerable<FileInfo> revokedCertificateFiles = revokedCertificateFolder.GetFiles("*.crt");
foreach (FileInfo revokedCertificateFileInfo in revokedCertificateFiles)
{
string name = revokedCertificateFileInfo.Name;
name = name.Substring(0, name.IndexOf('.'));
BigInteger serialNumber = new BigInteger(name);
//Причина отзыва не указывается
generator.AddCrlEntry(serialNumber, DateTime.UtcNow, CrlReason.Unspecified);
}
var crl = generator.Generate(PrivateKey);
TryWriteFile(Settings.CrlFilePath, crl.GetEncoded(), 100);
return crl;
}
}
static List<BigInteger> GetSerialNumbers(X509Crl crl)
{
List<BigInteger> listNumber = new List<BigInteger>();
Org.BouncyCastle.Utilities.Collections.ISet revokedCerts = crl.GetRevokedCertificates();
if (revokedCerts != null)
{
foreach (X509CrlEntry crlEntry in revokedCerts)
{
listNumber.Add(crlEntry.SerialNumber);
}
}
return listNumber;
}
Побег из Крипто Про. Режиссерская версия, СМЭВ-edition