You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
616 lines
17 KiB
616 lines
17 KiB
/*++
|
|
|
|
Copyright (C) 1996, 1997 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
nt5wrap.cpp
|
|
|
|
Abstract:
|
|
|
|
Client side CryptXXXData calls.
|
|
|
|
Client funcs are preceeded by "CS" == Client Side
|
|
Server functions are preceeded by "SS" == Server Side
|
|
|
|
Author:
|
|
|
|
Scott Field (sfield) 14-Aug-97
|
|
|
|
Revisions:
|
|
|
|
Todds 04-Sep-97 Ported to .dll
|
|
Matt Thomlinson (mattt) 09-Oct-97 Moved to common area for link by crypt32
|
|
philh 03-Dec-97 Added I_CertProtectFunction
|
|
philh 29-Sep-98 Renamed I_CertProtectFunction to
|
|
I_CertCltProtectFunction.
|
|
I_CertProtectFunction was moved to
|
|
..\ispu\pki\certstor\protroot.cpp
|
|
|
|
--*/
|
|
|
|
#ifndef _CRYPT32_
|
|
#define _CRYPT32_ // use correct Dll Linkage
|
|
#endif
|
|
|
|
#include <nt.h>
|
|
#include <ntrtl.h>
|
|
#include <nturtl.h>
|
|
#include <windows.h>
|
|
#include <wincrypt.h>
|
|
#include <cryptui.h>
|
|
#include <sha.h>
|
|
#include "crypt.h"
|
|
|
|
#include <lm.h>
|
|
#include <malloc.h>
|
|
|
|
#include "unicode.h"
|
|
#include "certprot.h"
|
|
|
|
// midl generated files
|
|
#include "dprpc.h"
|
|
|
|
#include "dpapiprv.h"
|
|
|
|
|
|
// fwds
|
|
RPC_STATUS BindW(
|
|
WCHAR **pszBinding,
|
|
RPC_BINDING_HANDLE *phBind
|
|
);
|
|
|
|
RPC_STATUS BindBackupKeyW(
|
|
LPCWSTR szComputerName,
|
|
WCHAR **pszBinding,
|
|
RPC_BINDING_HANDLE *phBind
|
|
);
|
|
|
|
RPC_STATUS UnbindW(
|
|
WCHAR **pszBinding,
|
|
RPC_BINDING_HANDLE *phBind
|
|
);
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
CryptProtectData(
|
|
DATA_BLOB* pDataIn,
|
|
LPCWSTR szDataDescr,
|
|
DATA_BLOB* pOptionalEntropy,
|
|
PVOID pvReserved,
|
|
CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
|
|
DWORD dwFlags,
|
|
DATA_BLOB* pDataOut)
|
|
{
|
|
RPC_BINDING_HANDLE h = NULL;
|
|
LPWSTR pszBinding;
|
|
RPC_STATUS RpcStatus;
|
|
|
|
BYTE rgbPasswordHash[ A_SHA_DIGEST_LEN ];
|
|
LPCWSTR wszDescription = szDataDescr?szDataDescr:L"";
|
|
LPWSTR szAlternateDataDescription = (LPWSTR)wszDescription;
|
|
DWORD dwRetVal = ERROR_INVALID_PARAMETER;
|
|
PBYTE pbTempIn = NULL;
|
|
DWORD cbTempIn;
|
|
|
|
// check params
|
|
if ((pDataOut == NULL) ||
|
|
(pDataIn == NULL) ||
|
|
(pDataIn->pbData == NULL))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
RpcStatus = BindW(&pszBinding, &h);
|
|
if(RpcStatus != RPC_S_OK)
|
|
{
|
|
SetLastError(RpcStatus);
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
PBYTE pbOptionalPassword = NULL;
|
|
DWORD cbOptionalPassword = 0;
|
|
SSCRYPTPROTECTDATA_PROMPTSTRUCT PromptStruct;
|
|
SSCRYPTPROTECTDATA_PROMPTSTRUCT *pLocalPromptStruct = NULL;
|
|
|
|
// zero so client stub allocates
|
|
ZeroMemory(pDataOut, sizeof(DATA_BLOB));
|
|
|
|
//
|
|
// only call UI function if prompt flags dictate, because we don't
|
|
// want to bring in cryptui.dll unless necessary.
|
|
//
|
|
|
|
if( (pPromptStruct != NULL) &&
|
|
((pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_UNPROTECT) ||
|
|
(pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_ON_PROTECT))
|
|
)
|
|
{
|
|
|
|
dwRetVal = I_CryptUIProtect(
|
|
pDataIn,
|
|
pPromptStruct,
|
|
dwFlags,
|
|
(PVOID*)&szAlternateDataDescription,
|
|
TRUE,
|
|
rgbPasswordHash
|
|
);
|
|
|
|
//
|
|
// If UI dictated strong security, then supply the hash.
|
|
//
|
|
|
|
if( pPromptStruct->dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
|
|
{
|
|
cbOptionalPassword = sizeof(rgbPasswordHash);
|
|
pbOptionalPassword = rgbPasswordHash;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
dwRetVal = ERROR_SUCCESS;
|
|
}
|
|
|
|
|
|
//
|
|
// Temporarily encrypt the input buffer, so that it's protected
|
|
// in the case where RPC leaves memory buffers laying around.
|
|
//
|
|
|
|
if( dwRetVal == ERROR_SUCCESS )
|
|
{
|
|
DWORD cbPadding;
|
|
NTSTATUS Status;
|
|
|
|
cbPadding = RTL_ENCRYPT_MEMORY_SIZE - pDataIn->cbData % RTL_ENCRYPT_MEMORY_SIZE;
|
|
|
|
cbTempIn = pDataIn->cbData + cbPadding;
|
|
pbTempIn = (PBYTE)LocalAlloc(LMEM_FIXED, cbTempIn);
|
|
if(pbTempIn != NULL)
|
|
{
|
|
CopyMemory(pbTempIn, pDataIn->pbData, pDataIn->cbData);
|
|
FillMemory(pbTempIn + pDataIn->cbData, cbPadding, (BYTE)cbPadding);
|
|
}
|
|
else
|
|
{
|
|
dwRetVal = ERROR_OUTOFMEMORY;
|
|
}
|
|
|
|
if( dwRetVal == ERROR_SUCCESS )
|
|
{
|
|
Status = RtlEncryptMemory(pbTempIn,
|
|
cbTempIn,
|
|
RTL_ENCRYPT_OPTION_SAME_LOGON);
|
|
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
dwRetVal = ERROR_ENCRYPTION_FAILED;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// Call over to the lsass.exe process, where the input buffer will be
|
|
// encrypted using the appropriate user (or machine) credentials.
|
|
//
|
|
|
|
if( dwRetVal == ERROR_SUCCESS )
|
|
{
|
|
if(pPromptStruct != NULL)
|
|
{
|
|
ZeroMemory(&PromptStruct, sizeof(PromptStruct));
|
|
PromptStruct.cbSize = sizeof(PromptStruct);
|
|
PromptStruct.dwPromptFlags = pPromptStruct->dwPromptFlags;
|
|
pLocalPromptStruct = &PromptStruct;
|
|
}
|
|
|
|
dwRetVal = SSCryptProtectData(
|
|
h,
|
|
&pDataOut->pbData,
|
|
&pDataOut->cbData,
|
|
pbTempIn,
|
|
cbTempIn,
|
|
szAlternateDataDescription,
|
|
(pOptionalEntropy) ? pOptionalEntropy->pbData : NULL,
|
|
(pOptionalEntropy) ? pOptionalEntropy->cbData : 0,
|
|
pLocalPromptStruct,
|
|
dwFlags,
|
|
pbOptionalPassword,
|
|
cbOptionalPassword
|
|
);
|
|
}
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
dwRetVal = GetExceptionCode();
|
|
}
|
|
|
|
UnbindW(&pszBinding, &h);
|
|
|
|
RtlSecureZeroMemory( rgbPasswordHash, sizeof(rgbPasswordHash) );
|
|
|
|
if( szAlternateDataDescription &&
|
|
szAlternateDataDescription != wszDescription )
|
|
{
|
|
LocalFree( szAlternateDataDescription );
|
|
}
|
|
|
|
if(pbTempIn != NULL)
|
|
{
|
|
RtlSecureZeroMemory(pbTempIn, cbTempIn);
|
|
LocalFree(pbTempIn);
|
|
}
|
|
|
|
if(dwRetVal != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(dwRetVal);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
BOOL
|
|
WINAPI
|
|
CryptUnprotectData(
|
|
DATA_BLOB* pDataIn, // in encr blob
|
|
LPWSTR* ppszDataDescr, // out
|
|
DATA_BLOB* pOptionalEntropy,
|
|
PVOID pvReserved,
|
|
CRYPTPROTECT_PROMPTSTRUCT* pPromptStruct,
|
|
DWORD dwFlags,
|
|
DATA_BLOB* pDataOut)
|
|
{
|
|
RPC_BINDING_HANDLE h = NULL;
|
|
LPWSTR pszBinding;
|
|
RPC_STATUS RpcStatus;
|
|
|
|
BYTE rgbPasswordHash[ A_SHA_DIGEST_LEN ];
|
|
DWORD dwRetVal;
|
|
DWORD dwRetryCount = 0;
|
|
|
|
// check params
|
|
if ((pDataOut == NULL) ||
|
|
(pDataIn == NULL) ||
|
|
(pDataIn->pbData == NULL))
|
|
{
|
|
SetLastError(ERROR_INVALID_PARAMETER);
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
RpcStatus = BindW(&pszBinding, &h);
|
|
if(RpcStatus != RPC_S_OK)
|
|
{
|
|
SetLastError(RpcStatus);
|
|
return FALSE;
|
|
}
|
|
|
|
__try {
|
|
CRYPTPROTECT_PROMPTSTRUCT DerivedPromptStruct;
|
|
PBYTE pbOptionalPassword = NULL;
|
|
DWORD cbOptionalPassword = 0;
|
|
LPCWSTR szDataDescr;
|
|
LPUWSTR szDataDescrUnaligned;
|
|
SSCRYPTPROTECTDATA_PROMPTSTRUCT PromptStruct;
|
|
SSCRYPTPROTECTDATA_PROMPTSTRUCT *pLocalPromptStruct = NULL;
|
|
|
|
//
|
|
// define outer+inner wrapper for security blob.
|
|
// this won't be necessary once SAS support is provided by the OS.
|
|
//
|
|
|
|
typedef struct {
|
|
DWORD dwOuterVersion;
|
|
GUID guidProvider;
|
|
|
|
DWORD dwVersion;
|
|
GUID guidMK;
|
|
DWORD dwPromptFlags;
|
|
DWORD cbDataDescr;
|
|
WCHAR szDataDescr[1];
|
|
} sec_blob, *psec_blob;
|
|
|
|
sec_blob UNALIGNED *SecurityBlob = (sec_blob*)(pDataIn->pbData);
|
|
|
|
|
|
//
|
|
// zero so client stub allocates
|
|
//
|
|
|
|
ZeroMemory(pDataOut, sizeof(DATA_BLOB));
|
|
|
|
if (ppszDataDescr)
|
|
*ppszDataDescr = NULL;
|
|
|
|
|
|
//
|
|
// recreate the promptstruct and DataDescr from the security blob.
|
|
//
|
|
|
|
DerivedPromptStruct.cbSize = sizeof(DerivedPromptStruct);
|
|
DerivedPromptStruct.dwPromptFlags = SecurityBlob->dwPromptFlags;
|
|
|
|
//
|
|
// SecurityBlob may be unaligned. Set szDataDescr to reference
|
|
// an aligned copy.
|
|
//
|
|
|
|
szDataDescrUnaligned = (SecurityBlob->szDataDescr);
|
|
WSTR_ALIGNED_STACK_COPY(&szDataDescr,szDataDescrUnaligned);
|
|
|
|
if( pPromptStruct )
|
|
{
|
|
DerivedPromptStruct.hwndApp = pPromptStruct->hwndApp;
|
|
DerivedPromptStruct.szPrompt = pPromptStruct->szPrompt;
|
|
} else {
|
|
DerivedPromptStruct.szPrompt = NULL;
|
|
DerivedPromptStruct.hwndApp = NULL;
|
|
}
|
|
|
|
|
|
retry:
|
|
|
|
//
|
|
// determine if UI is to be raised, and what type.
|
|
//
|
|
|
|
//
|
|
// only call UI function if prompt flags dictate, because we don't
|
|
// want to bring in cryptui.dll unless necessary.
|
|
//
|
|
|
|
if( ((DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_ON_UNPROTECT) ||
|
|
(DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_ON_PROTECT))
|
|
)
|
|
{
|
|
|
|
dwRetVal = I_CryptUIProtect(
|
|
pDataIn,
|
|
&DerivedPromptStruct,
|
|
dwFlags,
|
|
(PVOID*)&szDataDescr,
|
|
FALSE,
|
|
rgbPasswordHash
|
|
);
|
|
|
|
//
|
|
// If UI dictated strong security, then supply the hash.
|
|
//
|
|
|
|
if( DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
|
|
{
|
|
cbOptionalPassword = sizeof(rgbPasswordHash);
|
|
pbOptionalPassword = rgbPasswordHash;
|
|
}
|
|
|
|
} else {
|
|
if( DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG )
|
|
{
|
|
dwRetVal = ERROR_INVALID_PARAMETER;
|
|
} else {
|
|
dwRetVal = ERROR_SUCCESS;
|
|
}
|
|
}
|
|
|
|
|
|
//
|
|
// make the RPC call to attempt to unprotect the data.
|
|
//
|
|
|
|
if( dwRetVal == ERROR_SUCCESS )
|
|
{
|
|
if(pPromptStruct != NULL)
|
|
{
|
|
ZeroMemory(&PromptStruct, sizeof(PromptStruct));
|
|
PromptStruct.cbSize = sizeof(PromptStruct);
|
|
PromptStruct.dwPromptFlags = pPromptStruct->dwPromptFlags;
|
|
pLocalPromptStruct = &PromptStruct;
|
|
}
|
|
|
|
dwRetVal = SSCryptUnprotectData(
|
|
h,
|
|
&pDataOut->pbData,
|
|
&pDataOut->cbData,
|
|
pDataIn->pbData,
|
|
pDataIn->cbData,
|
|
ppszDataDescr,
|
|
(pOptionalEntropy) ? pOptionalEntropy->pbData : NULL,
|
|
(pOptionalEntropy) ? pOptionalEntropy->cbData : 0,
|
|
pLocalPromptStruct,
|
|
dwFlags,
|
|
pbOptionalPassword,
|
|
cbOptionalPassword
|
|
);
|
|
|
|
if( (dwRetVal == ERROR_INVALID_DATA) &&
|
|
(DerivedPromptStruct.dwPromptFlags & CRYPTPROTECT_PROMPT_STRONG))
|
|
{
|
|
//
|
|
// The data did not decrypt correctly, so warn the user that
|
|
// the password might have been entered incorrectly and let them
|
|
// try it again up to 3 times.
|
|
//
|
|
|
|
I_CryptUIProtectFailure(
|
|
&DerivedPromptStruct,
|
|
dwFlags,
|
|
(PVOID*)&szDataDescr);
|
|
|
|
if( dwRetryCount++ < 3 )
|
|
{
|
|
goto retry;
|
|
}
|
|
}
|
|
|
|
|
|
if(dwRetVal == ERROR_SUCCESS || dwRetVal == CRYPT_I_NEW_PROTECTION_REQUIRED)
|
|
{
|
|
if(pDataOut->cbData > 0)
|
|
{
|
|
NTSTATUS Status;
|
|
DWORD cbPadding;
|
|
|
|
// Decrypt output buffer.
|
|
Status = RtlDecryptMemory(pDataOut->pbData,
|
|
pDataOut->cbData,
|
|
RTL_ENCRYPT_OPTION_SAME_LOGON);
|
|
if(!NT_SUCCESS(Status))
|
|
{
|
|
dwRetVal = ERROR_DECRYPTION_FAILED;
|
|
}
|
|
|
|
// Remove padding
|
|
if(dwRetVal == ERROR_SUCCESS)
|
|
{
|
|
cbPadding = pDataOut->pbData[pDataOut->cbData - 1];
|
|
|
|
if((cbPadding > 0) &&
|
|
(cbPadding <= pDataOut->cbData) &&
|
|
(cbPadding <= RTL_ENCRYPT_MEMORY_SIZE))
|
|
{
|
|
pDataOut->cbData -= cbPadding;
|
|
}
|
|
else
|
|
{
|
|
dwRetVal = ERROR_INVALID_DATA;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
} __except(EXCEPTION_EXECUTE_HANDLER) {
|
|
dwRetVal = GetExceptionCode();
|
|
}
|
|
|
|
RtlSecureZeroMemory( rgbPasswordHash, sizeof(rgbPasswordHash) );
|
|
|
|
UnbindW(&pszBinding, &h);
|
|
|
|
if((dwFlags & CRYPTPROTECT_VERIFY_PROTECTION ) &&
|
|
((CRYPT_I_NEW_PROTECTION_REQUIRED == dwRetVal) ||
|
|
(ERROR_SUCCESS == dwRetVal)))
|
|
{
|
|
SetLastError(dwRetVal);
|
|
return TRUE;
|
|
}
|
|
|
|
if(dwRetVal != ERROR_SUCCESS)
|
|
{
|
|
SetLastError(dwRetVal);
|
|
return FALSE;
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
|
|
C_ASSERT(CRYPTPROTECTMEMORY_SAME_PROCESS == 0);
|
|
C_ASSERT(CRYPTPROTECTMEMORY_CROSS_PROCESS == RTL_ENCRYPT_OPTION_CROSS_PROCESS);
|
|
C_ASSERT(CRYPTPROTECTMEMORY_SAME_LOGON == RTL_ENCRYPT_OPTION_SAME_LOGON);
|
|
|
|
WINCRYPT32API
|
|
BOOL
|
|
WINAPI
|
|
CryptProtectMemory(
|
|
IN OUT LPVOID pDataIn, // in out data to encrypt
|
|
IN DWORD cbDataIn, // multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
|
|
IN DWORD dwFlags
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = RtlEncryptMemory(pDataIn, cbDataIn, dwFlags);
|
|
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
SetLastError( LsaNtStatusToWinError( Status ));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
WINCRYPT32API
|
|
BOOL
|
|
WINAPI
|
|
CryptUnprotectMemory(
|
|
IN OUT LPVOID pDataIn, // in out data to decrypt
|
|
IN DWORD cbDataIn, // multiple of CRYPTPROTECTMEMORY_BLOCK_SIZE
|
|
IN DWORD dwFlags
|
|
)
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
Status = RtlDecryptMemory(pDataIn, cbDataIn, dwFlags);
|
|
|
|
if( NT_SUCCESS(Status) )
|
|
{
|
|
return TRUE;
|
|
}
|
|
|
|
SetLastError( LsaNtStatusToWinError( Status ));
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
|
|
RPC_STATUS BindW(WCHAR **pszBinding, RPC_BINDING_HANDLE *phBind)
|
|
{
|
|
RPC_STATUS status;
|
|
|
|
status = RpcStringBindingComposeW(
|
|
NULL,
|
|
(unsigned short*)DPAPI_LOCAL_PROT_SEQ,
|
|
NULL,
|
|
(unsigned short*)DPAPI_LOCAL_ENDPOINT,
|
|
NULL,
|
|
(unsigned short * *)pszBinding
|
|
);
|
|
|
|
if (status)
|
|
{
|
|
return(status);
|
|
}
|
|
|
|
status = RpcBindingFromStringBindingW((unsigned short *)*pszBinding, phBind);
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
RPC_STATUS UnbindW(WCHAR **pszBinding, RPC_BINDING_HANDLE *phBind)
|
|
{
|
|
RPC_STATUS status;
|
|
|
|
status = RpcStringFreeW((unsigned short **)pszBinding);
|
|
|
|
if (status)
|
|
{
|
|
return(status);
|
|
}
|
|
|
|
RpcBindingFree(phBind);
|
|
|
|
return RPC_S_OK;
|
|
}
|
|
|
|
|
|
void __RPC_FAR * __RPC_API midl_user_allocate(size_t len)
|
|
{
|
|
return LocalAlloc(LMEM_FIXED, len);
|
|
}
|
|
|
|
void __RPC_API midl_user_free(void __RPC_FAR * ptr)
|
|
{
|
|
ZeroMemory(ptr, LocalSize( ptr ));
|
|
LocalFree(ptr);
|
|
}
|
|
|