#include "global.h" //+------------------------------------------------------------------------- // Private Key file definitions // // The file consists of the FILE_HDR followed by cbEncryptData optional // bytes used to encrypt the private key and then the private key. // The private key is encrypted according to dwEncryptType. // // The public key is included with the private key. //-------------------------------------------------------------------------- typedef struct _FILE_HDR { DWORD dwMagic; DWORD dwVersion; DWORD dwKeySpec; DWORD dwEncryptType; DWORD cbEncryptData; DWORD cbPvk; } FILE_HDR, *PFILE_HDR; // BUGBUG: enum from pvk.h? #ifndef ENTER_PASSWORD #define ENTER_PASSWORD 0 #endif // ENTER_PASSWORD #define PVK_FILE_VERSION_0 0 #define PVK_MAGIC 0xb0b5f11e // Private key encrypt types #define PVK_NO_ENCRYPT 0 #define MAX_PVK_FILE_LEN 4096 typedef BOOL (* PFNREAD)(HANDLE h, void * p, DWORD cb); extern DWORD g_dwSubjectStoreFlag; //+------------------------------------------------------------------------- // Read & Write to memory fucntion //-------------------------------------------------------------------------- typedef struct _MEMINFO { BYTE * pb; DWORD cb; DWORD cbSeek; } MEMINFO, * PMEMINFO; static BOOL ReadFromMemory( IN HANDLE h, IN void * p, IN DWORD cb ) { PMEMINFO pMemInfo = (PMEMINFO) h; if (pMemInfo->cbSeek + cb <= pMemInfo->cb) { // copy the bytes memcpy(p, &pMemInfo->pb[pMemInfo->cbSeek], cb); pMemInfo->cbSeek += cb; return TRUE; } else { SetLastError(ERROR_END_OF_MEDIA); return FALSE; } } //+------------------------------------------------------------------------- // Converts the bytes into WCHAR hex // // Needs (cb * 2 + 1) * sizeof(WCHAR) bytes of space in wsz //-------------------------------------------------------------------------- static void BytesToWStr(ULONG cb, void* pv, LPWSTR wsz) { BYTE* pb = (BYTE*) pv; for (ULONG i = 0; i> 4; *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A'; b = *pb & 0x0F; *wsz++ = (b <= 9) ? b + L'0' : (b - 10) + L'A'; pb++; } *wsz++ = 0; } #define UUID_WSTR_BYTES ((sizeof(GUID) * 2 + 1) * sizeof(WCHAR)) //------------------------------------------------------------------------- // // Call GetLastError and convert the return code to HRESULT //-------------------------------------------------------------------------- HRESULT WINAPI SignError () { DWORD dw = GetLastError (); HRESULT hr; if ( dw <= (DWORD) 0xFFFF ) hr = HRESULT_FROM_WIN32 ( dw ); else hr = dw; if ( ! FAILED ( hr ) ) { // somebody failed a call without properly setting an error condition hr = E_UNEXPECTED; } return hr; } static BOOL LoadKeyW( IN HCRYPTPROV hCryptProv, IN HANDLE hRead, IN PFNREAD pfnRead, IN DWORD cbKeyData, IN HWND hwndOwner, IN LPCWSTR pwszKeyName, IN DWORD dwFlags, IN OUT OPTIONAL DWORD *pdwKeySpec ) { BOOL fResult; FILE_HDR Hdr; HCRYPTKEY hKey = 0; BYTE *pbPvk = NULL; DWORD cbPvk; // Read the file header and verify if (!pfnRead(hRead, &Hdr, sizeof(Hdr))) { ERROR_OUT(("can't read in-memory pvk file hdr")); goto BadPvkFile; } ASSERT( Hdr.dwMagic == PVK_MAGIC ); // Treat as a "normal" private key file cbPvk = Hdr.cbPvk; if (Hdr.dwVersion != PVK_FILE_VERSION_0 || Hdr.cbEncryptData > MAX_PVK_FILE_LEN || cbPvk == 0 || cbPvk > MAX_PVK_FILE_LEN) goto BadPvkFile; if (pdwKeySpec) { DWORD dwKeySpec = *pdwKeySpec; *pdwKeySpec = Hdr.dwKeySpec; if (dwKeySpec && dwKeySpec != Hdr.dwKeySpec) { SetLastError(PVK_HELPER_WRONG_KEY_TYPE); goto ErrorReturn; } } // Allocate and read the private key if (NULL == (pbPvk = new BYTE[cbPvk])) goto ErrorReturn; if (!pfnRead(hRead, pbPvk, cbPvk)) goto BadPvkFile; ASSERT(Hdr.dwEncryptType == PVK_NO_ENCRYPT); // Decrypt and import the private key if (!CryptImportKey(hCryptProv, pbPvk, cbPvk, 0, dwFlags, &hKey)) goto ErrorReturn; fResult = TRUE; goto CommonReturn; BadPvkFile: SetLastError(PVK_HELPER_BAD_PVK_FILE); if (pdwKeySpec) *pdwKeySpec = 0; ErrorReturn: fResult = FALSE; CommonReturn: if (pbPvk) delete (pbPvk); if (hKey) CryptDestroyKey(hKey); return fResult; } static BOOL AcquireKeyContextW( IN LPCWSTR pwszProvName, IN DWORD dwProvType, IN HANDLE hRead, IN PFNREAD pfnRead, IN DWORD cbKeyData, IN HWND hwndOwner, IN LPCWSTR pwszKeyName, IN OUT OPTIONAL DWORD *pdwKeySpec, OUT HCRYPTPROV *phCryptProv ) { BOOL fResult; HCRYPTPROV hProv = 0; GUID TmpContainerUuid; LPWSTR pwszTmpContainer = NULL; // Create a temporary keyset to load the private key into // UuidCreate(&TmpContainerUuid); if (CoCreateGuid((GUID *)&TmpContainerUuid) != S_OK) { goto ErrorReturn; } if (NULL == (pwszTmpContainer = (LPWSTR) new BYTE[ 6 * sizeof(WCHAR) + UUID_WSTR_BYTES])) goto ErrorReturn; LStrCpyW(pwszTmpContainer, L"TmpKey"); BytesToWStr(sizeof(UUID), &TmpContainerUuid, pwszTmpContainer + 6); if (!CryptAcquireContextU( &hProv, pwszTmpContainer, pwszProvName, dwProvType, CRYPT_NEWKEYSET | ( g_dwSubjectStoreFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE ? CRYPT_MACHINE_KEYSET : 0 ))) goto ErrorReturn; if (!LoadKeyW( hProv, hRead, pfnRead, cbKeyData, hwndOwner, pwszKeyName, 0, // dwFlags pdwKeySpec )) goto DeleteKeySetReturn; fResult = TRUE; goto CommonReturn; DeleteKeySetReturn: CryptReleaseContext(hProv, 0); CryptAcquireContextU( &hProv, pwszTmpContainer, pwszProvName, dwProvType, CRYPT_DELETEKEYSET ); hProv = 0; ErrorReturn: if (hProv) { CryptReleaseContext(hProv, 0); hProv = 0; } fResult = FALSE; CommonReturn: if (pwszTmpContainer) { delete (pwszTmpContainer); } *phCryptProv = hProv; return fResult; } //+------------------------------------------------------------------------- // Creates a temporary container in the provider and loads the private key // from memory. // For success, returns a handle to a cryptographic provider for the private // key and the name of the temporary container. PrivateKeyReleaseContext must // be called to release the hCryptProv and delete the temporary container. // // PrivateKeyLoadFromMemory is called to load the private key into the // temporary container. //-------------------------------------------------------------------------- BOOL WINAPI PvkPrivateKeyAcquireContextFromMemory( IN LPCWSTR pwszProvName, IN DWORD dwProvType, IN BYTE *pbData, IN DWORD cbData, IN HWND hwndOwner, IN LPCWSTR pwszKeyName, IN OUT OPTIONAL DWORD *pdwKeySpec, OUT HCRYPTPROV *phCryptProv ) { HRESULT hr = S_OK; if(FAILED(hr)) return FALSE; MEMINFO MemInfo; MemInfo.pb = pbData; MemInfo.cb = cbData; MemInfo.cbSeek = 0; BOOL fhr = AcquireKeyContextW( pwszProvName, dwProvType, (HANDLE) &MemInfo, ReadFromMemory, cbData, hwndOwner, pwszKeyName, pdwKeySpec, phCryptProv ); return fhr; } //+------------------------------------------------------------------------- // Releases the cryptographic provider and deletes the temporary container // created by PrivateKeyAcquireContext or PrivateKeyAcquireContextFromMemory. //-------------------------------------------------------------------------- BOOL WINAPI PvkPrivateKeyReleaseContext( IN HCRYPTPROV hCryptProv, IN LPCWSTR pwszProvName, IN DWORD dwProvType, IN LPWSTR pwszTmpContainer ) { HRESULT hr = S_OK; if (hCryptProv) CryptReleaseContext(hCryptProv, 0); if (pwszTmpContainer) { // Delete the temporary container for the private key from // the provider // // Note: for CRYPT_DELETEKEYSET, the returned hCryptProv is undefined // and must not be released. CryptAcquireContextU( &hCryptProv, pwszTmpContainer, pwszProvName, dwProvType, CRYPT_DELETEKEYSET ); delete (pwszTmpContainer); } return TRUE; } //+------------------------------------------------------------------------- // Get crypto provider to based on either the pvkfile or key container name //-------------------------------------------------------------------------- HRESULT WINAPI PvkGetCryptProv( IN HWND hwnd, IN LPCWSTR pwszCaption, IN LPCWSTR pwszCapiProvider, IN DWORD dwProviderType, IN LPCWSTR pwszPvkFile, IN LPCWSTR pwszKeyContainerName, IN DWORD *pdwKeySpec, OUT LPWSTR *ppwszTmpContainer, OUT HCRYPTPROV *phCryptProv) { HANDLE hFile=NULL; HRESULT hr=E_FAIL; DWORD dwRequiredKeySpec=0; //Init *ppwszTmpContainer=NULL; *phCryptProv=NULL; //get the provider handle based on the key container name if(!CryptAcquireContextU(phCryptProv, pwszKeyContainerName, pwszCapiProvider, dwProviderType, ( g_dwSubjectStoreFlag == CERT_SYSTEM_STORE_LOCAL_MACHINE ? CRYPT_MACHINE_KEYSET : 0 ))) return SignError(); dwRequiredKeySpec=*pdwKeySpec; //make sure *pdwKeySpec is the correct key spec HCRYPTKEY hPubKey; if (CryptGetUserKey( *phCryptProv, dwRequiredKeySpec, &hPubKey )) { CryptDestroyKey(hPubKey); *pdwKeySpec=dwRequiredKeySpec; return S_OK; } else { // Doesn't have the specified public key hr=SignError(); CryptReleaseContext(*phCryptProv, 0); *phCryptProv=NULL; return hr; } } void WINAPI PvkFreeCryptProv(IN HCRYPTPROV hProv, IN LPCWSTR pwszCapiProvider, IN DWORD dwProviderType, IN LPWSTR pwszTmpContainer) { if (pwszTmpContainer) { // Delete the temporary container for the private key from // the provider PvkPrivateKeyReleaseContext(hProv, pwszCapiProvider, dwProviderType, pwszTmpContainer); } else { if (hProv) CryptReleaseContext(hProv, 0); } }