| ||||
| ||||
как используя Crypto API (Low Level Message Functions) побавить подпись к уже подписанному сообщению, так, чтобы сообщение, полученное в результате, выглядело как подписанное двумя подписями (т.е. не добавляя подпись "поверх" первого)? | ||||
Ответы: | ||||
| ||||
Последовательность действий должна быть такая: 1. Вызов CryptMsgOpenToDecode+CryptMsgUpdate для декодирования "доподписываемого" сообщения. 2. Вызов CryptMsgControl с параметром "CMSG_CTRL_ADD_SIGNER". 3. Получившиеся сообщение получаем функцией CryptMsgGetParam с параметром "CMSG_ENCODED_MESSAGE" 4. Все. | ||||
| ||||
спасибо | ||||
| ||||
Есть вот такая функция, которая доподписывает сообщение. Проблема в том, что в Windows 2000 и XP функция работает, а в Win 98 нет, на функции CryptAcquireCertificatePrivateKey пишет ошибку (Операция завершена успешно). В MSDN сказано, что функция присутствует при установленом IE 5 и выше. В Crypt32.dll функция CryptAcquireCertificatePrivateKey присутствует. В чём может быть проблема? extern "C" bool __declspec(dllexport) CosignMessage(const BYTE* signedMessage, DWORD signedMessageSize, BYTE* cosignedMessageBlob, DWORD* cosignedMessageBlobSize, LPCSTR certHash, DWORD certHashLength) { HCRYPTMSG cryptMsg = 0; HCERTSTORE hStoreHandle = 0; PCCERT_CONTEXT certContext = 0; CRYPT_HASH_BLOB blobCert; HCRYPTPROV hCryptProv = NULL; DWORD keySpec = 0; char OID[64] = szOID_CP_GOST_R3411; BYTE bytes[20]; blobCert.cbData = 20; blobCert.pbData = bytes; stringToBinary((char*)certHash, &blobCert); if (!(hStoreHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_CURRENT_USER, PERSONAL_STORE_NAME))) { setLastError(); return false; } if(!(certContext = CertFindCertificateInStore(hStoreHandle, MY_ENCODING_TYPE, 0, CERT_FIND_HASH, &blobCert, NULL))) { CertCloseStore(hStoreHandle, 0); setLastError(); return false; } if (!CryptAcquireCertificatePrivateKey(certContext, CRYPT_ACQUIRE_CACHE_FLAG, NULL, &hCryptProv, &keySpec, NULL)) { CertCloseStore(hStoreHandle, 0); CertFreeCertificateContext(certContext); setLastError(); return false; } if (!(cryptMsg = CryptMsgOpenToDecode(MY_ENCODING_TYPE, 0, 0, NULL, NULL, NULL))) { CryptReleaseContext(hCryptProv, 0); CertCloseStore(hStoreHandle, 0); CertFreeCertificateContext(certContext); setLastError(); return false; } if(!CryptMsgUpdate(cryptMsg, signedMessage, signedMessageSize, TRUE)) { CryptReleaseContext(hCryptProv, 0); CertCloseStore(hStoreHandle, 0); CertFreeCertificateContext(certContext); setLastError(); return false; } CRYPT_ALGORITHM_IDENTIFIER HashAlgorithm; memset(&HashAlgorithm, 0, sizeof(CRYPT_ALGORITHM_IDENTIFIER)); HashAlgorithm.pszObjId = OID; CMSG_SIGNER_ENCODE_INFO signerInfo; memset(&signerInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO)); signerInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO); signerInfo.pCertInfo = certContext->pCertInfo; signerInfo.hCryptProv = hCryptProv; signerInfo.cAuthAttr = 0; signerInfo.cUnauthAttr = 0; signerInfo.dwKeySpec = keySpec; signerInfo.HashAlgorithm = HashAlgorithm; signerInfo.pvHashAuxInfo = NULL; signerInfo.rgAuthAttr = NULL; signerInfo.rgUnauthAttr = NULL; if (!CryptMsgControl(cryptMsg, 0, CMSG_CTRL_ADD_SIGNER, &signerInfo)) { CryptReleaseContext(hCryptProv, 0); CertCloseStore(hStoreHandle, 0); CertFreeCertificateContext(certContext); setLastError(); return false; } // добавим сертификат CERT_BLOB certInfo; certInfo.cbData = certContext->cbCertEncoded; certInfo.pbData = certContext->pbCertEncoded; if (!CryptMsgControl(cryptMsg, 0, CMSG_CTRL_ADD_CERT, &certInfo)) { CryptReleaseContext(hCryptProv, 0); CertCloseStore(hStoreHandle, 0); CertFreeCertificateContext(certContext); setLastError(); return false; } if (!CryptMsgGetParam(cryptMsg, CMSG_ENCODED_MESSAGE, 0, cosignedMessageBlob, cosignedMessageBlobSize)) { CryptReleaseContext(hCryptProv, 0); CertCloseStore(hStoreHandle, 0); CertFreeCertificateContext(certContext); setLastError(); return false; } CryptReleaseContext(hCryptProv, 0); CertCloseStore(hStoreHandle, 0); CertFreeCertificateContext(certContext); return true; } | ||||
| ||||
Программа - "юникодная"? | ||||
| ||||
Сама программа на C# .NET - следовательно юникодная. А данная функция заключена в C++ Dll (отдельная библиотека), в параметрах dll'ки указано, чтобы не использовать Unicode, так что вроде не должна быть. | ||||
| ||||
Просто это важно с точки зрения Windows 98. Чтобы убедится наверняка я бы посоветовал открыть вашу DLL с этим кодом в Microsoft Dependency Walker (depends.exe из состава Visual Studio или Platform SDK). Там будет явно указан суффикс импортируемых функций - "A" или "W". | ||||
| ||||
Открыл. Там нет никаких суффиксов и префиксов. Простоназвания функций, такие, какими я их называл в коде. | ||||
| ||||
Да, действительно. Используемые функции в единственном экземпляре. Так, едем дальше: "CryptAcquireCertificatePrivateKey пишет ошибку (Операция завершена успешно)" - как вы получаете код/текст ошибки? | ||||
| ||||
extern "C" void __declspec(dllexport) setLastError() { LPCSTR lpMsgBuf; FormatMessageA(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPSTR)&lpMsgBuf, 0, NULL); lastError = lpMsgBuf; } Вот такой вот функцией. | ||||
| ||||
Но между вызовами CryptAcquireCertificatePrivateKey() и setLastError() вы вызываете CertCloseStore() и CertFreeCertificateContext(). Они сбрасывают "LastError" на 0. GetLastError() необходимо вызывать сразу после интересующей функции. | ||||
| ||||
вот на этом месте вываливается оказывается: CMSG_SIGNER_ENCODE_INFO signerInfo; memset(&signerInfo, 0, sizeof(CMSG_SIGNER_ENCODE_INFO)); signerInfo.cbSize = sizeof(CMSG_SIGNER_ENCODE_INFO); signerInfo.pCertInfo = certContext->pCertInfo; signerInfo.hCryptProv = hCryptProv; signerInfo.cAuthAttr = 0; signerInfo.cUnauthAttr = 0; signerInfo.dwKeySpec = keySpec; signerInfo.HashAlgorithm = HashAlgorithm; signerInfo.pvHashAuxInfo = NULL; signerInfo.rgAuthAttr = NULL; signerInfo.rgUnauthAttr = NULL; if (!CryptMsgControl(cryptMsg, 0, CMSG_CTRL_ADD_SIGNER, &signerInfo)) { setLastError(); MessageBox(NULL, lastError, "CryptMsgControl_1", 0); CryptReleaseContext(hCryptProv, 0); CertCloseStore(hStoreHandle, 0); CertFreeCertificateContext(certContext); return false; } при выводе ошибки, пишет: ",ye" :) Видимо что то со структурой не то, она правильно заполнена? | ||||
| ||||
Код ошибки-то какой? | ||||
| ||||
Код: -2146893811 = 0x8009000D Значение: Ключ не существует. Вот | ||||
| ||||
Может быть всё таки CryptAcquireCertificatePrivateKey не срабатывает? Возвращает что нить не то... MSDN: Client Requires: Windows XP, Windows 2000 Professional, Windows NT Workstation 4.0 SP3 and later, or Windows Me. Server Requires: Windows Server 2003, Windows 2000 Server, or Windows NT Server 4.0 SP3 and later. Redistributable: Requires Internet Explorer 5 or later on Windows 98 or Windows 95. Header Declared in: Wincrypt.h. Library Link to: Crypt32.lib. DLL Requires: Crypt32.dll. | ||||
| ||||
заменил CryptAcquireCertificatePrivateKey на Вытаскивание keySpec и контекста криптопровайдера из свойств сертификата, выбранного из хранилища. Проблема такая же, в XP работает, в 98 ошибка: отсутствует набор ключей! | ||||
| ||||
точнее не "отсутствует набор ключей" a "Ключ не существует" | ||||
| ||||
В общем, ошибка с CryptAcquireCertificatePrivateKey() воспроизводится на примере cryptcp на Windows 98. Попробую поизучать еще. | ||||
| ||||
Я вот как раз оттуда и взял, что надо открыть сертификат из хранилища и получить из него свойства. И так тоже не работает | ||||
| ||||
Попробуйте передать в CryptMsgOpenToDecode() hProv | ||||
| ||||
Отлично! Спасибо, заработало. | ||||