| ||||
| ||||
Пытаюсь собрать программу #include <afx.h> #include <stdio.h> #include <windows.h> #include <wincrypt.h> #define ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) void main(int carg,LPSTR* args){ CRYPT_DATA_BLOB pPFX; HCERTSTORE hCertStore = NULL; //HCERTSTORE hSystemStore; DWORD dwFlags = CRYPT_USER_KEYSET; HCRYPTPROV hProv = NULL; DWORD dwKeySpec = 0; CFile file; file.Open("iecert.pfx", CFile::modeRead); pPFX.cbData = file.GetLength(); pPFX.pbData = (BYTE*)new char[pPFX.cbData]; file.Read(pPFX.pbData, pPFX.cbData); file.Close(); hCertStore = PFXImportCertStore(&pPFX, L"222", dwFlags); if (hCertStore == NULL) { printf("Cert was not imported\n"); return ; } else { printf("Cert was successfully imported\n"); } } Линковщик VC++6.0 выдает сообщение о невозможности разрешить ссылку unresolved external symbol __imp__PFXImportCertStore@12 Установлена Microsoft SDK, и в настройках VC стоит ссылка на директории include ( wincrypt.h) и lib ( crypt32.lib ) этого SDK. Библиотека crypt32.dll есть в windows\system32. Подскажите, почему ссылка на вызов модуля PFXImportCertStore не разрешается? | ||||
Ответы: | ||||
| ||||
из MSDN Library: Use Advapi32.lib. | ||||
| ||||
Но ведь в этой библиотеке нет программы PFXImportCertStore. | ||||
| ||||
а линкуется именно crypt32.lib из Platform SDK, а не MS VC 6.0? | ||||
| ||||
Проверил. В опциях VC первыми стоят директории из platform SDK ( я устанавливал не весь пакет, а только раздел Internet). Ошибки выглядят так: imptcert.obj : error LNK2001: unresolved external symbol __imp__PFXImportCertStore@12 nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __endthreadex nafxcwd.lib(thrdcore.obj) : error LNK2001: unresolved external symbol __beginthreadex Debug/CertImport.exe : fatal error LNK1120: 3 unresolved externals Я работаю под XP, может быть crypt32.dll не соответствует crypt32.lib из SDK? | ||||
| ||||
у меня этот пример собрался под 2000, действительно, advapi32.lib не нужно. crypt32.dll тут тоже не при чем - ее отсутствие/несоответствие проявилось бы при работе программы а не при сборке. проблема наверняка с crypt32.lib | ||||
| ||||
Поставил VC++6.0 и Internet Development SDK на windows 2000. Программа импорта сертификатов стала разрешаться при линковании. Странно, тоже самое под XP выдавало ошибку. Теперь две последние ошибки не могу победить: __endthreadex и __beginthreadex. Вроде это процедуры работы со средами из стандартных библиотек. Как их то побороть? | ||||
| ||||
в настройке Project Settings->General включите использование MFC | ||||
| ||||
Пришлось подправить код и отказаться от CFile. Вместо этого использую поток fstream. Теперь PFXImportCertStore возвращает значение отличное от NULL. Вопрос в том - куда записывается мой персональный сертификат. Я ожидал увидеть его в IE, но там "Internet Oprions - Content - Certificates - Personal", но он там не появился. Поясните, как надо правильно импортировать персональный сертифика с помощью API. Спасибо. Вот текст программы #include <string> #include <iostream> #include <fstream> #include <windows.h> #include <wincrypt.h> //#include <process.h> using namespace std; #define ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) int main(int carg,LPSTR* args){ CRYPT_DATA_BLOB pPFX; HCERTSTORE hCertStore = NULL; //HCERTSTORE hSystemStore; DWORD dwFlags = CRYPT_USER_KEYSET; HCRYPTPROV hProv = NULL; DWORD dwKeySpec = 0; std::string fileName("iecert.pfx"); std::fstream certFile; char* area; int cnt = 0; certFile.open(fileName.c_str(), ios::in | ios::binary); if ( certFile.is_open == 0 ) { cout << "Error open file " << fileName.c_str() << "\n"; return 1; } area = new char[10000]; certFile.read(area, 10000); cout << "stat=" << certFile.rdstate() << "gcount()=" << certFile.gcount() << "\n"; pPFX.pbData = (BYTE*) area; pPFX.cbData = certFile.gcount(); certFile.close(); hCertStore = PFXImportCertStore(&pPFX, L"222", dwFlags); if (hCertStore == NULL) { cout << "Cert was not imported\n"; return 2; } else { cout <<"Cert was successfully imported\n"; } return 0; } | ||||
| ||||
судя по этому коду, он никуда не записывается, а остается в памяти. если Вы хотите записать его в какое-то постоянное хранилище, то нужно открыть это хранилищие (CertOpenStore), найти контекст сертификата (допустим, перебором - CertEnumCertificatesInStore) в Вашем временном хранилище и после этого добавить его в постоянное (CertAddCertificateContextToStore) | ||||
| ||||
Да, с этим разобрался. Осталось только непонятно - какое хранилище соответствует персональному сертификату в Internet Explorer. Не могу понять. Пробовал записывать в hSystemStore = CertOpenStore( CERT_STORE_PROV_SYSTEM_REGISTRY, 0, hProv, CERT_SYSTEM_STORE_LOCAL_MACHINE , L"MY" а так же комбинацию CERT_SYSTEM_STORE_CURRENT_USER, ’Trust’ В реестре записи появляются, а в IE в разделе ’Personal’ их нет. Какое хранилище выбрать для этого случая? Спасибо | ||||
| ||||
так, попробую по порядку :) в win 2000 личные пользовательские сертификаты хранятся не в реестре, а в папке "Documents and Settings". эксплорер не показывает сертификаты, находящиеся в Local Machine, только в Current User. Для просмотра сертифкатов лучше пользоваться оснасткой MMC "Сертификаты". Trust - это хранилище "Доверительные отношения в предприятии", эксплорер его тоже не показывает. | ||||
| ||||
Прошу извинить за странные вопросы, но не знаю где найти ответ. Читаю сайт MSDN про хранилища. Есть параметр lpszStoreProvider у CertOpenStore со значением CERT_STORE_PROV_FILENAME. Нужно создать store с помощью CreateFile, а затем вызвать CertOpenStore. Посмотрел что создается в файловрй системе если проимпортировать сертификат интерактивно. Имя создаваемого файла впечатляет - несколько десятков шестнадцатиричных цифр. Это в \Documents and Settings\user\Application Data\Microsoft\SystemCertificates\My \Certificates. Так можно ли с помощью CryptoAPI проимпортировать сертификат для Internet Explorer и если да, то как правильно открыть этот Store? Спасибо | ||||
| ||||
конечно можно. хранилище надо открывать например так : hCertStore = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, hProv, CERT_STORE_OPEN_EXISTING_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"MY"); соответсвенно для корневых имя хранилища будет Root, для промежуточных - CA, для других пользователей - AddressBook | ||||
| ||||
Почитал о коллекциях сертификатов и их физическом хранении. Вроде ясно. Подправил программу. Проверил коды завершения всех процедур. Все нормально. Вот только желанный сертификат не хочет появляться ни на диске,ни в "Personal" IE. Может помимо закрытия Store нужно выполнить какое-нибудь подтверждение сохранения. Вот текст программы: #include <string> #include <iostream> #include <fstream> #include <windows.h> #include <wincrypt.h> //#include <process.h> using namespace std; #define ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) int main(int carg,LPSTR* args){ CRYPT_DATA_BLOB pPFX; HCERTSTORE hCertStore = NULL; HCERTSTORE hSystemStore = NULL; HCRYPTPROV hProv = NULL; DWORD dwKeySpec = 0; BOOL shouldIFreeProv = false; DWORD dwFlags = CRYPT_USER_KEYSET; std::string fileName("iecert.pfx"); std::fstream certFile; char* area; int cnt = 0; certFile.open(fileName.c_str(), ios::in | ios::binary); if ( certFile.is_open == 0 ) { cout << "Error open file " << fileName.c_str() << "\n"; return 1; } area = new char[10000]; certFile.read(area, 10000); cout << "stat=" << certFile.rdstate() << "gcount()=" << certFile.gcount() << "\n"; pPFX.pbData = (BYTE*) area; pPFX.cbData = certFile.gcount(); certFile.close(); hCertStore = PFXImportCertStore(&pPFX, L"222", dwFlags); if (hCertStore == NULL) { cout << "Cert was not imported\n"; return 2; } else { cout <<"Cert was successfully imported\n"; } PCCERT_CONTEXT pCert = CertEnumCertificatesInStore(hCertStore, NULL); //X509Certificate* sert = NULL; //String* strCertInfo; if (pCert != NULL) { //open system store hSystemStore = CertOpenStore( CERT_STORE_PROV_SYSTEM, // The memory provider type. 0, hProv, // provider information CERT_STORE_OPEN_EXISTING_FLAG | CERT_SYSTEM_STORE_CURRENT_USER, L"MY" ); if ( hSystemStore == NULL ) { cout << "Error open certificate store\n"; return 5; } //add cert to the store if(!CertAddCertificateContextToStore( hSystemStore, // The store handle pCert, // The pointer to a certificate CERT_STORE_ADD_ALWAYS, //CERT_STORE_ADD_REPLACE_EXISTING, NULL)) { cout << "Certificate was not added to the store. \n" ; } } if(pCert) CertFreeCertificateContext(pCert); if(hProv && shouldIFreeProv) CryptReleaseContext(hProv, 0); if (hSystemStore) CertCloseStore(hSystemStore, 0); return 0; } | ||||
| ||||
Выполнил полный перебор всех контекстов из файла сертификата и загрузил их в постоянное Личное хранилище. Получилось то что ожидалось. Спасибо. while( pCert = CertEnumCertificatesInStore(hCertStore, pCert) ) {; if (pCert != NULL) { cnt++; //add cert into the Store if(!CertAddCertificateContextToStore( hSystemStore, // The store handle pCert, // The pointer to a certificate CERT_STORE_ADD_REPLACE_EXISTING, //CERT_STORE_ADD_ALWAYS, NULL)) { cout << "Certificate was not added to the memory store. \n" ; } } } | ||||