| ||||
| ||||
Есть encrypted digest. Вопрос: как его положить внутря сообщения pkcs#7? | ||||
Ответы: | ||||
| ||||
Немного конкретизирую вопрос: в стандарте RFC 2315 SignerInfo содержит поле EncryptedDigest... А в микрософтовской реализации этого поля не вывешивается (вероятно, чтобы не трогали руками). Есть ли более законный способ?.. | ||||
| ||||
и снова извиняюсь, данное поле, насколько я понял, есть EncryptedHash. Порядок действий такой: CryptMessageOpenToEncode с параметром CMSG_DATA, туда добавляется CryptMsgUpdate'ом SignerInfo, дальше достается из сообщения с помощью CryptMsgGetParam с параметром CMSG_CONTENT_PARAM полученное сообщение, но оно какое-то короткое (288 байт вместо стандартных 322, при создании подписи нормальным путем), и, при попытке проверки на втором Update'e (которым добавляются данные для проверки в сообщение) приходит отрицательный ответ.. Что я делаю не так? | ||||
| ||||
А откуда вообще такой странный способ взялся - собирать PKCS7 с помощью CryptMsg* функций? | ||||
| ||||
производственная необходимость =) А если серьезно, то есть готовые Digest'ы, есть нужда (для другой системы) соорудить из них сообщения. Переподписывать - совсем не вариант. Вот и приходится изгаляться | ||||
| ||||
Не, я не спрашиваю зачем Вы это делаете - это вообщем Ваше дело :) Вопрос другой - почему Вы решили это делать через CryptMsg*? | ||||
| ||||
У меня тоже появилась производственная необходимость сделать pkcs#7 подпись из короткой. Штатных способов не нашел, поэтому собрал наполовину вручную. Сделал недавно, могут быть ошибки, но в предварительный тест прошла. Будут вопросы, посылай на мэйл ap[собака]front.ru (читай с конца) #include "stdafx.h" #include "Pkcs7.h" Pkcs7::Pkcs7(byte_buffer& LongSign): LongSign(LongSign), idx(0) { }; // кодирует длину (считаем что умещается в 2 байта) void Pkcs7::EncodeSize(size_t dwSize) { LongSign[idx--] = static_cast<BYTE>(dwSize); if (dwSize > 0xFF) { LongSign[idx--] = static_cast<BYTE>(dwSize >> 8); LongSign[idx--] = 0x82; } else if (dwSize > 0x7F) LongSign[idx--] = 0x81; } // добавляет данные как есть void Pkcs7::AddData(const BYTE* pbyData, DWORD size) { idx -= size; ::CopyMemory(&LongSign[idx + 1], pbyData, size); } /** Кодирование OBJECT IDENTIFIER BER-кодирование OBJECT IDENTIFIER является всегда примитивным. Октеты содержимого представляют собой объединение n-1 строки октетов, где n число компонент объектного идентификатора. Каждая октетная строка несет в себе целое число по модулю 128 (старшая часть первая). 8-ой бит каждого октета, кроме последнего, равен 1. Пусть value1, …, valuen целые значения компонентов объектного идентификатора. Тогда n-1 субидентификаторов, из которых формируется октетная строка, будут иметь следующий вид. Первый субидентификатор равен 40value1 + value2. (значение value1 лежит в пределах 0-2 включительно, а value2 в интервале 0-39, когда value1 равна 0 или 1. i-ый субидентификатор равен valuei+1 ; 2 <= i<= n-1. **/ bool Pkcs7::AddOID(const char* pszObjId) { size_t startIdx = idx; // сначала преобразуем строку вида value1.value2.... в массив __int64 unsigned __int64 comp[20]; size_t ncomp = 0; comp[0] = 0; for (const char* pch = pszObjId; *pch != 0; pch++) { if (*pch == '.') { ncomp++; if (ncomp >= sizeof(comp)) return false; comp[ncomp] = 0; continue; } int by = *pch - '0'; if (by < 0 || by > 9) return false; comp[ncomp] = comp[ncomp]*10 + by; } // преобразуем в der с конца кроме первых двух for (size_t i = ncomp; i > 1; i--) { unsigned __int64 c = comp[i]; size_t carryflag = 0; do { if (idx < 3) return false; LongSign[idx--] = static_cast<BYTE>((c & 0x7F) | carryflag); c >>= 7; carryflag = 0x80; } while (c > 0); } // Преобразуем первые два числа BYTE byte0 = 40*static_cast<BYTE>(comp[0]); if (comp[0] > 2) return false; // value1 лежит в пределах 0-2 включительно if (ncomp > 0) byte0 += static_cast<BYTE>(comp[1]); LongSign[idx--] = byte0; // Первый байт получается из двух первых чисел EncodeSize(startIdx - idx); // размер LongSign[idx--] = 0x06; // код OBJECT IDENTIFIER return true; } DWORD HandleError(DWORD dwErr = -5) { return ::HandleError(dwErr, L"Невозможно закодировать объект в PKCS#7"); } /* ContentInfo ::= SEQUENCE { contentType ContentType, content [0] EXPLICIT ANY DEFINED BY contentType OPTIONAL } ContentType ::= OBJECT IDENTIFIER SignedData ::= SEQUENCE { version CMSVersion, digestAlgorithms DigestAlgorithmIdentifiers, encapContentInfo EncapsulatedContentInfo, certificates [0] IMPLICIT CertificateSet OPTIONAL, crls [1] IMPLICIT CertificateRevocationLists OPTIONAL, signerInfos SignerInfos } DigestAlgorithmIdentifiers ::= SET OF DigestAlgorithmIdentifier DigestAlgorithmIdentifier ::= AlgorithmIdentifier AlgorithmIdentifier ::= SEQUENCE { algorithm OBJECT IDENTIFIER, parameter ANY DEFINED BY algorithm OPTIONAL } SignerInfos ::= SET OF SignerInfo SignerInfo ::= SEQUENCE { version CMSVersion, sid SignerIdentifier, digestAlgorithm DigestAlgorithmIdentifier, signedAttrs [0] IMPLICIT SignedAttributes OPTIONAL, signatureAlgorithm SignatureAlgorithmIdentifier, signature SignatureValue, unsignedAttrs [1] IMPLICIT UnsignedAttributes OPTIONAL } */ /** /* 0 291: SEQUENCE {* /0x30,0x82,0x01,0x23, /* 4 9: OBJECT IDENTIFIER signedData * / 0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x02, /* 15 276: [0] { * / 0xA0,0x82,0x01,0x14, /* 19 272: SEQUENCE { * / 0x30,0x82,0x01,0x10, /* 23 1: INTEGER 1 * /0x02,0x01,0x01, /* 26 12: SET { * / 0x31,0x0C, /* 28 10: SEQUENCE { * / 0x30,0x0A, /* 30 6: OBJECT IDENTIFIER alg oid * / 0x06,0x06,0x2A,0x85,0x03,0x02,0x02,0x09, /* 38 0: NULL * / 0x05,0x00, /* : } * / /* : } * / /* 40 11: SEQUENCE { * / 0x30,0x0B, /* 42 9: OBJECT IDENTIFIER data * / 0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x01, /* : } */ /* 53 239: SET {...* / 0x31,0x81,0xEF Дальше идет signerInfo **/ const BYTE gEncapsulatedContentInfo[] = {0x30,0x0B,0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x01}; const BYTE gNullVal[] = {0x05, 0x00}; const BYTE gVersionVal[] = {0x02, 0x01, 0x01}; const BYTE gSignDataType[] = {0x06,0x09,0x2A,0x86,0x48,0x86,0xF7,0x0D,0x01,0x07,0x02}; DWORD Pkcs7::ShortSignToPkcs7Sign(CMSG_SIGNER_INFO* pSignerInfo) { // Кодируем SignerInfo с помощью CryptoApi DWORD dwSize = 1000; byte_buffer Signer(dwSize); if (!::CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS7_SIGNER_INFO, pSignerInfo, Signer.c_ptr(), &dwSize)) { if (GetLastError() != ERROR_MORE_DATA) return HandleError(GetLastError()); LongSign.reserve(dwSize); if (!::CryptEncodeObject(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING, PKCS7_SIGNER_INFO, pSignerInfo, Signer.c_ptr(), &dwSize)) return HandleError(GetLastError()); } Signer.resize(dwSize); // Кодируем остальное вручную idx = 100; dwSize += static_cast<DWORD>(idx); LongSign.reserve(dwSize); LongSign.resize(idx); idx--; // SET OF DigestAlgorithmIdentifier EncodeSize(Signer.size()); LongSign[idx--] = 0x31; // EncapsulatedContentInfo AddData(gEncapsulatedContentInfo, sizeof(gEncapsulatedContentInfo)); // DigestAlgorithmIdentifier size_t sz = idx; AddData(gNullVal, sizeof(gNullVal)); // algorithm parameter if (!AddOID(pSignerInfo->HashAlgorithm.pszObjId)) return HandleError(); if (idx < 30) return HandleError(); sz = sz - idx; // SEQUENCE { * / 0x30, size of DigestAlgorithmIdentifier, LongSign[idx--] = (BYTE) sz; LongSign[idx--] = 0x30; // digestAlgorithms SET { * / 0x31, size LongSign[idx--] = (BYTE) (sz + 2); LongSign[idx--] = 0x31; // CMSVersion AddData(gVersionVal, sizeof(gVersionVal)); //SignedData ::= SEQUENCE { * / 0x30, size EncodeSize(dwSize - idx - 1); LongSign[idx--] = 0x30; // content [0] EncodeSize(dwSize - idx - 1); LongSign[idx--] = 0xA0; // contentType AddData(gSignDataType, sizeof(gSignDataType)); // ContentInfo ::= SEQUENCE { EncodeSize(dwSize - idx - 1); LongSign[idx] = 0x30; ::CopyMemory(LongSign.c_ptr(), &LongSign[idx], LongSign.size() - idx); ::CopyMemory(&LongSign[LongSign.size() - idx], Signer.c_ptr(), Signer.size()); LongSign.resize(LongSign.size() - idx + Signer.size()); return 0; } // static DWORD Pkcs7::ShortSignToPkcs7Sign(WinCryptoConfig& config, PCCERT_CONTEXT pCertCxt, byte_buffer& ShortSign, byte_buffer& LongSign) { CMSG_SIGNER_INFO SignerInfo; ::ZeroMemory(&SignerInfo, sizeof(SignerInfo)); SignerInfo.dwVersion = CMSG_SIGNER_INFO_PKCS_1_5_VERSION; SignerInfo.Issuer = pCertCxt->pCertInfo->Issuer; SignerInfo.SerialNumber = pCertCxt->pCertInfo->SerialNumber; CRYPT_ALGORITHM_IDENTIFIER HashAlg = {config.GetHashAlgOID(), {0, 0}}; SignerInfo.HashAlgorithm = HashAlg; SignerInfo.HashEncryptionAlgorithm = pCertCxt->pCertInfo->SubjectPublicKeyInfo.Algorithm; // Подпись хэша в обратном должна идти в обратном порядке byte_buffer ReverseShortSign; ShortSign.reverse_to(ReverseShortSign); SignerInfo.EncryptedHash.cbData = ReverseShortSign.size(); SignerInfo.EncryptedHash.pbData = ReverseShortSign.c_ptr(); Pkcs7 pkcs7(LongSign); return pkcs7.ShortSignToPkcs7Sign(&SignerInfo); }; | ||||
| ||||
самому реализовывать стандарт не хочется, потому что сразу возникнут вопросы на тему "а правильно ли оно реализовано" и тому подобные... то есть вы хотите сказать, что собрать его просто используя микрософтовские функции - дохлый номер?.. | ||||
| ||||
Я хочу сказать, что microsoft'овских способов сборки pkcs#7 я не нашел, кроме как кодирования SignerInfo, которая входит в pkcs#7 с помощью EncodeObject. И подозреваю что их нет. | ||||
| ||||
Документированных нет, недокументированные пока неизвестны :) | ||||
| ||||
ясно, остается только реализовывать все ручками, а так не хотелось... Жаль =( Спасибо за ответы =) | ||||