| ||||
| ||||
Привет! Спасибо большое за форум! Задача: В таблице LDSSCertificateStore базы данных LANDOCS есть BLOB Certificate, мне нужно извлечь из этого BLOB-а public key для этого я сохраняю вручную этот BLOB в файл с расширением *.cer (используя PLSQL Developer) затем применяю следующий скрипт в C++ : >> #include "stdafx.h" >> #include <windows.h> >> #include <wincrypt.h> >> #include <stdio.h> >> #include "cptumar.h" >> >> #include <stdlib.h> //atoi() >> >> #include <wtypes.h> >> >> #define BUFSIZE 1024 >> void HandleError(char *s); >> void ErrorExit(LPTSTR lpszFunction); >> >> int _tmain(int argc, _TCHAR* argv[]) >> { >> FILE *hFile; >> FILE *PubKeyFile; >> BYTE rgbFile[BUFSIZE]; >> DWORD cbRead =0; >> BOOL bResult =FALSE; >> HCRYPTPROV hProv = 0; >> HCRYPTKEY hPubKey; >> BYTE pbData[1000]; // 1000 will hold the longest >> // key container name. >> DWORD cbData; >> >> >> hFile =fopen("1.cer", "r+b"); >> if (hFile) >> { >> printf("The file was opened"); >> } >> else >> { >> printf("Error opening file"); >> } >> //return 0; >> >> do >> { >> cbRead =(DWORD)fread(rgbFile,1,BUFSIZE,hFile); >> if (!cbRead) >> { >> >> bResult =TRUE; >> break; >> } >> >> } >> while (!feof(hFile)); >> printf( "Number of items read = %d\n", cbRead ); >> >> //------------------------------------------------------------------ >> #define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING) >> >> PCCERT_CONTEXT pCertContext = NULL; >> >> // Create a new certificate from the encoded part of >> // an available certificate. pDesiredCert is a previously >> // assigned PCCERT_CONTEXT variable. >> >> if(pCertContext = CertCreateCertificateContext( >> MY_ENCODING_TYPE, // The encoding type >> rgbFile, // The encoded data from >> // the certificate retrieved >> cbRead)) // The length of the encoded data >> { >> printf("A new certificate as been created.\n"); >> >> >> >> if (!CryptAcquireContext( >> &hProv, >> NULL, >> NULL, >> 25, >> 0)) >> { >> // dwStatus = GetLastError(); >> printf("CryptAcquireContext failed:"); >> //fclose(hFile); >> //return dwStatus; >> } >> else >> { >> printf("CryptAcquireContext success!!!"); >> } >> >> // Read the name of the default CSP. >> >> cbData = 1000; >> if(CryptGetProvParam( >> hProv, >> PP_NAME, >> pbData, >> &cbData, >> 0)) >> { >> printf("CryptGetProvParam succeeded.\n"); >> printf("Provider name: %s\n", pbData); >> } >> else >> { >> printf("Error reading CSP name. \n"); >> exit(1); >> } >> >> // Read the name of the key container. >> >> cbData = 1000; >> if(CryptGetProvParam( >> hProv, >> PP_CONTAINER, >> pbData, >> &cbData, >> 0)) >> { >> printf("CryptGetProvParam succeeded. \n"); >> printf("Key Container name: %s\n", pbData); >> } >> else >> { >> HandleError("Error reading key container name. \n"); >> } >> >> >> // через функцию CryptAcquireCertificatePrivateKey получаем доступ к CSP >> // одна из самых интересных и полезных функций в CryptoAPI >> /* >> HCRYPTPROV hProv; >> DWORD dwKeySpec; >> BOOL fCallerFreeProv; >> >> if(CryptAcquireCertificatePrivateKey( >> pCertContext, >> CRYPT_ACQUIRE_COMPARE_KEY_FLAG, >> NULL, >> &hProv, >> &dwKeySpec, >> &fCallerFreeProv >> )) >> { >> printf("CryptAcquireCertificatePrivateKey выполнилась успешно!\n"); >> } >> else >> { >> printf(" Error CryptAcquireCertificatePrivateKey.\n"); >> } >> */ >> CERT_INFO *certInfo = pCertContext->pCertInfo; >> CERT_PUBLIC_KEY_INFO keyInfo = certInfo->SubjectPublicKeyInfo; //(pCertContext->>>pCertInfo->SubjectPublicKeyInfo) >> if(CryptImportPublicKeyInfo( >> hProv, >> MY_ENCODING_TYPE, >> &keyInfo, >> &hPubKey >> )) >> { >> printf("Import public key success.\n"); >> PubKeyFile = fopen( "PubKeyFile.txt", "w+b" ); >> >> if(!PubKeyFile) >> printf( "Problem opening the file\n" ); >> >> fwrite (&hPubKey, 1, 500, PubKeyFile); >> } >> else >> { >> HandleError("Error Import public key."); >> } >> >> >> >> >> // Use the certificate context as needed. >> // ... >> >> // When finished, free the certificate context. >> CertFreeCertificateContext(pCertContext); >> >> } >> else >> { >> printf("A new certificate could not be created.\n"); >> // exit(1); >> } >> >> } >> void HandleError(char *s) >> { >> printf("Error. \n"); >> printf("%s\n",s); >> printf("Error number %x\n.", GetLastError()); >> printf("Program terminating. \n"); >> ErrorExit("8009310b"); >> exit(1); >> } >> void ErrorExit(LPTSTR lpszFunction) >> { >> TCHAR szBuf[80]; >> LPVOID lpMsgBuf; >> DWORD dw = GetLastError(); >> >> FormatMessage( >> FORMAT_MESSAGE_ALLOCATE_BUFFER | >> FORMAT_MESSAGE_FROM_SYSTEM, >> NULL, >> dw, >> MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), >> (LPTSTR) &lpMsgBuf, >> 0, NULL ); >> >> wsprintf(szBuf, >> "%s failed with error %d: %s", >> lpszFunction, dw, lpMsgBuf); >> >> MessageBox(NULL, szBuf, "Error", MB_OK); >> >> LocalFree(lpMsgBuf); >> ExitProcess(dw); >> } И когда вызывается функция CryptImportPublicKeyInfo выдает следующее сообщение об ошибке: 8009310b failed with error -2146881269: ASN1 bad tag value met Что я делаю не так? -- | ||||
Ответы: | ||||
| ||||
Если Вы читаете сертификат из файла .cer, то функция CryptAcquireCertificatePrivateKey работать не будет - у такого сертификата нет ссылки на секретный ключ. | ||||
| ||||
Sorry, там у меня закоментировано, т.е. я не использую функцию CryptAcquireCertificatePrivateKey. hProv - я получаю через CryptAcquireContext. | ||||
| ||||
А точно ОК создан дефолтным провайдером 25 типа? | ||||
| ||||
Да. Спасибо. | ||||
| ||||
Мб этот провайдер вообще импорт открытых ключей не поддерживает? | ||||
| ||||
Спасибо Кирилл! Провайдер поддерживает импорт открытых ключей. Я убедился в этом когда выполнял импорт из сертификата который они сами выпустили. Импорт был успешным. А когда я делаю импорт из сертификата который был помещен в базу данных, ну предварительно я этот blob извлекаю оттуда и сохраняю в виде файла с расширением *.cer то импорт failed. Возможно эти черти поместили этот сертификат в БД не в стандартной кодировке ASN1? Намеренно. | ||||
| ||||
Если был неправильный ASN, то CertCreateCertificateContext не проходил бы. А можно им проверить подпись какую-нибудь? | ||||