КриптоПро TSP SDK: Низкоуровневый интерфейс |
Низкоуровневый интерфейс из состава КриптоПро TSP SDK предназначен для работы со штампами времени. Использование данного интерфейса упрощает реализацию служб штампов и делает возможным встраивание службы в существующую систему.
Низкоуровневый интерфейс представляет собой библиотеку классов C++.
В библиотеке реализована поддержка структур данных, описанных в RFC 3161, и штампов времени, используемых Microsoft для подписи исполняемых файлов (в технологии Authenticode).
Для поддержки штампов времени Microsoft предоставляются классы:
Основные классы библиотеки (запросы, ответы, штампы) содержат методы encode()/decode(), выполняющие операцию кодирования в ASN.1 DER-представление и декодирования из него. Классы, работающие со структурами, которые содержат подпись (CToken, CMSStamp), обеспечивают операции подписи и проверки подписи (sign()/verify()), а также доступ к информации о подписи (SignerInfo). Используя конструктор по умолчанию, можно создать пустой объект, для последующего вызова функции decode(). Во всех остальных случаях, если существует конструктор с аргументами, использование конструктора по умолчанию не рекомендуется, так как перед вызовом encode() все обязательные поля структуры должны быть проинициализированы корректными значениями. Конструкторы с аргументами заполняют эти поля при создании объекта, а конструкторы по умолчанию - нет, что допускает вероятность того, что объект не будет правильно проинициализирован перед вызовом encode().
Представление объектов в виде ASN.1 DER, используется для их транспортировки между клиентом и сервером. Таким образом, есть два типичных сценария работы с классами библиотеки:
При возникновении ошибок методы классов данной библиотеки могут генерировать следующие виды исключений: std::exception и ATL::CAtlException.
Пример (создание запроса на штамп времени):
//создание запроса на штамп времени //алгоритм хэша (параметры нулевые) CryptoPro::ASN1::CAlgorithmIdentifierEx hashAlgorithm; hashAlgorithm.put_algorithm(hashAlgorithmOID); //подсчет хэша CryptoPro::CBlob hashBlob = ::MakeHash(0,hashAlgorithm.get_AlgId(),data); // cоздается запрос CryptoPro::PKI::TSP::CRequest tsRequest(hashAlgorithm,hashBlob,certReq); // здесь установка опциональных параметров tsRequest.put_reqPolicy(policyOID); // 64-битное случайное число CryptoPro::ASN1::CBigInteger nonce = ::MakeRandomBigInteger(0,8); tsRequest.put_nonce(&nonce); // extensions; // кодируется запрос в блоб return tsRequest.encode();
Пример (создание штампа времени Microsoft):
// содание штампа времени // вкладывается request.contentInfo.content и время штампа CryptoPro::CDateTime time = CryptoPro::CDateTime::Now(); CryptoPro::PKI::TSP::CMSStamp timeStamp( request.get_contentInfo().get_content(), time); // получение дескриптора закрытого ключа, на котором будет подписан штамп HCRYPTPROV hProv = 0; DWORD dwKeySpec = 0; ::FindInStoreAndAcquirePrivateKey( tsaCert, tsaStore.c_str(), false, hProv, dwKeySpec); CryptoPro::ASN1::CAlgorithmIdentifierEx hashAlgorithm; hashAlgorithm.put_algorithm(hashOID); CryptoPro::ASN1::CEncodedCertificateList certs; certs.push_back(tsaCert); // вложение дополнительных сертификатов (опционально) timeStamp.put_certificates(&certs); // подпись timeStamp.sign( hProv, dwKeySpec, tsaCert, hashAlgorithm); return timeStamp.encode();
Пример (создание штампа времени):
// OID политики const char * policy; // серийный номер штампа CryptoPro::ASN1::CBigInteger serialNumber = ::MakeRandomBigInteger(0/*нулевой hProv - будет открыт внутри*/,10); serialNumber++; // время создания штампа CryptoPro::CDateTime genTime = CryptoPro::CDateTime::Now(); // создание штампа времени CryptoPro::PKI::TSP::CToken tsToken( policy, tsRequest.get_hashAlgorithm(), tsRequest.get_hashedMessage(), serialNumber, genTime, true); // заполняются опциональные атрибуты штампа времени // переносим случайное число из запроса tsToken.put_nonce( tsRequest.get_nonce() ); // обязательный атрибут SigningCertificate // RFC 3161 2.4.2 CryptoPro::ASN1::CESSCertIDList ids; ids.push_back( ESSCertIDFromCertificate(encodedTSACertificate) ); CryptoPro::ASN1::CAttrSigningCertificate attrSigningCertificate(ids); CryptoPro::ASN1::CAttribute attr(attrSigningCertificate.get_oid()); attr.add(attrSigningCertificate); // атрибут OtherSigningCertificate CryptoPro::ASN1::CAlgorithmIdentifierEx certHashAlgorithm; certHashAlgorithm.put_algorithm(szOID_OIWSEC_sha1); CryptoPro::ASN1::COtherCertIDList otherIds; otherIds.push_back( OtherCertIDFromCertificate(encodedTSACertificate,certHashAlgorithm) ); CryptoPro::ASN1::CAttrOtherSigningCertificate attrOtherSigningCertificate(otherIds); CryptoPro::ASN1::CAttribute attr1(attrOtherSigningCertificate.get_oid()); attr1.add(attrOtherSigningCertificate); CryptoPro::ASN1::CAttributes attrs; attrs.push_back(attr); attrs.push_back(attr1); tsToken.put_signedAttributes(&attrs); // если certReq равен true добавляем сертификат if( tsRequest.get_certReq() ) { CryptoPro::ASN1::CEncodedCertificateList certificateList; certificateList.push_back(encodedTSACertificate); tsToken.put_certificates(&certificateList); } // устанавливаем точность CryptoPro::PKI::TSP::CAccuracy accuracy(1,2,3); tsToken.put_accuracy(&accuracy); // subject службы штампов времени CryptoPro::CBlob tsaSubject( pCertStoreContext->pCertInfo->Subject.pbData, pCertStoreContext->pCertInfo->Subject.cbData); CryptoPro::ASN1::CGeneralName tsa; tsa.put_directoryName(tsaSubject); tsToken.put_tsa(&tsa); // алгоритм для хэширования сообщения CryptoPro::ASN1::CAlgorithmIdentifierEx msgHashAlgorithm(szOID_OIWSEC_sha1); // подписывание штампа tsToken.sign(hProv,dwKeySpec,encodedTSACertificate,msgHashAlgorithm); // return tsToken;
Пример (разбор полученного штампа времени Microsoft):
CryptoPro::PKI::TSP::CMSStamp timeStamp; timeStamp.decode(encodedResponse); // получение информации о подписчике CryptoPro::ASN1::CSignerInfo signer = timeStamp.get_signerInfo(); // поиск сертификата подписчика CCertStore store; HRESULT hr = store.InitSystemStore( L"My", CERT_STORE_OPEN_EXISTING_FLAG | CERT_STORE_READONLY_FLAG | CERT_SYSTEM_STORE_CURRENT_USER); if(FAILED(hr)) ATL::AtlThrowImpl(hr); CryptoPro::CBlob timeStampAuthorityCertificate = ::FindCertificateInStoreBySigner( store, signer); // проверка подписи if(!timeStamp.verify(timeStampAuthorityCertificate)) throw std::runtime_error("Authenticode time stamp signature is not verified."); // проверка на соответствие запросу CryptoPro::CBlob encodedRequest; encodedRequest.readFromFile("request.der"); CryptoPro::PKI::TSP::CMSRequest request; request.decode(encodedRequest); if( request.get_contentInfo().get_content() != timeStamp.get_content() ) throw std::runtime_error("Authenticode time stamp content doesn't match."); // получение времени штампа timeStamp.get_signingTime(); // получение дополнительных сертификатов timeStamp.get_certificates();