424 lines
12 KiB
C++
424 lines
12 KiB
C++
#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<cb; i++) {
|
|
int b;
|
|
b = (*pb & 0xF0) >> 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);
|
|
}
|
|
}
|
|
|
|
|
|
|