Экспорт сертификата с помощью CryptoAPI.

dim101
Дата: 01.06.2011 15:10:16
Нужно экспортировать сертификат без закрытого ключа. Нашел функцию CryptUIWizExport.
При отладке функция возвращает false, а GetLastError возвращает 2147942487.
М.б. кто-нибудь подскажет, в чем ошибка.

Описание функции CryptUIWizExport и структуры PCCRYPTUI_WIZ_EXPORT_INFO

+
const
  Cryptui     = 'Cryptui.dll';

type
  PCCRYPTUI_WIZ_EXPORT_INFO = ^CCRYPTUI_WIZ_EXPORT_INFO;
  CCRYPTUI_WIZ_EXPORT_INFO = [b]record[/b]
  dwSize: DWORD;
  pwszExportFileName: LPCWSTR;
  dwSubjectChoice: DWORD;
  pCertContext: PCCERT_CONTEXT;
  cStores: DWORD;
  rghStores: HCERTSTORE;

  end;

function[/b] CryptUIWizExport(dwFlags: DWORD;
                          hwndParent: HWND;
                          pwszWizardTitle: LPCWSTR;
                          pExportInfo: PCCRYPTUI_WIZ_EXPORT_INFO;
                          pvoid: PVOID) :BOOL;stdcall;

function CryptUIWizExport        ;external Cryptui name 'CryptUIWizExport';

// Описание процедуры экспорта
procedure ExportCert;
var
    prov: HCRYPTPROV;
    store: HCERTSTORE;
    cont, stor: PChar;
    err: string;
    cert: PCCERT_CONTEXT;
    encType: DWORD;
    PCCRYPTUI: PCCRYPTUI_WIZ_EXPORT_INFO;
begin
encType := PKCS_7_ASN_ENCODING or X509_ASN_ENCODING;

if CryptAcquireContext(@prov, nil, nil, PROV_RSA_FULL, 0) = false then
ShowMessage('ошибка');

err := 'MY';
stor := StrAlloc(length(err) + 1);
StrPCopy(stor, err);

//открываем хранилище сертификатов
store := CertOpenSystemStore(prov, stor);

//получаем сертификат
cert := CertEnumCertificatesInStore(store, nil);


PCCRYPTUI:=New(PCCRYPTUI_WIZ_EXPORT_INFO); // Выделяем память
 PCCRYPTUI.dwSize := sizeof(PCCRYPTUI);
 PCCRYPTUI.pwszExportFileName := 'E:\10.cer';
 PCCRYPTUI.dwSubjectChoice := 1; // CRYPTUI_WIZ_EXPORT_CERT_CONTEXT
 PCCRYPTUI.pCertContext := cert;
 PCCRYPTUI.cStores := 0;
 PCCRYPTUI.rghStores := store;

// пытаюсь экспортировать сертификат
if  [i]CryptUIWizExport[/i](1, // CRYPTUI_WIZ_NO_UI
 0, 0, PCCRYPTUI, PCCRYPTUI) = false then
    MessageDlg('Ошибка экспорта сертификата: ' + IntToStr(int64(GetLastError)), mtError, [mbOK], 0);

Dispose(PCCRYPTUI); // Уничтожаем память
End;
Альт
Дата: 01.06.2011 15:33:14
Первое, что сразу бросается в глаза:
PCCRYPTUI.dwSize := sizeof(PCCRYPTUI);

PCCRYPTUI = 4, а надо sizeof(CCRYPTUI_WIZ_EXPORT_INFO) = 24
dim101
Дата: 01.06.2011 15:51:57
Альт, спасибо, поправил:
PCCRYPTUI.dwSize := sizeof(CCRYPTUI_WIZ_EXPORT_INFO);
Код ошибки изменился “2147500037”
Гаджимурадов Рустам
Дата: 01.06.2011 16:35:11
ОФФ

Альт, с возвращением. :)
Кроик Семён
Дата: 01.06.2011 16:49:16
dim101,

с CryptoAPI не знаком, но может там есть возможность получить сообщение об ошибке в виде текста?
Вот, здесь что-то подобное было
   ..... GetErrorMessage(GetLastError())
dim101
Дата: 01.06.2011 17:56:25
Кроик Семён,

Описание кодов ошибок даны тут

Смущает длина кода ошибки. Слишком большая. М.б. ошибок несколько.
_Vasilisk_
Дата: 01.06.2011 21:01:45
На каком основании вы последним параметром передаете указатель на CCRYPTUI_WIZ_EXPORT_INFO?
dim101
Дата: 02.06.2011 08:40:00
_Vasilisk_, cпасибо.
Действительно последним параметром в функции CryptUIWizExport нужно передавать другую структуру - CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO.

+
type
  PCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO = ^CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO;
  CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO = record
  dwSize: DWORD;
  dwExportFormat: DWORD;
  fExportChain: BOOL;
  fExportPrivateKeys: BOOL;
  pwszPassword: LPCWSTR;
  fStrongEncryption: BOOL;
  end;

var
…
    PCRYPTUI_CERTCONTEXT: PCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO;

…
PCRYPTUI_CERTCONTEXT:=New(PCRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO); 
 PCRYPTUI_CERTCONTEXT.dwSize := sizeof(CRYPTUI_WIZ_EXPORT_CERTCONTEXT_INFO);
 PCRYPTUI_CERTCONTEXT.dwExportFormat := 1;//CRYPTUI_WIZ_EXPORT_FORMAT_DER
 PCRYPTUI_CERTCONTEXT.fExportChain := false;
 PCRYPTUI_CERTCONTEXT.fExportPrivateKeys := false;
 PCRYPTUI_CERTCONTEXT.pwszPassword := 0;
 PCRYPTUI_CERTCONTEXT.fStrongEncryption := false;

if  CryptUIWizExport(1,
                   0,
                   0,
                   PCCRYPTUI,
                   PCRYPTUI_CERTCONTEXT
) = false then
    MessageDlg('Ошибка экспорта сертификата: ' + (IntToStr(GetLastError)), mtError, [mbOK], 0);

 Dispose(PCRYPTUI_CERTCONTEXT); 
 Dispose(PCCRYPTUI); 

Всему виной моя невнимательность
Теперь все работает. Всем спасибо.