|
|
//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1995.
//
// File: callback.c
//
// Contents:
//
// Classes:
//
// Functions:
//
// History: 09-23-97 jbanes Created
//
//----------------------------------------------------------------------------
#include "sslp.h"
SECURITY_STATUS NTAPI SPSignatureCallback( ULONG_PTR hProv, ULONG_PTR aiHash, SecBuffer *pInput, SecBuffer *pOutput);
SECURITY_STATUS NTAPI UploadCertContextCallback( ULONG_PTR Argument1, ULONG_PTR Argument2, SecBuffer *pInput, SecBuffer *pOutput);
SECURITY_STATUS NTAPI UploadCertStoreCallback( ULONG_PTR Argument1, ULONG_PTR Argument2, SecBuffer *pInput, SecBuffer *pOutput);
SECURITY_STATUS NTAPI RemoteCryptAcquireContextCallback( ULONG_PTR dwProvType, ULONG_PTR dwFlags, SecBuffer *pInput, SecBuffer *pOutput);
SECURITY_STATUS RemoteCryptReleaseContextCallback( ULONG_PTR hProv, ULONG_PTR dwFlags, SecBuffer *pInput, SecBuffer *pOutput);
SECURITY_STATUS DownloadCertContextCallback( ULONG_PTR Argument1, ULONG_PTR Argument2, SecBuffer *pInput, SecBuffer *pOutput);
SECURITY_STATUS NTAPI GetUserKeysCallback( ULONG_PTR dwLsaContext, ULONG_PTR dwFlags, SecBuffer *pInput, SecBuffer *pOutput);
SCH_CALLBACK_LIST g_SchannelCallbacks[] = { { SCH_SIGNATURE_CALLBACK, SPSignatureCallback }, { SCH_UPLOAD_CREDENTIAL_CALLBACK, UploadCertContextCallback }, { SCH_UPLOAD_CERT_STORE_CALLBACK, UploadCertStoreCallback }, { SCH_ACQUIRE_CONTEXT_CALLBACK, RemoteCryptAcquireContextCallback }, { SCH_RELEASE_CONTEXT_CALLBACK, RemoteCryptReleaseContextCallback }, { SCH_DOWNLOAD_CERT_CALLBACK, DownloadCertContextCallback }, { SCH_GET_USER_KEYS, GetUserKeysCallback }, };
DWORD g_cSchannelCallbacks = sizeof(g_SchannelCallbacks) / sizeof(SCH_CALLBACK_LIST);
//+---------------------------------------------------------------------------
//
// Function: PerformApplicationCallback
//
// Synopsis: Call back to the application process.
//
// Arguments: [dwCallback] -- Callback function number.
// [dwArg1] --
// [dwArg2] --
// [pInput] --
// [pOutput] --
//
// History: 09-23-97 jbanes Created
//
// Notes:
//
//----------------------------------------------------------------------------
SECURITY_STATUS PerformApplicationCallback( DWORD dwCallback, ULONG_PTR dwArg1, ULONG_PTR dwArg2, SecBuffer *pInput, SecBuffer *pOutput, BOOL fExpectOutput) { SECURITY_STATUS Status; PVOID pvBuffer;
if(LsaTable == NULL) { return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); }
pOutput->BufferType = SECBUFFER_EMPTY; pOutput->pvBuffer = NULL; pOutput->cbBuffer = 0;
try { Status = LsaTable->ClientCallback((PCHAR)ULongToPtr(dwCallback), // Sundown: dwCallback is a function number.
dwArg1, dwArg2, pInput, pOutput); } except(EXCEPTION_EXECUTE_HANDLER) { Status = SP_LOG_RESULT(SEC_E_UNSUPPORTED_FUNCTION); } if ( !NT_SUCCESS( Status ) ) { return SP_LOG_RESULT( Status ); } if(Status != SEC_E_OK) { SP_LOG_RESULT( Status ); return SEC_E_INTERNAL_ERROR; }
if(pOutput->pvBuffer && pOutput->cbBuffer) { pvBuffer = SPExternalAlloc(pOutput->cbBuffer); if(pvBuffer == NULL) { return SP_LOG_RESULT( SEC_E_INSUFFICIENT_MEMORY ); }
Status = LsaTable->CopyFromClientBuffer(NULL, pOutput->cbBuffer, pvBuffer, pOutput->pvBuffer );
if ( !NT_SUCCESS( Status ) ) { SPExternalFree(pvBuffer); return SP_LOG_RESULT( Status ); }
Status = SPFreeUserAllocMemory(pOutput->pvBuffer, pOutput->cbBuffer);
if ( !NT_SUCCESS( Status ) ) { SPExternalFree(pvBuffer); return SP_LOG_RESULT( Status ); }
pOutput->pvBuffer = pvBuffer; } else if(fExpectOutput) { return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); }
return Status; }
#if 0
// This helper function is called by the LSA process in order to duplicate
// a handle belonging to the application process.
BOOL DuplicateApplicationHandle( HANDLE hAppHandle, LPHANDLE phLsaHandle) { SECPKG_CALL_INFO CallInfo; HANDLE hAppProcess; HANDLE hLsaProcess; BOOL fResult;
// Get handle to application process.
if(!LsaTable->GetCallInfo(&CallInfo)) { return FALSE; } hAppProcess = OpenProcess(PROCESS_DUP_HANDLE, FALSE, CallInfo.ProcessId); if(hAppProcess == NULL) { return FALSE; }
// Get handle to lsa process.
hLsaProcess = GetCurrentProcess();
// Duplicate handle
fResult = DuplicateHandle(hAppProcess, hAppHandle, hLsaProcess, phLsaHandle, 0, FALSE, DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE);
CloseHandle(hAppProcess); CloseHandle(hLsaProcess);
return fResult; } #endif
//+---------------------------------------------------------------------------
//
// Function: RemoteCryptAcquireContextCallback
//
// Synopsis: Obtain a CSP context handle, using the information passed
// in the input buffer.
//
// Arguments: [dwProvType] -- Provider type.
// [dwFlags] -- Flags.
// [pInput] -- Buffer containing provider info.
// [pOutput] -- Buffer containing CSP context handle.
//
// History: 09-24-97 jbanes Created
//
// Notes: The structure of the input buffer is as follows:
//
// cbContainerName
// cbProvName
// wszContainerName
// wszProvName
//
// This function always uses an actual CSP.
//
//----------------------------------------------------------------------------
SECURITY_STATUS RemoteCryptAcquireContextCallback( ULONG_PTR dwProvType, // in
ULONG_PTR dwFlags, // in
SecBuffer *pInput, // in
SecBuffer *pOutput) // out
{ LPWSTR pwszContainerName; DWORD cbContainerName; LPWSTR pwszProvName; DWORD cbProvName; HCRYPTPROV hProv; LPBYTE pbBuffer; DWORD cbBuffer;
if(!SchannelInit(TRUE)) { return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); }
DebugLog((DEB_TRACE, "RemoteCryptAcquireContextCallback\n"));
pOutput->BufferType = SECBUFFER_DATA; pOutput->cbBuffer = 0; pOutput->pvBuffer = NULL;
if(pInput->pvBuffer == NULL) { return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); }
// Parse input buffer.
pbBuffer = pInput->pvBuffer; cbBuffer = pInput->cbBuffer;
if(cbBuffer < sizeof(DWORD) * 2) { return SP_LOG_RESULT(SEC_E_INCOMPLETE_MESSAGE); }
cbContainerName = *(DWORD *)pbBuffer; pbBuffer += sizeof(DWORD);
cbProvName = *(DWORD *)pbBuffer; pbBuffer += sizeof(DWORD);
if(cbBuffer < sizeof(DWORD) * 2 + cbContainerName + cbProvName) { return SP_LOG_RESULT(SEC_E_INCOMPLETE_MESSAGE); }
if(cbContainerName) { pwszContainerName = (LPWSTR)pbBuffer; } else { pwszContainerName = NULL; } pbBuffer += cbContainerName;
if(cbProvName) { pwszProvName = (LPWSTR)pbBuffer; } else { pwszProvName = NULL; }
// HACKHACK - clear the smart-card specific flag.
dwFlags &= ~CERT_SET_KEY_CONTEXT_PROP_ID;
DebugLog((SP_LOG_TRACE, "Container:%ls\n", pwszContainerName)); DebugLog((SP_LOG_TRACE, "Provider: %ls\n", pwszProvName)); DebugLog((SP_LOG_TRACE, "Type: 0x%8.8x\n", dwProvType)); DebugLog((SP_LOG_TRACE, "Flags: 0x%8.8x\n", dwFlags));
// Attempt to get CSP context handle.
if(!CryptAcquireContextW(&hProv, pwszContainerName, pwszProvName, (DWORD) dwProvType, (DWORD) dwFlags)) { return SP_LOG_RESULT(GetLastError()); }
// Allocate memory for the output buffer.
pOutput->BufferType = SECBUFFER_DATA; pOutput->cbBuffer = sizeof(HCRYPTPROV); pOutput->pvBuffer = PvExtVirtualAlloc(pOutput->cbBuffer); if(pOutput->pvBuffer == NULL) { return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); }
// Place hProv in output buffer.
*(HCRYPTPROV *)pOutput->pvBuffer = hProv;
return SEC_E_OK; }
NTSTATUS RemoteCryptAcquireContextW( HCRYPTPROV *phProv, LPCWSTR pwszContainerName, LPCWSTR pwszProvName, DWORD dwProvType, DWORD dwFlags) { SecBuffer Input; SecBuffer Output; DWORD cbContainerName; DWORD cbProvName; PBYTE pbBuffer; SECURITY_STATUS scRet;
// Build input buffer.
if(pwszContainerName) { cbContainerName = (lstrlenW(pwszContainerName) + 1) * sizeof(WCHAR); } else { cbContainerName = 0; } if(pwszProvName) { cbProvName = (lstrlenW(pwszProvName) + 1) * sizeof(WCHAR); } else { cbProvName = 0; }
Input.BufferType = SECBUFFER_DATA; Input.cbBuffer = sizeof(DWORD) + sizeof(DWORD) + cbContainerName + cbProvName; SafeAllocaAllocate(Input.pvBuffer, Input.cbBuffer); if(Input.pvBuffer == NULL) { return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); }
pbBuffer = Input.pvBuffer;
*(DWORD *)pbBuffer = cbContainerName; pbBuffer += sizeof(DWORD); *(DWORD *)pbBuffer = cbProvName; pbBuffer += sizeof(DWORD);
CopyMemory(pbBuffer, pwszContainerName, cbContainerName); pbBuffer += cbContainerName;
CopyMemory(pbBuffer, pwszProvName, cbProvName); pbBuffer += cbProvName;
// Do callback.
scRet = PerformApplicationCallback( SCH_ACQUIRE_CONTEXT_CALLBACK, dwProvType, dwFlags, &Input, &Output, TRUE); if(!NT_SUCCESS(scRet)) { DebugLog((SP_LOG_ERROR, "Error 0x%x calling remote CryptAcquireContext\n", scRet)); SafeAllocaFree(Input.pvBuffer); return scRet; }
// Get hProv from output buffer.
*phProv = *(HCRYPTPROV *)Output.pvBuffer;
DebugLog((SP_LOG_TRACE, "Remote CSP handle retrieved (0x%x)\n", *phProv));
SafeAllocaFree(Input.pvBuffer); SPExternalFree(Output.pvBuffer);
return SEC_E_OK; }
SECURITY_STATUS RemoteCryptReleaseContextCallback( ULONG_PTR hProv, // in
ULONG_PTR dwFlags, // in
SecBuffer *pInput, // in
SecBuffer *pOutput) // out
{ UNREFERENCED_PARAMETER(pInput);
if(!SchannelInit(TRUE)) { return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); }
DebugLog((DEB_TRACE, "RemoteCryptReleaseContextCallback\n"));
pOutput->BufferType = SECBUFFER_DATA; pOutput->cbBuffer = 0; pOutput->pvBuffer = NULL;
if(!CryptReleaseContext((HCRYPTPROV)hProv, (DWORD)dwFlags)) { return SP_LOG_RESULT(GetLastError()); }
return SEC_E_OK; }
BOOL RemoteCryptReleaseContext( HCRYPTPROV hProv, DWORD dwFlags) { SecBuffer Input; SecBuffer Output; DWORD Status;
Input.BufferType = SECBUFFER_DATA; Input.cbBuffer = 0; Input.pvBuffer = NULL;
Status = PerformApplicationCallback(SCH_RELEASE_CONTEXT_CALLBACK, (ULONG_PTR) hProv, (ULONG_PTR) dwFlags, &Input, &Output, FALSE); if(!NT_SUCCESS(Status)) { DebugLog((SP_LOG_ERROR, "Error 0x%x releasing crypto context!\n", Status)); SetLastError(Status); return FALSE; }
return TRUE; }
//+---------------------------------------------------------------------------
//
// Function: UploadCertContextCallback
//
// Synopsis: Transfer a cert context structure from the application
// process to the LSA process.
//
// Arguments: [Argument1] -- Not used.
// [Argument2] -- Not used.
//
// [pInput] -- Buffer containing a cert context structure.
//
// [pOutput] -- Buffer containing the serialized certificate
// context, etc.
//
// History: 09-23-97 jbanes Created
//
// Notes: The structure of the output buffer is as follows:
//
// HCRYPTPROV hProv;
// DWORD cbSerializedCertContext;
// PVOID pvSerializedCertContext;
//
// This function always uses an actual CSP.
//
//----------------------------------------------------------------------------
SECURITY_STATUS UploadCertContextCallback( ULONG_PTR Argument1, // in
ULONG_PTR Argument2, // in
SecBuffer *pInput, // in
SecBuffer *pOutput) // out
{ PCCERT_CONTEXT pCertContext; HCRYPTPROV hProv;
DWORD cbProvHandle; DWORD cbCertContext; PBYTE pbBuffer; SECURITY_STATUS scRet = SEC_E_UNKNOWN_CREDENTIALS;
UNREFERENCED_PARAMETER(Argument1); UNREFERENCED_PARAMETER(Argument2);
if(!SchannelInit(TRUE)) { return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); }
DebugLog((DEB_TRACE, "UploadCertContextCallback\n"));
if(pInput->cbBuffer != sizeof(PCCERT_CONTEXT *) || pInput->pvBuffer == NULL) { return SP_LOG_RESULT(SEC_E_INCOMPLETE_MESSAGE); } pCertContext = *(PCCERT_CONTEXT *)pInput->pvBuffer;
pOutput->cbBuffer = 0; pOutput->pvBuffer = NULL; pOutput->BufferType = SECBUFFER_DATA;
// Attempt to read the hProv associated with the cert context.
cbProvHandle = sizeof(HCRYPTPROV); if(!CertGetCertificateContextProperty(pCertContext, CERT_KEY_PROV_HANDLE_PROP_ID, (PVOID)&hProv, &cbProvHandle)) { hProv = 0; cbProvHandle = sizeof(HCRYPTPROV); }
// Determine the size of the serialized cert context.
if(!CertSerializeCertificateStoreElement( pCertContext, 0, NULL, &cbCertContext)) { scRet = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); goto Return; }
//
// Build output buffer.
//
// Allocate memory for the output buffer.
pOutput->cbBuffer = sizeof(HCRYPTPROV) + sizeof(DWORD) + cbCertContext; pOutput->pvBuffer = PvExtVirtualAlloc(pOutput->cbBuffer); if(pOutput->pvBuffer == NULL) { scRet = SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); goto Return; } pbBuffer = pOutput->pvBuffer;
// Place hProv in output buffer.
*(HCRYPTPROV *)pbBuffer = hProv; pbBuffer += sizeof(HCRYPTPROV);
// Place certificate context in output buffer.
*(DWORD *)pbBuffer = cbCertContext; if(!CertSerializeCertificateStoreElement( pCertContext, 0, pbBuffer + sizeof(DWORD), &cbCertContext)) { scRet = SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); goto Return; }
scRet = SEC_E_OK;
Return:
if(!NT_SUCCESS(scRet) && (NULL != pOutput->pvBuffer)) { SECURITY_STATUS Status;
Status = FreeExtVirtualAlloc(pOutput->pvBuffer, pOutput->cbBuffer); SP_ASSERT(NT_SUCCESS(Status)); }
return scRet; }
//+---------------------------------------------------------------------------
//
// Function: UploadCertStoreCallback
//
// Synopsis: Transfer a cert store from the application
// process to the LSA process, in the form of a serialized
// certificate store.
//
// Arguments: [Argument1] -- Not used.
// [Argument2] -- Not used.
//
// [pInput] -- Buffer containing a HCERTSTORE handle.
//
// [pOutput] -- Buffer containing the serialized cert store.
//
// History: 02-03-98 jbanes Created
//
// Notes: The structure of the output buffer is as follows:
//
// DWORD cbSerializedCertStore;
// PVOID pvSerializedCertStore;
//
// This function always uses an actual CSP.
//
//----------------------------------------------------------------------------
SECURITY_STATUS UploadCertStoreCallback( ULONG_PTR Argument1, // in
ULONG_PTR Argument2, // in
SecBuffer *pInput, // in
SecBuffer *pOutput) // out
{ HCERTSTORE hStore; CRYPT_DATA_BLOB SaveBlob; DWORD cbCertStore; PBYTE pbBuffer;
UNREFERENCED_PARAMETER(Argument1); UNREFERENCED_PARAMETER(Argument2);
if(!SchannelInit(TRUE)) { return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); }
DebugLog((DEB_TRACE, "UploadCertStoreCallback\n"));
pOutput->cbBuffer = 0; pOutput->pvBuffer = NULL; pOutput->BufferType = SECBUFFER_DATA;
if(pInput->cbBuffer != sizeof(HCERTSTORE) || pInput->pvBuffer == NULL) { return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); }
hStore = *(HCERTSTORE *)pInput->pvBuffer;
// Determine the size of the serialized store.
SaveBlob.cbData = 0; SaveBlob.pbData = NULL; if(!CertSaveStore(hStore, X509_ASN_ENCODING, CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_MEMORY, (PVOID)&SaveBlob, 0)) { return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); } cbCertStore = SaveBlob.cbData;
//
// Build output buffer.
//
// Allocate memory for the output buffer.
pOutput->cbBuffer = sizeof(DWORD) + cbCertStore; pOutput->pvBuffer = PvExtVirtualAlloc(pOutput->cbBuffer); if(pOutput->pvBuffer == NULL) { return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); } pbBuffer = pOutput->pvBuffer;
// Place certificate store in output buffer.
*(DWORD *)pbBuffer = cbCertStore; SaveBlob.cbData = cbCertStore; SaveBlob.pbData = pbBuffer + sizeof(DWORD); if(!CertSaveStore(hStore, X509_ASN_ENCODING, CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_MEMORY, (PVOID)&SaveBlob, 0)) { FreeExtVirtualAlloc(pOutput->pvBuffer, pOutput->cbBuffer); return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); }
return SEC_E_OK; }
SP_STATUS SignHashUsingCallback( HCRYPTPROV hProv, DWORD dwKeySpec, ALG_ID aiHash, PBYTE pbHash, DWORD cbHash, PBYTE pbSignature, PDWORD pcbSignature, DWORD fHashData) { SecBuffer Input; SecBuffer Output; SP_STATUS pctRet;
//
// Build input buffer.
//
Input.BufferType = SECBUFFER_DATA; Input.cbBuffer = sizeof(DWORD) * 2 + cbHash; Input.pvBuffer = SPExternalAlloc(Input.cbBuffer); if(Input.pvBuffer == NULL) { return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); }
memcpy(Input.pvBuffer, (PBYTE)&dwKeySpec, sizeof(DWORD)); memcpy((PBYTE)Input.pvBuffer + sizeof(DWORD), (PBYTE)&fHashData, sizeof(DWORD)); memcpy((PBYTE)Input.pvBuffer + sizeof(DWORD) * 2, pbHash, cbHash);
//
// Callback into application process.
//
pctRet = PerformApplicationCallback(SCH_SIGNATURE_CALLBACK, hProv, aiHash, &Input, &Output, TRUE);
SPExternalFree(Input.pvBuffer);
if(pctRet != PCT_ERR_OK) { return pctRet; }
if(Output.cbBuffer > *pcbSignature) { *pcbSignature = Output.cbBuffer; SPExternalFree(Output.pvBuffer); return SP_LOG_RESULT(SEC_E_BUFFER_TOO_SMALL); }
*pcbSignature = Output.cbBuffer; memcpy(pbSignature, Output.pvBuffer, Output.cbBuffer);
SPExternalFree(Output.pvBuffer);
return PCT_ERR_OK; }
//+---------------------------------------------------------------------------
//
// Function: SPSignatureCallback
//
// Synopsis: Perform signature, using application's hProv
//
// Arguments: [hProv] --
// [aiHash] --
// [pInput] --
// [pOutput] --
//
// History: 09-23-97 jbanes Created
//
// Notes: This function always uses an actual CSP.
//
//----------------------------------------------------------------------------
SECURITY_STATUS SPSignatureCallback(ULONG_PTR hProv, // in
ULONG_PTR aiHash, // in
SecBuffer *pInput, // in
SecBuffer *pOutput) // out
{ HCRYPTHASH hHash; DWORD dwKeySpec; DWORD fHashData; PBYTE pbHash; DWORD cbHash; SP_STATUS pctRet;
if(!SchannelInit(TRUE)) { return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); }
DebugLog((DEB_TRACE, "SPSignatureCallback\n"));
//
// Parse input buffer.
//
if(pInput->cbBuffer < sizeof(DWORD) * 2) { return SP_LOG_RESULT(PCT_ERR_ILLEGAL_MESSAGE); }
memcpy(&dwKeySpec, pInput->pvBuffer, sizeof(DWORD)); memcpy(&fHashData, (PBYTE)pInput->pvBuffer + sizeof(DWORD), sizeof(DWORD));
pbHash = (PBYTE)pInput->pvBuffer + sizeof(DWORD) * 2; cbHash = pInput->cbBuffer - sizeof(DWORD) * 2;
//
// Prepare hash object.
//
if(!CryptCreateHash(hProv, (ALG_ID)aiHash, 0, 0, &hHash)) { SP_LOG_RESULT( GetLastError() ); return PCT_ERR_ILLEGAL_MESSAGE; } if(!fHashData) { // set hash value
if(!CryptSetHashParam(hHash, HP_HASHVAL, pbHash, 0)) { SP_LOG_RESULT( GetLastError() ); CryptDestroyHash(hHash); return PCT_ERR_ILLEGAL_MESSAGE; } } else { if(!CryptHashData(hHash, pbHash, cbHash, 0)) { SP_LOG_RESULT( GetLastError() ); CryptDestroyHash(hHash); return PCT_ERR_ILLEGAL_MESSAGE; } }
//
// Sign hash.
//
pOutput->BufferType = SECBUFFER_DATA;
// Get size of signature
if(!CryptSignHash(hHash, dwKeySpec, NULL, 0, NULL, &pOutput->cbBuffer)) { pctRet = SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); return pctRet; }
// Allocate memory
pOutput->pvBuffer = PvExtVirtualAlloc(pOutput->cbBuffer); if(pOutput->pvBuffer == NULL) { CryptDestroyHash(hHash); return SP_LOG_RESULT(SEC_E_INSUFFICIENT_MEMORY); }
// Sign hash.
if(!CryptSignHash(hHash, dwKeySpec, NULL, 0, pOutput->pvBuffer, &pOutput->cbBuffer)) { pctRet = SP_LOG_RESULT(GetLastError()); CryptDestroyHash(hHash); FreeExtVirtualAlloc(pOutput->pvBuffer, pOutput->cbBuffer); return pctRet; }
CryptDestroyHash(hHash);
return PCT_ERR_OK; }
//+---------------------------------------------------------------------------
//
// Function: DownloadCertContextCallBack
//
// Synopsis: Transfer a cert context structure from the application
// process to the LSA process, in the form of a serialized
// certificate store.
//
// Arguments: [Argument1] -- Not used.
// [Argument2] -- Not used.
// [pInput] --
// [pOutput] --
//
// History: 09-26-97 jbanes Created
//
// Notes: The structure of the input buffer is as follows:
//
// DWORD cbSerializedCertStore;
// PVOID pvSerializedCertStore;
// DWORD cbSerializedCertContext;
// PVOID pvSerializedCertContext;
//
// This function always uses an actual CSP.
//
//----------------------------------------------------------------------------
SECURITY_STATUS DownloadCertContextCallback( ULONG_PTR Argument1, // in
ULONG_PTR Argument2, // in
SecBuffer *pInput, // in
SecBuffer *pOutput) // out
{ PCCERT_CONTEXT pCertContext; SECURITY_STATUS scRet;
UNREFERENCED_PARAMETER(Argument1); UNREFERENCED_PARAMETER(Argument2);
if(!SchannelInit(TRUE)) { return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); }
DebugLog((DEB_TRACE, "DownloadCertContextCallback\n"));
// Allocate memory for output buffer.
pOutput->BufferType = SECBUFFER_DATA; pOutput->cbBuffer = sizeof(PVOID); pOutput->pvBuffer = PvExtVirtualAlloc(pOutput->cbBuffer); if(pOutput->pvBuffer == NULL) { return SP_LOG_RESULT( SEC_E_INSUFFICIENT_MEMORY ); }
// Deserialize buffer.
scRet = DeserializeCertContext(&pCertContext, pInput->pvBuffer, pInput->cbBuffer); if(FAILED(scRet)) { FreeExtVirtualAlloc(pOutput->pvBuffer, pOutput->cbBuffer); return SP_LOG_RESULT( scRet ); }
// Place cert context pointer in output buffer.
*(PCCERT_CONTEXT *)pOutput->pvBuffer = pCertContext;
return SEC_E_OK; }
//+---------------------------------------------------------------------------
//
// Function: SerializeCertContext
//
// Synopsis: Serialize the specified certificate context, along with its
// associated certificate store.
//
// Arguments: [pCertContext] --
// [pbBuffer] --
// [pcbBuffer] --
//
// History: 09-26-97 jbanes Created
//
// Notes: The structure of the output buffer is as follows:
//
// DWORD cbSerializedCertStore
// PVOID pvSerializedCertStore
// DWORD cbSerializedCertContext
// PVOID pvSerializedCertContext
//
//----------------------------------------------------------------------------
SECURITY_STATUS SerializeCertContext( PCCERT_CONTEXT pCertContext, // in
PBYTE pbBuffer, // out
PDWORD pcbBuffer) // out
{ CRYPT_DATA_BLOB SaveBlob; DWORD cbCertContext; DWORD cbCertStore; DWORD cbBuffer;
if(pCertContext == NULL) { *pcbBuffer = 0; return SEC_E_OK; }
// Determine the size of the serialized cert context.
if(!CertSerializeCertificateStoreElement( pCertContext, 0, NULL, &cbCertContext)) { return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); }
// Determine the size of the serialized store.
if(pCertContext->hCertStore) { SaveBlob.cbData = 0; SaveBlob.pbData = NULL; if(!CertSaveStore(pCertContext->hCertStore, X509_ASN_ENCODING, CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_MEMORY, (PVOID)&SaveBlob, 0)) { return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); } cbCertStore = SaveBlob.cbData; } else { cbCertStore = 0; }
cbBuffer = sizeof(DWORD) + cbCertContext + sizeof(DWORD) + cbCertStore;
if(pbBuffer == NULL) { *pcbBuffer = cbBuffer; return SEC_E_OK; }
if(*pcbBuffer < cbBuffer) { return SP_LOG_RESULT(SEC_E_BUFFER_TOO_SMALL); }
// Set output values.
*pcbBuffer = cbBuffer;
// Place certificate store in output buffer.
*(DWORD *)pbBuffer = cbCertStore; if(pCertContext->hCertStore) { SaveBlob.cbData = cbCertStore; SaveBlob.pbData = pbBuffer + sizeof(DWORD); if(!CertSaveStore(pCertContext->hCertStore, X509_ASN_ENCODING, CERT_STORE_SAVE_AS_STORE, CERT_STORE_SAVE_TO_MEMORY, (PVOID)&SaveBlob, 0)) { return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); } } pbBuffer += sizeof(DWORD) + cbCertStore;
// Place certificate context in output buffer.
*(DWORD UNALIGNED *)pbBuffer = cbCertContext; if(!CertSerializeCertificateStoreElement( pCertContext, 0, pbBuffer + sizeof(DWORD), &cbCertContext)) { return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); }
return SEC_E_OK; }
SECURITY_STATUS DeserializeCertContext( PCCERT_CONTEXT *ppCertContext, // out
PBYTE pbBuffer, // in
DWORD cbBuffer) // in
{ CRYPT_DATA_BLOB Serialized; HCERTSTORE hStore; DWORD cbCertContext;
if(cbBuffer < sizeof(DWORD)) { return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); }
//
// Deserialize certificate store.
//
Serialized.cbData = *(DWORD *)pbBuffer; Serialized.pbData = pbBuffer + sizeof(DWORD);
if(cbBuffer < sizeof(DWORD) + Serialized.cbData) { return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); }
hStore = CertOpenStore( CERT_STORE_PROV_SERIALIZED, X509_ASN_ENCODING, 0, CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, &Serialized); if(hStore == NULL) { return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); } pbBuffer += sizeof(DWORD) + Serialized.cbData; cbBuffer -= sizeof(DWORD) + Serialized.cbData;
//
// Deserialize certificate context.
//
if(cbBuffer < sizeof(DWORD)) { CertCloseStore(hStore, 0); return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); }
cbCertContext = *(DWORD UNALIGNED *)pbBuffer;
if(cbBuffer < sizeof(DWORD) + cbCertContext) { CertCloseStore(hStore, 0); return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); }
if(!CertAddSerializedElementToStore(hStore, pbBuffer + sizeof(DWORD), cbCertContext, CERT_STORE_ADD_USE_EXISTING, 0, CERT_STORE_CERTIFICATE_CONTEXT_FLAG, NULL, ppCertContext)) { CertCloseStore(hStore, 0); return SP_LOG_RESULT(SEC_E_UNKNOWN_CREDENTIALS); }
if(!CertCloseStore(hStore, 0)) { SP_LOG_RESULT(GetLastError()); }
return SEC_E_OK; }
//+---------------------------------------------------------------------------
//
// Function: SPGetApplicationKeys
//
// Synopsis: Callback to the user process and retrieve the user encryption
// keys.
//
// Arguments: [pContext] -- Schannel context.
// [dwFlags] -- SCH_FLAG_READ_KEY, SCH_FLAG_WRITE_KEY
//
// History: 10-17-97 jbanes Created
//
// Notes:
//
//----------------------------------------------------------------------------
SP_STATUS SPGetUserKeys( PSPContext pContext, DWORD dwFlags) { PBYTE pbBuffer; PBYTE pbReadKey; DWORD cbReadKey; PBYTE pbWriteKey; DWORD cbWriteKey; SecBuffer Input; SecBuffer Output; SECURITY_STATUS scRet; BOOL fWow64Client = FALSE;
#ifdef _WIN64
SECPKG_CALL_INFO CallInfo; #endif
//
// Call back into the application process and get the keys, in the
// form of 2 opaque blobs.
//
DebugLog((SP_LOG_TRACE, "SPGetUserKeys: 0x%p, %d\n", pContext, dwFlags));
if(LsaTable == NULL) { // We're probably being called from the application process.
return SP_LOG_RESULT(STATUS_INVALID_PARAMETER); }
#ifdef _WIN64
if(!LsaTable->GetCallInfo(&CallInfo)) { scRet = STATUS_INTERNAL_ERROR; return SP_LOG_RESULT(scRet); } fWow64Client = (CallInfo.Attributes & SECPKG_CALL_WOWCLIENT) != 0; #endif
if(fWow64Client) { Input.BufferType = SECBUFFER_DATA; Input.cbBuffer = sizeof(pContext->ContextThumbprint); Input.pvBuffer = &pContext->ContextThumbprint; } else { Input.BufferType = SECBUFFER_DATA; Input.cbBuffer = 0; Input.pvBuffer = NULL; }
scRet = PerformApplicationCallback( SCH_GET_USER_KEYS, (ULONG_PTR) pContext, (ULONG_PTR) dwFlags, &Input, &Output, TRUE); if(!NT_SUCCESS(scRet)) { DebugLog((SP_LOG_ERROR, "Error 0x%x retrieving user keys\n", scRet)); return SP_LOG_RESULT(PCT_INT_INTERNAL_ERROR); }
//
// Parse output buffer
//
pbBuffer = Output.pvBuffer;
if(Output.cbBuffer < sizeof(DWORD) * 4) { return SP_LOG_RESULT(STATUS_INVALID_PARAMETER); }
if(dwFlags & SCH_FLAG_READ_KEY) { pContext->ReadCounter = *(PDWORD)pbBuffer; } pbBuffer += sizeof(DWORD);
if(dwFlags & SCH_FLAG_WRITE_KEY) { pContext->WriteCounter = *(PDWORD)pbBuffer; } pbBuffer += sizeof(DWORD);
cbReadKey = *(PDWORD)pbBuffer; pbBuffer += sizeof(DWORD);
cbWriteKey = *(PDWORD)pbBuffer; pbBuffer += sizeof(DWORD);
if(Output.cbBuffer < sizeof(DWORD) * 4 + cbReadKey + cbWriteKey) { return SP_LOG_RESULT(STATUS_INVALID_PARAMETER); }
pbReadKey = pbBuffer; pbBuffer += cbReadKey;
pbWriteKey = pbBuffer; pbBuffer += cbWriteKey;
SP_ASSERT(pbBuffer - (PBYTE)Output.pvBuffer == (INT)Output.cbBuffer);
//
// Place keys into context structure.
//
if(dwFlags & SCH_FLAG_READ_KEY) { if(cbReadKey) { if(!CryptImportKey(pContext->RipeZombie->hMasterProv, pbReadKey, cbReadKey, 0, CRYPT_EXPORTABLE, &pContext->hReadKey)) { SP_LOG_RESULT(GetLastError()); scRet = PCT_INT_INTERNAL_ERROR; goto done; } } else { pContext->hReadKey = 0; } }
if(dwFlags & SCH_FLAG_WRITE_KEY) { if(cbWriteKey) { if(!CryptImportKey(pContext->RipeZombie->hMasterProv, pbWriteKey, cbWriteKey, 0, CRYPT_EXPORTABLE, &pContext->hWriteKey)) { SP_LOG_RESULT(GetLastError()); scRet = PCT_INT_INTERNAL_ERROR; goto done; } } else { pContext->hWriteKey = 0; } }
done:
SPExternalFree(Output.pvBuffer);
return scRet; }
//+---------------------------------------------------------------------------
//
// Function: GetUserKeysCallback
//
// Synopsis: Find the user context that corresponds to the passed in LSA
// context, serialize the encryption keys, and return them in
// the output buffer.
//
// Arguments: [dwLsaContext] -- Pointer to LSA Schannel context.
// [dwFlags] -- SCH_FLAG_READ_KEY, SCH_FLAG_WRITE_KEY
// [pInput] -- Not used.
// [pOutput] -- (output) Serialized keys.
//
// History: 10-17-97 jbanes Created
//
// Notes: The structure of the output buffer is as follows:
//
// DWORD dwReadSequence;
// DWORD dwWriteSequence;
// DWORD cbReadKey;
// BYTE rgbReadKey[];
// DWORD cbWriteKey;
// BYTE rgbWriteKey[];
//
//----------------------------------------------------------------------------
SECURITY_STATUS GetUserKeysCallback( ULONG_PTR dwLsaContext, ULONG_PTR dwFlags, SecBuffer *pInput, SecBuffer *pOutput) { DWORD cbReadKey = 0; DWORD cbWriteKey = 0; DWORD cbData; PBYTE pbBuffer; DWORD cbBuffer; PSPContext pContext; PSSL_USER_CONTEXT pUserContext;
if(!SchannelInit(TRUE)) { return SP_LOG_RESULT(SEC_E_INTERNAL_ERROR); }
DebugLog((DEB_TRACE, "GetUserKeysCallback\n"));
//
// Find the user context.
//
if(pInput->pvBuffer != NULL && pInput->cbBuffer == sizeof(CRED_THUMBPRINT)) { // Search for matching context thumbprint.
pUserContext = SslFindUserContextEx((PCRED_THUMBPRINT)pInput->pvBuffer); if(pUserContext == NULL) { return SP_LOG_RESULT( SEC_E_INVALID_HANDLE ); } } else { // Search for matching lsa context
pUserContext = SslFindUserContext(dwLsaContext); if(pUserContext == NULL) { return SP_LOG_RESULT( SEC_E_INVALID_HANDLE ); } }
pContext = pUserContext->pContext; if(pContext == NULL) { return SP_LOG_RESULT( SEC_E_INTERNAL_ERROR ); }
//
// Compute size of output buffer.
//
if(dwFlags & SCH_FLAG_READ_KEY) { if(pContext->pReadCipherInfo->aiCipher != CALG_NULLCIPHER) { if(!pContext->hReadKey) { return SP_LOG_RESULT( SEC_E_INVALID_HANDLE ); } if(!CryptExportKey(pContext->hReadKey, 0, OPAQUEKEYBLOB, 0, NULL, &cbReadKey)) { SP_LOG_RESULT(GetLastError()); return SEC_E_INTERNAL_ERROR; } } else { cbReadKey = 0; } }
if(dwFlags & SCH_FLAG_WRITE_KEY) { if(pContext->pWriteCipherInfo->aiCipher != CALG_NULLCIPHER) { if(!pContext->hWriteKey) { return SP_LOG_RESULT( SEC_E_INVALID_HANDLE ); } if(!CryptExportKey(pContext->hWriteKey, 0, OPAQUEKEYBLOB, 0, NULL, &cbWriteKey)) { SP_LOG_RESULT(GetLastError()); return SEC_E_INTERNAL_ERROR; } } else { cbWriteKey = 0; } }
cbBuffer = sizeof(DWORD) + sizeof(DWORD) + sizeof(DWORD) + cbReadKey + sizeof(DWORD) + cbWriteKey;
// Allocate memory for output buffer.
pbBuffer = PvExtVirtualAlloc( cbBuffer); if(pbBuffer == NULL) { return SP_LOG_RESULT( SEC_E_INSUFFICIENT_MEMORY ); } pOutput->BufferType = SECBUFFER_DATA; pOutput->cbBuffer = cbBuffer; pOutput->pvBuffer = pbBuffer;
//
// Serialize keys.
//
*(PDWORD)pbBuffer = pContext->ReadCounter; pbBuffer += sizeof(DWORD);
*(PDWORD)pbBuffer = pContext->WriteCounter; pbBuffer += sizeof(DWORD);
*(PDWORD)pbBuffer = cbReadKey; pbBuffer += sizeof(DWORD);
*(PDWORD)pbBuffer = cbWriteKey; pbBuffer += sizeof(DWORD);
if(dwFlags & SCH_FLAG_READ_KEY) { if(pContext->pReadCipherInfo->aiCipher != CALG_NULLCIPHER) { cbData = cbReadKey; if(!CryptExportKey(pContext->hReadKey, 0, OPAQUEKEYBLOB, 0, pbBuffer, &cbData)) { FreeExtVirtualAlloc(pOutput->pvBuffer, pOutput->cbBuffer); SP_LOG_RESULT(GetLastError()); return SEC_E_INTERNAL_ERROR; } if(!CryptDestroyKey(pContext->hReadKey)) { SP_LOG_RESULT(GetLastError()); } } pContext->hReadKey = 0; } pbBuffer += cbReadKey;
if(dwFlags & SCH_FLAG_WRITE_KEY) { if(pContext->pWriteCipherInfo->aiCipher != CALG_NULLCIPHER) { cbData = cbWriteKey; if(!CryptExportKey(pContext->hWriteKey, 0, OPAQUEKEYBLOB, 0, pbBuffer, &cbData)) { FreeExtVirtualAlloc(pOutput->pvBuffer, pOutput->cbBuffer); SP_LOG_RESULT(GetLastError()); return SEC_E_INTERNAL_ERROR; } if(!CryptDestroyKey(pContext->hWriteKey)) { SP_LOG_RESULT(GetLastError()); } } pContext->hWriteKey = 0; } pbBuffer += cbWriteKey;
return SEC_E_OK; }
// Always called from callback routine (in the application process).
VOID * PvExtVirtualAlloc(DWORD cb) { SECURITY_STATUS Status; PVOID pv = NULL; SIZE_T Size = cb;
Status = NtAllocateVirtualMemory( GetCurrentProcess(), &pv, 0, &Size, MEM_COMMIT, PAGE_READWRITE); if(!NT_SUCCESS(Status)) { pv = NULL; }
DebugLog((DEB_TRACE, "SslCallbackVirtualAlloc: 0x%x bytes at 0x%x\n", cb, pv));
return(pv); }
// Always called from callback routine (in the application process),
// typically when an error occurs and we're cleaning up.
SECURITY_STATUS FreeExtVirtualAlloc(PVOID pv, SIZE_T cbMem) { cbMem = 0; return(NtFreeVirtualMemory(GetCurrentProcess(), &pv, &cbMem, MEM_RELEASE)); }
// Always called from the LSA process, when freeing memory allocated
// by a callback function.
SECURITY_STATUS SPFreeUserAllocMemory(PVOID pv, SIZE_T cbMem) { SECPKG_CALL_INFO CallInfo;
if(LsaTable->GetCallInfo(&CallInfo)) { SECURITY_STATUS Status; HANDLE hProcess;
hProcess = OpenProcess(PROCESS_VM_OPERATION, FALSE, CallInfo.ProcessId); if(hProcess == NULL) { return SP_LOG_RESULT(GetLastError()); }
cbMem = 0; Status = NtFreeVirtualMemory(hProcess, &pv, &cbMem, MEM_RELEASE); if(!NT_SUCCESS(Status)) { SP_LOG_RESULT(Status); }
CloseHandle(hProcess); }
DebugLog((DEB_TRACE, "SslCallbackVirtualFree: 0x%x bytes at 0x%x\n", cbMem, pv));
return SEC_E_OK; }
|