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.
 
 
 
 
 
 

1034 lines
31 KiB

//+-------------------------------------------------------------------------
// Microsoft Windows
//
// Copyright (C) Microsoft Corporation, 1995 - 1999
//
// File: crypttls.cpp
//
// Contents: Crypt Thread Local Storage (TLS) and OssGlobal "world"
// installation and allocation functions
//
// Functions: I_CryptTlsDllMain
// I_CryptAllocTls
// I_CryptFreeTls
// I_CryptGetTls
// I_CryptSetTls
// I_CryptDetachTls
// I_CryptInstallOssGlobal
// I_CryptUninstallOssGlobal
// I_CryptGetOssGlobal
//
// I_CryptInstallAsn1Module
// I_CryptUninstallAsn1Module
// I_CryptGetAsn1Encoder
// I_CryptGetAsn1Decoder
//
// Assumption:
// For PROCESS_ATTACH or THREAD_ATTACH, I_CryptTlsDllMain is called
// first. For PROCESS_DETACH or THREAD_DETACH, I_CryptTlsDllMain
// is called last.
//
// History: 17-Nov-96 philh created
//--------------------------------------------------------------------------
#include "global.hxx"
#include <dbgdef.h>
#include <asn1code.h>
#ifdef STATIC
#undef STATIC
#endif
#define STATIC
// CryptTls Entry types
#define FREE_CRYPTTLS 0
#define USER_CRYPTTLS 1
#define OSS_CRYPTTLS 2
#define ASN1_CRYPTTLS 3
typedef struct _ASN1_TLS_ENTRY {
ASN1encoding_t pEnc;
ASN1decoding_t pDec;
} ASN1_TLS_ENTRY, *PASN1_TLS_ENTRY;
// The following is reallocated and updated for each I_CryptAllocTls or
// I_CryptInstallOssGlobal. For I_CryptAllocTls, dwType is set to
// USER_CRYPTTLS and dwNext is zeroed. For I_CryptInstallOssGlobal, dwType
// is set to OSS_CRYPTTLS and pvCtlTbl is updated with pvCtlTbl.
// For I_CryptFreeTls, dwType is set to FREE_CRYPTTLS and dwNext is
// updated with previous dwFreeProcessTlsHead.
//
// The array is indexed via hCryptTls -1 or hOssGlobal -1.
typedef struct _CRYPTTLS_PROCESS_ENTRY {
DWORD dwType;
union {
void *pvCtlTbl;
ASN1module_t pMod;
// Following is applicable to I_CryptFreeTls'ed entries.
// Its the array index + 1 of the next free entry. A dwNext
// of zero terminates.
DWORD dwNext;
};
} CRYPTTLS_PROCESS_ENTRY, *PCRYPTTLS_PROCESS_ENTRY;
static DWORD cProcessTls;
static PCRYPTTLS_PROCESS_ENTRY pProcessTls;
// The head of the entries freed by I_CryptFreeTls are indexed by the following.
// A 0 index indicates an empty free list.
//
// I_CryptAllocTls first checks this list before reallocating pProcessTls.
static DWORD dwFreeProcessTlsHead;
// The kernel32.dll Thread Local Storage (TLS) slot index
static DWORD iCryptTLS = 0xFFFFFFFF;
// The Thread Local Storage (TLS) referenced by iCryptTLS points to the
// following structure allocated for each thread. Once allocated, not
// reallocated.
typedef struct _CRYPTTLS_THREAD_HDR CRYPTTLS_THREAD_HDR, *PCRYPTTLS_THREAD_HDR;
struct _CRYPTTLS_THREAD_HDR {
DWORD cTls;
void **ppvTls; // reallocated
PCRYPTTLS_THREAD_HDR pNext;
PCRYPTTLS_THREAD_HDR pPrev;
};
// Linked list of all threads having CRYPTTLS
static PCRYPTTLS_THREAD_HDR pThreadTlsHead;
// Minimum number of entries allocated for pProcessTls and the ppvTls
//
// realloc optimization (MIN value is 1)
#define MIN_TLS_ALLOC_COUNT 16
// Used to protect the allocation of TLS and installation of OssGlobals
static CRITICAL_SECTION CryptTlsCriticalSection;
#define OSS_INIT_PROC_IDX 0
#define OSS_TERM_PROC_IDX 1
#define OSS_GET_OSS_GLOBAL_SIZE_PROC_IDX 2
#define OSS_SET_ENCODING_RULES_PROC_IDX 3
#define OSS_SET_DECODING_FLAGS_PROC_IDX 4
#define OSS_SET_ENCODING_FLAGS_PROC_IDX 5
#define OSS_PROC_CNT 6
static LPSTR rgpszOssProc[OSS_PROC_CNT] = {
"ossinit", // 0
"ossterm", // 1
"ossGetOssGlobalSize", // 2
"ossSetEncodingRules", // 3
"ossSetDecodingFlags", // 4
"ossSetEncodingFlags" // 5
};
static void *rgpvOssProc[OSS_PROC_CNT];
static HMODULE hmsossDll = NULL;
static BOOL fLoadedOss = FALSE;
static void OssUnload()
{
if (hmsossDll) {
FreeLibrary(hmsossDll);
hmsossDll = NULL;
}
}
static void OssLoad()
{
DWORD i;
if (fLoadedOss)
return;
EnterCriticalSection(&CryptTlsCriticalSection);
if (fLoadedOss)
goto LeaveReturn;
if (NULL == (hmsossDll = LoadLibraryA("msoss.dll")))
goto msossLoadLibraryError;
for (i = 0; i < OSS_PROC_CNT; i++) {
if (NULL == (rgpvOssProc[i] = GetProcAddress(
hmsossDll, rgpszOssProc[i])))
goto msossGetProcAddressError;
}
LeaveReturn:
LeaveCriticalSection(&CryptTlsCriticalSection);
CommonReturn:
fLoadedOss = TRUE;
return;
ErrorReturn:
LeaveCriticalSection(&CryptTlsCriticalSection);
OssUnload();
goto CommonReturn;
TRACE_ERROR(msossLoadLibraryError)
TRACE_ERROR(msossGetProcAddressError)
}
// nonstandard extension used : redefined extern to static
#pragma warning (disable: 4211)
typedef int (DLL_ENTRY* pfnossinit)(struct ossGlobal *world,
void *ctl_tbl);
static int DLL_ENTRY ossinit(struct ossGlobal *world,
void *ctl_tbl)
{
if (hmsossDll)
return ((pfnossinit) rgpvOssProc[OSS_INIT_PROC_IDX])(
world,
ctl_tbl);
else
return API_DLL_NOT_LINKED;
}
typedef void (DLL_ENTRY* pfnossterm)(struct ossGlobal *world);
static void DLL_ENTRY ossterm(struct ossGlobal *world)
{
if (hmsossDll)
((pfnossterm) rgpvOssProc[OSS_TERM_PROC_IDX])(world);
}
typedef int (DLL_ENTRY* pfnossGetOssGlobalSize)(void);
static int DLL_ENTRY ossGetOssGlobalSize(void)
{
if (hmsossDll)
return ((pfnossGetOssGlobalSize)
rgpvOssProc[OSS_GET_OSS_GLOBAL_SIZE_PROC_IDX])();
else
return 0;
}
typedef int (DLL_ENTRY* pfnossSetEncodingRules)(struct ossGlobal *world,
ossEncodingRules rules);
static int DLL_ENTRY ossSetEncodingRules(struct ossGlobal *world,
ossEncodingRules rules)
{
if (hmsossDll)
return ((pfnossSetEncodingRules)
rgpvOssProc[OSS_SET_ENCODING_RULES_PROC_IDX])(
world,
rules);
else
return API_DLL_NOT_LINKED;
}
#if !DBG
typedef int (DLL_ENTRY* pfnossSetDecodingFlags)(struct ossGlobal *world,
unsigned long flags);
static int DLL_ENTRY ossSetDecodingFlags(struct ossGlobal *world,
unsigned long flags)
{
if (hmsossDll)
return ((pfnossSetDecodingFlags)
rgpvOssProc[OSS_SET_DECODING_FLAGS_PROC_IDX])(
world,
flags);
else
return API_DLL_NOT_LINKED;
}
typedef int (DLL_ENTRY* pfnossSetEncodingFlags)(struct ossGlobal *world,
unsigned long flags);
static int DLL_ENTRY ossSetEncodingFlags(struct ossGlobal *world,
unsigned long flags)
{
if (hmsossDll)
return ((pfnossSetEncodingFlags)
rgpvOssProc[OSS_SET_ENCODING_FLAGS_PROC_IDX])(
world,
flags);
else
return API_DLL_NOT_LINKED;
}
#endif
//+-------------------------------------------------------------------------
// Free the thread's CRYPT TLS
//
// Upon entry/exit, in CryptTlsCriticalSection
//--------------------------------------------------------------------------
static void FreeCryptTls(
IN PCRYPTTLS_THREAD_HDR pTlsHdr
)
{
if (pTlsHdr->pNext)
pTlsHdr->pNext->pPrev = pTlsHdr->pPrev;
if (pTlsHdr->pPrev)
pTlsHdr->pPrev->pNext = pTlsHdr->pNext;
else if (pTlsHdr == pThreadTlsHead)
pThreadTlsHead = pTlsHdr->pNext;
else {
assert(pTlsHdr == pThreadTlsHead);
}
if (pTlsHdr->ppvTls)
free(pTlsHdr->ppvTls);
free(pTlsHdr);
}
//+-------------------------------------------------------------------------
// Dll initialization
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CryptTlsDllMain(
HMODULE hInst,
ULONG ulReason,
LPVOID lpReserved)
{
BOOL fRet;
PCRYPTTLS_THREAD_HDR pTlsHdr;
switch (ulReason) {
case DLL_PROCESS_ATTACH:
if (!Pki_InitializeCriticalSection(&CryptTlsCriticalSection))
goto InitCritSectionError;
if ((iCryptTLS = TlsAlloc()) == 0xFFFFFFFF) {
DeleteCriticalSection(&CryptTlsCriticalSection);
goto TlsAllocError;
}
break;
case DLL_PROCESS_DETACH:
case DLL_THREAD_DETACH:
if (pTlsHdr = (PCRYPTTLS_THREAD_HDR) TlsGetValue(iCryptTLS)) {
DWORD cTls;
DWORD cDetach = 0;
DWORD i;
cTls = pTlsHdr->cTls;
EnterCriticalSection(&CryptTlsCriticalSection);
assert(cTls <= cProcessTls);
for (i = 0; i < cTls; i++) {
void *pvTls;
if (pvTls = pTlsHdr->ppvTls[i]) {
switch (pProcessTls[i].dwType) {
case OSS_CRYPTTLS:
// Following API is in delay loaded msoss.dll.
__try {
ossterm((POssGlobal) pvTls);
} __except(EXCEPTION_EXECUTE_HANDLER) {
}
free(pvTls);
pTlsHdr->ppvTls[i] = NULL;
break;
case ASN1_CRYPTTLS:
{
PASN1_TLS_ENTRY pAsn1TlsEntry =
(PASN1_TLS_ENTRY) pvTls;
if (pAsn1TlsEntry->pEnc)
ASN1_CloseEncoder(pAsn1TlsEntry->pEnc);
if (pAsn1TlsEntry->pDec)
ASN1_CloseDecoder(pAsn1TlsEntry->pDec);
free(pvTls);
pTlsHdr->ppvTls[i] = NULL;
}
break;
case USER_CRYPTTLS:
cDetach++;
break;
default:
assert(FREE_CRYPTTLS == pProcessTls[i].dwType);
}
}
}
FreeCryptTls(pTlsHdr);
TlsSetValue(iCryptTLS, 0);
LeaveCriticalSection(&CryptTlsCriticalSection);
assert(cDetach == 0);
}
if (ulReason == DLL_PROCESS_DETACH) {
while(pThreadTlsHead)
FreeCryptTls(pThreadTlsHead);
if (pProcessTls) {
free(pProcessTls);
pProcessTls = NULL;
}
cProcessTls = 0;
dwFreeProcessTlsHead = 0;
OssUnload();
DeleteCriticalSection(&CryptTlsCriticalSection);
TlsFree(iCryptTLS);
iCryptTLS = 0xFFFFFFFF;
}
break;
default:
break;
}
fRet = TRUE;
CommonReturn:
return fRet;
ErrorReturn:
fRet = FALSE;
goto CommonReturn;
TRACE_ERROR(InitCritSectionError)
TRACE_ERROR(TlsAllocError)
}
//+-------------------------------------------------------------------------
// Get a pointer to the Crypt TLS entries. Check that the hCryptTls is
// included in the list of entries. If hCryptTls isn't included and
// allocation isn't inhibited, alloc/realloc the array of TLS entries.
//
// Also verifies the hCryptTls handle.
//--------------------------------------------------------------------------
STATIC void **GetCryptTls(
IN HCRYPTTLS hCryptTls,
IN BOOL fInhibitAlloc // TRUE for I_CryptDetachTls
)
{
PCRYPTTLS_THREAD_HDR pTlsHdr;
DWORD cTls;
void **ppvTls;
DWORD i;
if (0 == hCryptTls--) {
SetLastError((DWORD) E_INVALIDARG);
return NULL;
}
pTlsHdr = (PCRYPTTLS_THREAD_HDR) TlsGetValue(iCryptTLS);
cTls = pTlsHdr ? pTlsHdr->cTls : 0;
if (hCryptTls < cTls)
return pTlsHdr->ppvTls;
if (fInhibitAlloc)
return NULL;
EnterCriticalSection(&CryptTlsCriticalSection);
if (hCryptTls >= cProcessTls)
goto InvalidArg;
assert(cTls < cProcessTls);
// Note for !DBG: realloc is mapped to LocalReAlloc. For LocalRealloc()
// the previous memory pointer can't be NULL.
if (pTlsHdr) {
if (cProcessTls > MIN_TLS_ALLOC_COUNT) {
if (NULL == (ppvTls = (void **) realloc(pTlsHdr->ppvTls,
cProcessTls * sizeof(void *))))
goto OutOfMemory;
} else {
ppvTls = pTlsHdr->ppvTls;
assert(ppvTls);
}
} else {
DWORD cAllocTls = (cProcessTls > MIN_TLS_ALLOC_COUNT) ?
cProcessTls : MIN_TLS_ALLOC_COUNT;
if (NULL == (ppvTls = (void **) malloc(cAllocTls * sizeof(void *))))
goto OutOfMemory;
if (NULL == (pTlsHdr = (PCRYPTTLS_THREAD_HDR) malloc(
sizeof(CRYPTTLS_THREAD_HDR)))) {
free(ppvTls);
goto OutOfMemory;
}
if (!TlsSetValue(iCryptTLS, pTlsHdr)) {
free(pTlsHdr);
free(ppvTls);
goto TlsSetValueError;
}
pTlsHdr->pPrev = NULL;
pTlsHdr->pNext = pThreadTlsHead;
if (pThreadTlsHead)
pThreadTlsHead->pPrev = pTlsHdr;
pThreadTlsHead = pTlsHdr;
}
for (i = cTls; i < cProcessTls; i++)
ppvTls[i] = NULL;
pTlsHdr->ppvTls = ppvTls;
pTlsHdr->cTls = cProcessTls;
CommonReturn:
LeaveCriticalSection(&CryptTlsCriticalSection);
return ppvTls;
ErrorReturn:
ppvTls = NULL;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
TRACE_ERROR(TlsSetValueError)
}
//+-------------------------------------------------------------------------
// Install a thread local storage entry and return a handle for future access.
//--------------------------------------------------------------------------
HCRYPTTLS
WINAPI
I_CryptAllocTls()
{
HCRYPTTLS hCryptTls;
EnterCriticalSection(&CryptTlsCriticalSection);
if (dwFreeProcessTlsHead) {
PCRYPTTLS_PROCESS_ENTRY pEntry;
hCryptTls = (HCRYPTTLS) dwFreeProcessTlsHead;
assert(hCryptTls <= cProcessTls);
pEntry = &pProcessTls[dwFreeProcessTlsHead - 1];
assert(FREE_CRYPTTLS == pEntry->dwType);
assert(pEntry->dwNext <= cProcessTls);
pEntry->dwType = USER_CRYPTTLS;
dwFreeProcessTlsHead = pEntry->dwNext;
pEntry->dwNext = 0;
} else {
PCRYPTTLS_PROCESS_ENTRY pNewProcessTls;
// Note for !DBG: realloc is mapped to LocalReAlloc. For LocalRealloc()
// the previous memory pointer can't be NULL.
if (pProcessTls) {
if (cProcessTls + 1 > MIN_TLS_ALLOC_COUNT)
pNewProcessTls = (PCRYPTTLS_PROCESS_ENTRY) realloc(pProcessTls,
(cProcessTls + 1) * sizeof(CRYPTTLS_PROCESS_ENTRY));
else
pNewProcessTls = pProcessTls;
} else
pNewProcessTls = (PCRYPTTLS_PROCESS_ENTRY) malloc(
(MIN_TLS_ALLOC_COUNT) * sizeof(CRYPTTLS_PROCESS_ENTRY));
if (pNewProcessTls) {
pNewProcessTls[cProcessTls].dwType = USER_CRYPTTLS;
pNewProcessTls[cProcessTls].dwNext = 0;
hCryptTls = (HCRYPTTLS) ++cProcessTls;
pProcessTls = pNewProcessTls;
} else {
SetLastError((DWORD) E_OUTOFMEMORY);
hCryptTls = 0;
}
}
LeaveCriticalSection(&CryptTlsCriticalSection);
return hCryptTls;
}
//+-------------------------------------------------------------------------
// Called at DLL_PROCESS_DETACH to free a thread local storage entry.
// Optionally, calls the callback for each thread having a non-NULL pvTls.
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CryptFreeTls(
IN HCRYPTTLS hCryptTls,
IN OPTIONAL PFN_CRYPT_FREE pfnFree
)
{
BOOL fResult;
DWORD dwType;
PCRYPTTLS_THREAD_HDR pThreadTls;
if (0 == hCryptTls--) {
SetLastError((DWORD) E_INVALIDARG);
return FALSE;
}
EnterCriticalSection(&CryptTlsCriticalSection);
if (hCryptTls >= cProcessTls)
goto InvalidArg;
dwType = pProcessTls[hCryptTls].dwType;
if (!(OSS_CRYPTTLS == dwType || USER_CRYPTTLS == dwType ||
ASN1_CRYPTTLS == dwType))
goto InvalidArg;
// Iterate through the threads having CRYPTTLS
pThreadTls = pThreadTlsHead;
while (pThreadTls) {
PCRYPTTLS_THREAD_HDR pThreadTlsNext;
pThreadTlsNext = pThreadTls->pNext;
if (pThreadTls->cTls > hCryptTls) {
void *pvTls = pThreadTls->ppvTls[hCryptTls];
if (pvTls) {
pThreadTls->ppvTls[hCryptTls] = NULL;
if (OSS_CRYPTTLS == dwType) {
// Following API is in delay loaded msoss.dll.
__try {
ossterm((POssGlobal) pvTls);
} __except(EXCEPTION_EXECUTE_HANDLER) {
}
free(pvTls);
} else if (ASN1_CRYPTTLS == dwType) {
PASN1_TLS_ENTRY pAsn1TlsEntry =
(PASN1_TLS_ENTRY) pvTls;
if (pAsn1TlsEntry->pEnc)
ASN1_CloseEncoder(pAsn1TlsEntry->pEnc);
if (pAsn1TlsEntry->pDec)
ASN1_CloseDecoder(pAsn1TlsEntry->pDec);
free(pvTls);
} else if (pfnFree) {
// Don't call the callback holding the critical section
LeaveCriticalSection(&CryptTlsCriticalSection);
pfnFree(pvTls);
EnterCriticalSection(&CryptTlsCriticalSection);
// In case this thread gets deleted, start over at
// the beginning.
pThreadTlsNext = pThreadTlsHead;
}
}
}
pThreadTls = pThreadTlsNext;
}
// Insert in beginning of process free list
pProcessTls[hCryptTls].dwType = FREE_CRYPTTLS;
pProcessTls[hCryptTls].dwNext = dwFreeProcessTlsHead;
dwFreeProcessTlsHead = hCryptTls + 1;
fResult = TRUE;
CommonReturn:
LeaveCriticalSection(&CryptTlsCriticalSection);
return fResult;
ErrorReturn:
fResult = FALSE;
goto CommonReturn;
SET_ERROR(InvalidArg, E_INVALIDARG)
}
//+-------------------------------------------------------------------------
// Get the thread specific pointer specified by the
// hCryptTls returned by I_CryptAllocTls().
//
// Returns NULL for an error or uninitialized or NULL pointer.
//--------------------------------------------------------------------------
void *
WINAPI
I_CryptGetTls(
IN HCRYPTTLS hCryptTls
)
{
void **ppvTls;
void *pvTls;
if (ppvTls = GetCryptTls(
hCryptTls,
FALSE)) { // fInhibitAlloc
if (NULL == (pvTls = ppvTls[hCryptTls - 1]))
SetLastError(NO_ERROR);
} else
pvTls = NULL;
return pvTls;
}
//+-------------------------------------------------------------------------
// Set the thread specific pointer specified by the
// hCryptTls returned by I_CryptAllocTls().
//
// Returns FALSE for an invalid handle or unable to allocate memory.
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CryptSetTls(
IN HCRYPTTLS hCryptTls,
IN void *pvTls
)
{
void **ppvTls;
if (ppvTls = GetCryptTls(
hCryptTls,
FALSE)) { // fInhibitAlloc
ppvTls[hCryptTls - 1] = pvTls;
return TRUE;
} else
return FALSE;
}
//+-------------------------------------------------------------------------
// Called at DLL_THREAD_DETACH to free the thread's
// TLS entry specified by the hCryptTls. Returns the thread specific pointer
// to be freed by the caller.
//
// Note, at DLL_PROCESS_DETACH, I_CryptFreeTls should be called instead.
//--------------------------------------------------------------------------
void *
WINAPI
I_CryptDetachTls(
IN HCRYPTTLS hCryptTls
)
{
void **ppvTls;
void *pvTls;
if (ppvTls = GetCryptTls(
hCryptTls,
TRUE)) { // fInhibitAlloc
if (pvTls = ppvTls[hCryptTls - 1])
ppvTls[hCryptTls - 1] = NULL;
else
SetLastError(NO_ERROR);
} else
pvTls = NULL;
return pvTls;
}
//+-------------------------------------------------------------------------
// Install an OssGlobal entry and return a handle for future access.
//
// Each thread has its own copy of OssGlobal. Allocation and
// initialization are deferred until first referenced by the thread.
//
// The parameter, pvCtlTbl is passed to ossinit() to initialize the OssGlobal.
//
// I_CryptGetOssGlobal must be called with the handled returned by
// I_CryptInstallOssGlobal to get the thread specific OssGlobal.
//
// Currently, dwFlags and pvReserved aren't used and must be set to 0.
//--------------------------------------------------------------------------
HCRYPTOSSGLOBAL
WINAPI
I_CryptInstallOssGlobal(
IN void *pvCtlTbl,
IN DWORD dwFlags,
IN void *pvReserved
)
{
HCRYPTOSSGLOBAL hOssGlobal;
if (hOssGlobal = (HCRYPTOSSGLOBAL) I_CryptAllocTls()) {
// Since pProcessTls can be reallocated in another thread
// need CriticalSection
EnterCriticalSection(&CryptTlsCriticalSection);
pProcessTls[hOssGlobal - 1].dwType = OSS_CRYPTTLS;
pProcessTls[hOssGlobal - 1].pvCtlTbl = pvCtlTbl;
LeaveCriticalSection(&CryptTlsCriticalSection);
}
return hOssGlobal;
}
//+-------------------------------------------------------------------------
// Called at DLL_PROCESS_DETACH to uninstall an OssGlobal entry. Iterate
// through the threads and frees their allocated copy of OssGlobal.
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CryptUninstallOssGlobal(
IN HCRYPTOSSGLOBAL hOssGlobal
)
{
return I_CryptFreeTls(
(HCRYPTTLS) hOssGlobal,
NULL // pfnFree
);
}
//+-------------------------------------------------------------------------
// Get the thread specific pointer to the OssGlobal specified by the
// hOssGlobal returned by CryptInstallOssGlobal. If the
// OssGlobal doesn't exist, then, its allocated and initialized using
// the pvCtlTbl associated with hOssGlobal.
//--------------------------------------------------------------------------
POssGlobal
WINAPI
I_CryptGetOssGlobal(
IN HCRYPTOSSGLOBAL hOssGlobal
)
{
POssGlobal pog;
void **ppvTls;
DWORD iOssGlobal;
DWORD dwType;
void *pvCtlTbl;
DWORD dwExceptionCode;
int cbOssGlobalSize;
if (NULL == (ppvTls = GetCryptTls(
(HCRYPTTLS) hOssGlobal,
FALSE))) // fInhibitAlloc
return NULL;
iOssGlobal = (DWORD) hOssGlobal - 1;
if (pog = (POssGlobal) ppvTls[iOssGlobal])
return pog;
// Since pProcessTls can be reallocated in another thread
// need CriticalSection
EnterCriticalSection(&CryptTlsCriticalSection);
dwType = pProcessTls[iOssGlobal].dwType;
pvCtlTbl = pProcessTls[iOssGlobal].pvCtlTbl;
LeaveCriticalSection(&CryptTlsCriticalSection);
if (OSS_CRYPTTLS != dwType || NULL == pvCtlTbl)
goto InvalidArg;
__try {
// Attempt to do delay, demand loading of msoss.dll
OssLoad();
if (0 >= (cbOssGlobalSize = ossGetOssGlobalSize()))
goto ossGetOssGlobalSizeError;
if (NULL == (pog = (POssGlobal) malloc(cbOssGlobalSize)))
goto OutOfMemory;
if (0 != ossinit(pog, pvCtlTbl))
goto ossinitError;
if (0 != ossSetEncodingRules(pog, OSS_DER))
goto SetEncodingRulesError;
#if DBG
if (!DbgInitOSS(pog))
goto DbgInitOSSError;
#else
if (0 != ossSetEncodingFlags(pog, NOTRAPPING | FRONT_ALIGN))
goto SetEncodingFlagsError;
if (0 != ossSetDecodingFlags(pog, NOTRAPPING | RELAXBER))
goto SetDecodingFlagsError;
#endif
} __except(EXCEPTION_EXECUTE_HANDLER) {
dwExceptionCode = GetExceptionCode();
goto msossLoadLibraryException;
}
ppvTls[iOssGlobal] = pog;
CommonReturn:
return pog;
ErrorReturn:
if (pog) {
free(pog);
pog = NULL;
}
goto CommonReturn;
SET_ERROR(ossGetOssGlobalSizeError, ERROR_MOD_NOT_FOUND)
SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
SET_ERROR(InvalidArg, E_INVALIDARG)
TRACE_ERROR(ossinitError)
TRACE_ERROR(SetEncodingRulesError)
#if DBG
TRACE_ERROR(DbgInitOSSError)
#else
TRACE_ERROR(SetEncodingFlagsError)
TRACE_ERROR(SetDecodingFlagsError)
#endif
SET_ERROR_VAR(msossLoadLibraryException, dwExceptionCode)
}
//+-------------------------------------------------------------------------
// Install an Asn1 module entry and return a handle for future access.
//
// Each thread has its own copy of the decoder and encoder associated
// with the Asn1 module. Creation is deferred until first referenced by
// the thread.
//
// I_CryptGetAsn1Encoder or I_CryptGetAsn1Decoder must be called with the
// handle returned by I_CryptInstallAsn1Module to get the thread specific
// Asn1 encoder or decoder.
//
// Currently, dwFlags and pvReserved aren't used and must be set to 0.
//--------------------------------------------------------------------------
HCRYPTASN1MODULE
WINAPI
I_CryptInstallAsn1Module(
IN ASN1module_t pMod,
IN DWORD dwFlags,
IN void *pvReserved
)
{
HCRYPTASN1MODULE hAsn1Module;
if (hAsn1Module = (HCRYPTOSSGLOBAL) I_CryptAllocTls()) {
// Since pProcessTls can be reallocated in another thread
// need CriticalSection
EnterCriticalSection(&CryptTlsCriticalSection);
pProcessTls[hAsn1Module - 1].dwType = ASN1_CRYPTTLS;
pProcessTls[hAsn1Module - 1].pMod = pMod;
LeaveCriticalSection(&CryptTlsCriticalSection);
}
return hAsn1Module;
}
//+-------------------------------------------------------------------------
// Called at DLL_PROCESS_DETACH to uninstall an hAsn1Module entry. Iterates
// through the threads and frees their created Asn1 encoders and decoders.
//--------------------------------------------------------------------------
BOOL
WINAPI
I_CryptUninstallAsn1Module(
IN HCRYPTASN1MODULE hAsn1Module
)
{
return I_CryptFreeTls(
(HCRYPTTLS) hAsn1Module,
NULL // pfnFree
);
}
STATIC
PASN1_TLS_ENTRY
WINAPI
I_CryptGetAsn1Tls(
IN HCRYPTASN1MODULE hAsn1Module
)
{
PASN1_TLS_ENTRY pAsn1TlsEntry;
void **ppvTls;
DWORD iAsn1Module;
if (NULL == (ppvTls = GetCryptTls(
(HCRYPTTLS) hAsn1Module,
FALSE))) // fInhibitAlloc
return NULL;
iAsn1Module = (DWORD) hAsn1Module - 1;
if (pAsn1TlsEntry = (PASN1_TLS_ENTRY) ppvTls[iAsn1Module])
return pAsn1TlsEntry;
if (NULL == (pAsn1TlsEntry = (PASN1_TLS_ENTRY) malloc(
sizeof(ASN1_TLS_ENTRY))))
goto OutOfMemory;
memset(pAsn1TlsEntry, 0, sizeof(ASN1_TLS_ENTRY));
ppvTls[iAsn1Module] = pAsn1TlsEntry;
CommonReturn:
return pAsn1TlsEntry;
ErrorReturn:
goto CommonReturn;
SET_ERROR(OutOfMemory, E_OUTOFMEMORY)
}
//+-------------------------------------------------------------------------
// Get the thread specific pointer to the Asn1 encoder specified by the
// hAsn1Module returned by CryptInstallAsn1Module. If the
// encoder doesn't exist, then, its created using the Asn1 module
// associated with hAsn1Module.
//--------------------------------------------------------------------------
ASN1encoding_t
WINAPI
I_CryptGetAsn1Encoder(
IN HCRYPTASN1MODULE hAsn1Module
)
{
PASN1_TLS_ENTRY pAsn1TlsEntry;
ASN1encoding_t pEnc;
DWORD iAsn1Module;
DWORD dwType;
ASN1module_t pMod;
ASN1error_e Asn1Err;
if (NULL == (pAsn1TlsEntry = I_CryptGetAsn1Tls(hAsn1Module)))
return NULL;
if (pEnc = pAsn1TlsEntry->pEnc)
return pEnc;
iAsn1Module = (DWORD) hAsn1Module - 1;
// Since pProcessTls can be reallocated in another thread
// need CriticalSection
EnterCriticalSection(&CryptTlsCriticalSection);
dwType = pProcessTls[iAsn1Module].dwType;
pMod = pProcessTls[iAsn1Module].pMod;
LeaveCriticalSection(&CryptTlsCriticalSection);
if (ASN1_CRYPTTLS != dwType || NULL == pMod)
goto InvalidArg;
Asn1Err = ASN1_CreateEncoder(
pMod,
&pEnc,
NULL, // pbBuf
0, // cbBufSize
NULL // pParent
);
if (ASN1_SUCCESS != Asn1Err)
goto CreateEncoderError;
pAsn1TlsEntry->pEnc = pEnc;
CommonReturn:
return pEnc;
ErrorReturn:
pEnc = NULL;
goto CommonReturn;
SET_ERROR_VAR(CreateEncoderError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(InvalidArg, E_INVALIDARG)
}
//+-------------------------------------------------------------------------
// Get the thread specific pointer to the Asn1 decoder specified by the
// hAsn1Module returned by CryptInstallAsn1Module. If the
// decoder doesn't exist, then, its created using the Asn1 module
// associated with hAsn1Module.
//--------------------------------------------------------------------------
ASN1decoding_t
WINAPI
I_CryptGetAsn1Decoder(
IN HCRYPTASN1MODULE hAsn1Module
)
{
PASN1_TLS_ENTRY pAsn1TlsEntry;
ASN1decoding_t pDec;
DWORD iAsn1Module;
DWORD dwType;
ASN1module_t pMod;
ASN1error_e Asn1Err;
if (NULL == (pAsn1TlsEntry = I_CryptGetAsn1Tls(hAsn1Module)))
return NULL;
if (pDec = pAsn1TlsEntry->pDec)
return pDec;
iAsn1Module = (DWORD) hAsn1Module - 1;
// Since pProcessTls can be reallocated in another thread
// need CriticalSection
EnterCriticalSection(&CryptTlsCriticalSection);
dwType = pProcessTls[iAsn1Module].dwType;
pMod = pProcessTls[iAsn1Module].pMod;
LeaveCriticalSection(&CryptTlsCriticalSection);
if (ASN1_CRYPTTLS != dwType || NULL == pMod)
goto InvalidArg;
Asn1Err = ASN1_CreateDecoder(
pMod,
&pDec,
NULL, // pbBuf
0, // cbBufSize
NULL // pParent
);
if (ASN1_SUCCESS != Asn1Err)
goto CreateDecoderError;
pAsn1TlsEntry->pDec = pDec;
CommonReturn:
return pDec;
ErrorReturn:
pDec = NULL;
goto CommonReturn;
SET_ERROR_VAR(CreateDecoderError, PkiAsn1ErrToHr(Asn1Err))
SET_ERROR(InvalidArg, E_INVALIDARG)
}