//+------------------------------------------------------------------------- // 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 #include #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) }