Leaked source code of windows server 2003
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

/*++
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);
}