| ||||
| ||||
Уважаемые разработчики! Жизнь заставляет отказываться от провайдеров MS и переходить на сертифицированные. Насколько я понимаю, ваш CSP должен соответствовать требованиям Crypto API 2.0. В моем приложениии все проще - используются вызовы Crypto API 1, и все это успешно было опробовано и работает на различных типах провайдеров. Но не Крипто ПРО. Как оказалось, при экспорте открытого ключа, буфер, отведенный под этот ключ, становится невозможно освободить. Более того, при последующей попытке освободить контекст, происходит аварийное завершение приложения. Вот упрощенный кусок кода: function ExportKeyToBuff(hProv: HCRYPTPROV;hKey:HCRYPTKEY; isPrivate:boolean; Pass:string; FromPoint:pointer):dword; const hExpKey: HCRYPTKEY = 0; dwAlg: DWORD = 0; dwBlobType: DWORD = 0; hHash: HCRYPTHASH = 0; htempKey:HCRYPTKEY = 0; begin result:=0; hExpKey:= 0; dwAlg:= 0; dwBlobType:= 0; hHash:= 0; try if isPrivate then begin dwBlobType:=PRIVATEKEYBLOB; ... end else dwBlobType:=PUBLICKEYBLOB; result:=$3FFF; if not CryptExportKey(hKey, hExpKey, dwBlobType, 0, FromPoint, @result) then raise Exception.CreateFmt(’Cant export. Error %x’,[getlasterror]); finally if hHash<>0 then CryptDestroyHash(hHash); if hExpKey<>0 then CryptDestroyKey(hExpKey); end; end; function ExportKeyToFile(hProv: HCRYPTPROV;hKey:HCRYPTKEY; isPrivate:boolean; Pass,FileName:string):dword; // я оставил код для isPrivate = true var hFile,hFileMapping:THandle; FileMap:pointer; temp:pointer; begin result:=0; // узнаем необходимую длину буфера result:=ExportKeyToBuff(hProv,hKey,isPrivate,Pass,nil); // выделяем память temp:=AllocMem(result); try // экспортируем ключ в буфер result:=ExportKeyToBuff(hProv,hKey,isPrivate,Pass,temp); ... finally ... // освобождаем память FreeMem(temp); end; end; При попытке освободить память (FreeMem(temp)) получаем invalid pointer operation. При последующем освобождении контекста происходит цепочка исключений, приводящих к падению приложения (если оно было скомпилировано в Delphi5), либо к невозможности дальнейшей работы с провайдером (скомпилировано в Delphi7). Повторю, что провайдеры MS в приведенном куске кода работают абсолютно корректно. Обнаруженная ошибка происходит если включена опция "хранить ключи в памяти приложений", т.е. установка по умолчанию. Надеюсь, приведенная информация поможет вам исправить работу провайдера | ||||
Ответы: | ||||
| ||||
Здравствуйте, Нижеследующий кусок кода вызывает сомнения: dwBlobType:=PUBLICKEYBLOB; result:=$3FFF; if not CryptExportKey(hKey, hExpKey, dwBlobType, 0, FromPoint, @result) | ||||
| ||||
Действительно, если подать на вход точное значение кол-ва выделенных байт, ошибки не происходит. Очевидно, csp крипто про при экспорте открытого ключа "пишет" не столько, сколько требуется для клоюча ключ, а сколько задали на входе. В отличие от других провайдеров (да и от того же крипто про в режиме использования службы хранения ключей). Возьмем на заметку. Спасибо. | ||||
| ||||
> Действительно, если подать на вход точное значение кол-ва выделенных байт, ошибки не происходит. Очевидно, csp крипто про при экспорте открытого ключа "пишет" не столько, сколько требуется для клоюча ключ, а сколько задали на входе. Имеет право, у MS черным по анлийски написано, что "value that specifies the size, in bytes, of the buffer pointed to by the pbData parameter" > В отличие от других провайдеров (да и от того же крипто про в режиме использования службы хранения ключей). Вот это странность, на мой взгляд Вы должны эту проблемы при работе с сервисом хранения ключей. | ||||
| ||||
По нашему мнению, Ваш код неправильно работает с указателями, поскольку ни на одной версии провайдера мы такой ошибки не обнаружили. | ||||
| ||||
У MS английским по белому написано, что "when the function returns, the DWORD value contains the number of bytes stored in the buffer". Так что на входе pdwDataLen определяет только максимальный размер переданного буфера. Если его недостаточно, Ваша задача вернуть ERROR_MORE_DATA. | ||||
| ||||
Ошибка ERROR_MORE_DATA должна выдаваться в случае, если CSP требуется буфер размером больше чем *pdwDataLen (в Вашем случае >16383). Вы же сообщили CSP, что буфер имеет размер 0x3FFF и он может ими пользоваться. Он и пользуется, и размера ему тоже хватает. pdwDataLen [in, out] Pointer to a DWORD value that specifies the size, in bytes, of the buffer pointed to by the pbData parameter... У MS поведение функции "Retrieving Data of Unknown Length" неопределено в случае если, и указатель не нулевой, и длина некорректная. Что и получается. Я всё правильно понял? | ||||
| ||||
Все верно, за исключением того, что в MSDN в этом же абзаце написано, что по выходе из функции в переменную по указателю pdwDataLen созраняется длина данных, скопированных в буфер. В данном случае это явно указано и ссылка на "Retrieving Data of Unknown Length" не корректна. | ||||
| ||||
Согласно приведённому коду по адресу @result, перед каждым вызовом CryptExportKey сначала записывается 0, а потом 16383. | ||||