필자가 작성한 응용 프로그램의 일부로 내 프로그램이 로컬 컴퓨터에 인증서를 임시로 설치하고 연결할 때 WinHTTP에서 클라이언트 인증서로 사용하기를 바랍니다. 웹 서버. 이 목적은 무단 액세스로부터 웹 서버를 보호하는 것입니다 (이 인증서는 보안 계층 일 뿐이며 누군가가 .exe에서 압축을 풀 수 있음을 알고 있습니다). 사용자가 인증서를 설치하지 않아도되고 응용 프로그램이 실행되고 있지 않을 때 인증서를 PC에 남기지 않으려합니다. 순간 임시 클라이언트 인증서 (개인 키 포함) 만들기
, 나는이 노력하고있어 :은 .P12 파일
사용은 C++ 응용 프로그램 로컬 인증서에서와 C 배열에 바이너리 데이터를 얻을 수에서 인증서를 수동으로 설치 내 응용 프로그램에
제거 인증서
(CryptExportKey 및 PCCERT_CONTEXT :: pbCertEncoded 사용) 할 때 응용 프로그램 부츠 :
,363,210열기 인증서에 대한 임시 저장소에 개인 키를 저장하는 곳 얻을 수있는 인증서를
CertAddEncodedCertificateToStore(m_certificateStoreHandle,
X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
reinterpret_cast< const BYTE * >(certificateData),
dataSize,
CERT_STORE_ADD_REPLACE_EXISTING,
&m_clientCertificate)
통화 CryptAcquireContext를 추가 할 수
m_certificateStoreHandle = CertOpenStore(CERT_STORE_PROV_MEMORY, 0, NULL, 0, NULL);
통화 CertAddEncodedCertificateToStore (I 각 실행에 키의 이름을 변경 순간 - 이상적으로 나는 키 비에 영구를 만들기 위해 CRYPT_VERIFYCONTEXT를 사용하려면,하지만 지금은 무시하는 일)
HCRYPTPROV cryptProvider = NULL;
HCRYPTKEY cryptKey = NULL;
CryptAcquireContext(&cryptProvider, "MyTestKeyNumber123", NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET)
입니다전화 CryptImportKey 내가 개인 키에 액세스 할 수 있는지 확인 (개인 키
char containerName[128];
DWORD containerNameSize = ARRAY_NUM_BYTES(containerName);
char providerName[128];
DWORD providerNameSize = ARRAY_NUM_BYTES(providerName);
CryptGetProvParam(cryptProvider, PP_CONTAINER, reinterpret_cast<byte *>(containerName), &containerNameSize, 0)
CryptGetProvParam(cryptProvider, PP_NAME, reinterpret_cast<byte *>(providerName), &providerNameSize, 0)
WCHAR containerNameWide[128];
convertCharToWChar(containerNameWide, containerName);
WCHAR providerNameWide[128];
convertCharToWChar(providerNameWide, providerName);
CRYPT_KEY_PROV_INFO privateKeyData;
neMemZero(&privateKeyData, sizeof(privateKeyData));
privateKeyData.pwszContainerName = containerNameWide;
privateKeyData.pwszProvName = providerNameWide;
privateKeyData.dwProvType = 0;
privateKeyData.dwFlags = CRYPT_SILENT;
privateKeyData.dwKeySpec = AT_KEYEXCHANGE;
if (CertSetCertificateContextProperty(m_clientCertificate, CERT_KEY_PROV_INFO_PROP_ID, 0, &privateKeyData))
에 작품을 인증서를 연결하는 키 저장소에
CryptImportKey(cryptProvider, reinterpret_cast< BYTE * >(privateKey), keySize, 0, CRYPT_EXPORTABLE, &cryptKey)
전화 CertSetCertificateContextProperty를 개인 키를로드, 정확히 같은 출력 내가) 응용 프로그램에 클라이언트 인증서의 작동을 확인하는
byte privateKeyBuffer[2048];
DWORD privateKeyBufferSize = ARRAY_NUM_BYTES(privateKeyBuffer);
memZero(privateKeyBuffer, privateKeyBufferSize);
if(CryptExportKey(cryptKey, 0, PRIVATEKEYBLOB, 0, privateKeyBuffer, &privateKeyBufferSize))
{
TRACE("Got private key!");
LOG_BUFFER(privateKeyBuffer, privateKeyBufferSize);
}
시도를 하드 코딩 한대로 데이터예상대로
char certNameBuffer[128] = "";
char certUrlBuffer[128] = "";
CertGetNameString(testValue, CERT_NAME_FRIENDLY_DISPLAY_TYPE, 0, NULL, certNameBuffer, ARRAY_NUM_BYTES(certNameBuffer));
CertGetNameString(testValue, CERT_NAME_URL_TYPE , 0, NULL, certUrlBuffer, ARRAY_NUM_BYTES(certUrlBuffer));
TRACE("SSL Certificate %s [%s]", certNameBuffer, certUrlBuffer);
HCRYPTPROV_OR_NCRYPT_KEY_HANDLE privateKey;
DWORD privateKeyType;
BOOL freeKeyAfter = false;
if(CryptAcquireCertificatePrivateKey(testValue, CRYPT_ACQUIRE_NO_HEALING, NULL, &privateKey, &privateKeyType, &freeKeyAfter))
{
HCRYPTPROV privateKeyProvider = static_cast<HCRYPTPROV>(privateKey);
HCRYPTKEY privateKeyHandle;
if(CryptGetUserKey(privateKeyProvider, privateKeyType, &privateKeyHandle))
{
NEbyte privateKeyBuffer[2048];
DWORD privateKeyBufferSize = NE_ARRAY_NUM_BYTES(privateKeyBuffer);
neMemZero(privateKeyBuffer, privateKeyBufferSize);
if(CryptExportKey(privateKeyHandle, 0, PRIVATEKEYBLOB, 0, privateKeyBuffer, &privateKeyBufferSize))
{
NE_TRACE("Got private key!");
HTTP_LOG_BUFFER(neGetGlobalTraceLog(), "Key", "", privateKeyBuffer, privateKeyBufferSize);
}
이 단계에서는 개인 키가 발견되었지만 NTE_BAD_KEY_STATE를 사용하면 CryptExportKey에 대한 호출이 실패합니다. WinHTTP에서 클라이언트 인증서를 사용하려고하면 ERROR_WINHTTP_CLIENT_CERT_NO_ACCESS_PRIVATE_KEY가 표시됩니다. 내가 함께 개인 키와 인증서를 연결 어떻게 든 할 수있을 때까지,
if (!WinHttpSetOption(handle,
WINHTTP_OPTION_CLIENT_CERT_CONTEXT,
const_cast<PCERT_CONTEXT>(m_clientCertificate),
sizeof(CERT_CONTEXT)))
{
HTTP_LOG_ERROR(getLog(), "Setting the client certificate failed with error code %x", GetLastError());
}
나는 그것을 볼 수있는 방법을 내가 사용할 수 있도록합니다 사람이 궁금해하는 경우,이 코드와 클라이언트 인증서를 사용하여 WinHTTP에게 CryptExcryptionKey를 사용하여 키 데이터를 다시 가져 오는 CryptAcquireCertificatePrivateKey는 WinHTTP가 성공할 기회를 제공하지 않습니다.
내 인증서가 개인 키를 사용하지 못하는 이유에 대한 의견이 있으십니까?