Статус: Новичок
Группы: Участники
Зарегистрирован: 20.01.2015(UTC) Сообщений: 6  Откуда: moscow
|
Добрый день! Необходимо реализовать вход в систему по ЭЦП, сейчас это работает, но перед тем чтобы пользователь смог войти в систему его сертификат нужно зарегистрировать в системе через КприптоПро. Т.е. каждый человек, желающий войти должен обращаться к администратору, чтобы тот его регистрировал. Сейчас же нужно сделать так, чтобы пользователю не нужно было обращаться к администратору для регистрации сертификата в системе. Это лишнее действие так как есть основная проверка на сервере аутентификации, который проходит каждый пользователь при попытке входа в систему. Сертификат пользователя хранится на рутокене. При регистрации сертификата через криптопро происходит привязка к контейнеру. Ниже приведён код моего решения. Суть в том, чтобы взять первый попавшийся сертификат из рутокена, зарегистрировать его в системе и вот с ним подписать нужные мне данные для аутентификации пользователя. Но это не работает так как при вызове CryptSignMessage вылетает окно в котором нужно выбрать отсутствующий контейнер! Не могу понять в чём причина, потому что контейнер-то с которого извлекался сертификат подключён к системе. Буду рад любой помощи. Код:
#include <windows.h>
#include <wincrypt.h>
#include <stdio.h>
#include <string>
#include <vector>
#include "WinCryptEx.h"
#pragma comment(lib, "Crypt32.lib")
#define MY_ENCODING_TYPE (PKCS_7_ASN_ENCODING | X509_ASN_ENCODING)
#define MAX_BUFFER_SIZE 100000
std::vector<PCCERT_CONTEXT> g_Certificates;
const char secret_phrase[] = "secret phrase";
void logInFile(std::string s) { printf("%s\n", s.c_str()); }
void MyEnumCert()
{
printf("refreshCertificates\n");
HCRYPTPROV hProv = 0;
if (!CryptAcquireContext(&hProv, NULL, NULL, PROV_GOST_2001_DH, CRYPT_VERIFYCONTEXT)) {
printf("CryptAcquireContext failed\n");
return;
}
DWORD fParam = CRYPT_FIRST;
DWORD cnt = 0;
DWORD size = 1000;
BYTE ContName[1000] = "mini_rutoken\0";
BYTE* pbCertBlob = 0;
DWORD dwCertBlob = 0;
PCCERT_CONTEXT certificate = 0;
fParam = CRYPT_FIRST;
while (CryptGetProvParam(hProv, PP_ENUMCONTAINERS, ContName, &size, fParam)) {
printf("Container name: ");
printf((char*)ContName);
printf("\n");
fParam = CRYPT_NEXT;
cnt++;
HCRYPTKEY hKey;
HCRYPTPROV hProv2;
std::wstring name(ContName, ContName + size);
CryptAcquireContextW(&hProv2, name.c_str(), NULL, PROV_GOST_2001_DH, NULL);
if (!CryptGetUserKey(hProv2, AT_KEYEXCHANGE, &hKey)) {
printf("CryptGetUserKey failed\n");
CryptReleaseContext(hProv2, 0);
continue;
}
if (!CryptGetKeyParam(hKey, KP_CERTIFICATE, NULL, &dwCertBlob, NULL)) {
printf("CryptGetKeyParam failed\n");
CryptReleaseContext(hProv2, 0);
continue;
}
pbCertBlob = new BYTE[dwCertBlob];
if (!CryptGetKeyParam(hKey, KP_CERTIFICATE, pbCertBlob, &dwCertBlob, NULL)) {
printf("Get certificate blob failed\n");
delete pbCertBlob;
CryptReleaseContext(hProv2, 0);
continue;
}
CRYPT_KEY_PROV_INFO key;
key.dwProvType = PROV_GOST_2001_DH;
key.dwFlags = NULL;
key.cProvParam = NULL;
key.rgProvParam = NULL;
key.dwKeySpec = AT_KEYEXCHANGE;
certificate = CertCreateCertificateContext(PKCS_7_ASN_ENCODING | X509_ASN_ENCODING, pbCertBlob, dwCertBlob);
if (certificate)
{
const int SUBJECT_NAME_SIZE = 512;
char subjectName[SUBJECT_NAME_SIZE] = "unknown";
CertGetNameString(certificate,
CERT_NAME_ATTR_TYPE,
0,
szOID_COMMON_NAME,
subjectName,
SUBJECT_NAME_SIZE);
CharToOemA(subjectName, subjectName);
printf("Certificate received\nPush certificate: %s\n", subjectName);
//m_certificates.push_back(certificate);
g_Certificates.push_back(certificate);
delete pbCertBlob;
CryptReleaseContext(hProv2, 0);
continue;
}
else
{
delete pbCertBlob;
printf("Error creating certificate context\n");
CryptReleaseContext(hProv2, 0);
continue;
}
}
CryptReleaseContext(hProv, 0);
}
const std::string signMessage(PCCERT_CONTEXT pSignerCertContext,
const BYTE* pbContent,
const DWORD & cbContent)
{
if (pSignerCertContext == NULL)
{
logInFile("Empty certificate received");
return "";
}
bool result = false;
CRYPT_SIGN_MESSAGE_PARA SignPara;
const BYTE *rgpbToBeSigned[1];
DWORD rgcbToBeSigned[1];
BYTE pbEncodedBlob[MAX_BUFFER_SIZE];
ZeroMemory(&SignPara, sizeof CRYPT_SIGN_MESSAGE_PARA);
SignPara.cbSize = sizeof(CRYPT_SIGN_MESSAGE_PARA);
SignPara.dwMsgEncodingType = MY_ENCODING_TYPE;
SignPara.pSigningCert = pSignerCertContext;
SignPara.HashAlgorithm.pszObjId = (LPSTR)szOID_CP_GOST_R3411;
SignPara.HashAlgorithm.Parameters.cbData = 0;
SignPara.pvHashAuxInfo = NULL;
SignPara.cMsgCert = 1;
SignPara.rgpMsgCert = &pSignerCertContext;
SignPara.cMsgCrl = 0;
SignPara.rgpMsgCrl = NULL;
SignPara.cAuthAttr = 0;
SignPara.rgAuthAttr = NULL;
SignPara.cUnauthAttr = 0;
SignPara.rgUnauthAttr = NULL;
SignPara.dwFlags = 0;
SignPara.dwInnerContentType = 0;
// Content to be signed
rgpbToBeSigned[0] = pbContent;
rgcbToBeSigned[0] = cbContent;
DWORD cbEncodedBlob = MAX_BUFFER_SIZE;
logInFile("Start signing");
BOOL success = CryptSignMessage(
&SignPara,
FALSE, // fDetachedSignature,
1, // 1 element in array
rgpbToBeSigned,
rgcbToBeSigned,
pbEncodedBlob,
&cbEncodedBlob
);
if (success)
{
logInFile("Message successfully signed");
std::string value(pbEncodedBlob, pbEncodedBlob + cbEncodedBlob);
return value;
}
else
{
char errorNumber[100];
_itoa(GetLastError(), errorNumber, 16);
logInFile("Message was not signed:");
logInFile(errorNumber);
return "";
}
}
bool addCertToStore(PCCERT_CONTEXT pcert, PCCERT_CONTEXT* pcert_new)
{
HCERTSTORE hSysStore = NULL;
hSysStore = CertOpenStore(
CERT_STORE_PROV_SYSTEM, // The store provider type
/*0*/ MY_ENCODING_TYPE, // The encoding type is not needed
NULL, // Use the default HCRYPTPROV
CERT_SYSTEM_STORE_LOCAL_MACHINE, // Set the store location in a registry location
L"MY" // The store name as a Unicode string
);
//hSysStore = CertOpenSystemStoreW(0, L"MY");
if (hSysStore)
printf("The system store was created successfully.\n");
else{
printf("An error occurred during creation of the system store!\n");
return false;
}
BOOL added = CertAddCertificateContextToStore(hSysStore, pcert, CERT_STORE_ADD_ALWAYS, pcert_new);
//BOOL added = CertAddCertificateContextToStore(hSysStore, pcert, CERT_STORE_ADD_REPLACE_EXISTING, pcert_new);
//BOOL added = CertAddCertificateContextToStore(hSysStore, pcert, CERT_STORE_ADD_USE_EXISTING, pcert_new);
//BOOL added = CertAddCertificateLinkToStore(hSysStore, pcert, CERT_STORE_ADD_REPLACE_EXISTING /*CERT_STORE_ADD_ALWAYS*/, pcert_new);
if (added)
printf("cert was added in system successfully, last error %d ( 0x%x ) \n", GetLastError(), GetLastError());
else
printf("cert wasn't added in system\n");
//CertCloseStore(hSysStore, CERT_CLOSE_STORE_CHECK_FLAG);
return added;
}
int main()
{
MyEnumCert();
if (!g_Certificates.empty())
{
printf("Found certificates %d\n", g_Certificates.size());
PCCERT_CONTEXT pcert = g_Certificates[0], pcert_new, pcert_old = g_Certificates[0];
const DWORD size = sizeof secret_phrase;
if ( addCertToStore(pcert, &pcert_new) )
{
pcert = pcert_new;
printf("change certificates\n");
const std::string s = signMessage(pcert, (const BYTE*)secret_phrase, size);
if (!s.empty())
{
std::string input(secret_phrase);
printf("Input data %d\n\nData: ", input.size());
for (int i = 0; i < s.length() && i < 10; i++) printf("%x:", input.data()[i]);
printf("\n\nSize of signed data %d\n\nData: ", s.size());
for (int i = 0; i < s.length() && i < 10; i++) printf("%x:", s.data()[i]);
}
//if (!CertDeleteCertificateFromStore(pcert_old)) printf("certificate wasn't removed\n");
//if (!CertDeleteCertificateFromStore(pcert_new)) printf("2certificate wasn't removed\n");
} else {
printf("couldn't add!\n");
}
}
printf("\n\npress any key to exit.\n");
getchar();
return 0;
}
|