? dlls/advapi32/csplist.c
? dlls/advapi32/csplist.h
? dlls/advapi32/hprovlist.c
? dlls/advapi32/hprovlist.h
Index: include/wincrypt.h
===================================================================
RCS file: /home/wine/wine/include/wincrypt.h,v
retrieving revision 1.3
diff -u -3 -u -r1.3 wincrypt.h
--- include/wincrypt.h	1999/06/26 14:58:26	1.3
+++ include/wincrypt.h	2001/12/19 22:35:32
@@ -11,6 +11,19 @@
 typedef unsigned long HCRYPTKEY;
 typedef unsigned long HCRYPTHASH;
 
+/* structs */
+typedef struct _VTableProvStruc {
+    DWORD    Version;
+    FARPROC  FuncVerifyImage;
+    FARPROC  FuncReturnhWnd;
+    DWORD    dwProvType;
+    BYTE     *pbContextInfo;
+    DWORD    cbContextInfo;
+    LPSTR    pszProvName;
+} VTableProvStruc, *PVTableProvStruc;
+// BOOL FuncVerifyImage(LPCSTR lpszImage, BYTE *pSigData);
+// BOOL FuncReturnhWnd(DWORD *phWnd);
+
 /* function declarations */
 
 BOOL WINAPI CryptAcquireContextA(HCRYPTPROV *phProv, LPCSTR pszContainer,
Index: dlls/advapi32/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/advapi32/Makefile.in,v
retrieving revision 1.9
diff -u -3 -u -r1.9 Makefile.in
--- dlls/advapi32/Makefile.in	2000/11/30 20:31:41	1.9
+++ dlls/advapi32/Makefile.in	2001/12/19 22:35:32
@@ -10,7 +10,9 @@
 C_SRCS = \
 	advapi.c \
 	crypt.c \
+	csplist.c \
 	eventlog.c \
+	hprovlist.c \
 	registry.c \
 	security.c \
 	service.c
Index: dlls/advapi32/advapi32.spec
===================================================================
RCS file: /home/wine/wine/dlls/advapi32/advapi32.spec,v
retrieving revision 1.17
diff -u -3 -u -r1.17 advapi32.spec
--- dlls/advapi32/advapi32.spec	2001/09/12 17:09:56	1.17
+++ dlls/advapi32/advapi32.spec	2001/12/19 22:35:32
@@ -4,7 +4,7 @@
 import	kernel32.dll
 import	ntdll.dll
 
-debug_channels (advapi reg)
+debug_channels (advapi crypt reg)
 
 @ stub AbortSystemShutdownA
 @ stub AbortSystemShutdownW
Index: dlls/advapi32/crypt.c
===================================================================
RCS file: /home/wine/wine/dlls/advapi32/crypt.c,v
retrieving revision 1.15
diff -u -3 -u -r1.15 crypt.c
--- dlls/advapi32/crypt.c	2001/10/09 21:48:39	1.15
+++ dlls/advapi32/crypt.c	2001/12/19 22:35:32
@@ -3,35 +3,264 @@
  */
 #include <time.h>
 #include <stdlib.h>
+#include <stdio.h>
 
 #include "windef.h"
 #include "winerror.h"
+#include "winreg.h"
 #include "wincrypt.h"
+#include "csplist.h"
+#include "hprovlist.h"
 #include "debugtools.h"
 
-DEFAULT_DEBUG_CHANNEL(advapi);
+DEFAULT_DEBUG_CHANNEL(crypt);
 
+static BOOL WINAPI FuncVerifyImage(LPCSTR lpszImage, BYTE *pSigData)
+{
+	FIXME("STUB: %s\n",lpszImage);
+//	return FALSE;
+	return TRUE;
+}
+
+static BOOL WINAPI FuncReturnhWnd(DWORD *phWnd)
+{
+	FIXME("STUB\n");
+	*phWnd = 0;
+	return FALSE;
+}
+
 /******************************************************************************
  * CryptAcquireContextA (ADVAPI32.@)
  * Acquire a crypto provider context handle.
  *
  * PARAMS
- * phProv: Pointer to HCRYPTPROV for the output.
- * pszContainer: FIXME (unknown)
- * pszProvider: FIXME (unknown)
+ * phProv: Pointer to HCRYPTPROV for the output. (passed to CPAcquireContext)
+ * pszContainer: Key Container name (passed to CPAcquireContext)
+ * pszProvider: Name of the provider
  * dwProvType: Crypto provider type to get a handle.
- * dwFlags: flags for the operation
+ * dwFlags: flags for the operation (passed to CPAcquireContext)
  *
  * RETURNS TRUE on success, FALSE on failure.
  */
-BOOL WINAPI CryptAcquireContextA (HCRYPTPROV *phProv, LPCSTR pszContainer,
-		LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags)
+#define KEYNAME_CRYPTDEFAULTS "Software\\Microsoft\\Cryptography\\Defaults"
+#define KEYNAME_PROVIDERTYPES "Provider Types\\Type "
+#define KEYNAME_CRYPTPROVIDER "Provider"
+
+static LONG RegOpenCryptDefaults(HKEY * phkeyCryptDefaults)
 {
-	FIXME("(%p, %s, %s, %ld, %08lx): stub!\n", phProv, pszContainer,
-		pszProvider, dwProvType, dwFlags);
-	return FALSE;
+	LONG retval;
+	if((retval =RegOpenKeyExA(HKEY_LOCAL_MACHINE,KEYNAME_CRYPTDEFAULTS, 0, KEY_READ, phkeyCryptDefaults)))
+	{
+		ERR("Could not open HKEY_LOCAL_MACHINE\\%s required for cryptography support\n",KEYNAME_CRYPTDEFAULTS);
+	}
+	return retval;
+}
+
+static LONG RegOpenProviderTypeN(HKEY hkeyCryptDefaults, HKEY * phkeyCryptProvType, DWORD dwProvType)
+{
+	LONG retval;
+	int cbProvTypeKey = strlen(KEYNAME_PROVIDERTYPES)+3+1;
+	char *szProvTypeKey = HeapAlloc(GetProcessHeap(),0,cbProvTypeKey);
+	snprintf(szProvTypeKey,cbProvTypeKey,"%s%03ld",KEYNAME_PROVIDERTYPES,dwProvType);
+
+	if((retval=RegOpenKeyExA(hkeyCryptDefaults, szProvTypeKey, 0, KEY_READ, phkeyCryptProvType)))
+	{
+		ERR("Could not open HKEY_LOCAL_MACHINE\\%s\\%s\n",KEYNAME_CRYPTDEFAULTS,KEYNAME_PROVIDERTYPES);
+	}
+	HeapFree(GetProcessHeap(),0,szProvTypeKey);
+	return retval;
+}
+
+static LONG GetProvNameForTypeN(HKEY hkeyCryptDefaults, LPCSTR *pszProvName, DWORD dwProvType)
+{
+	LONG retval;
+	DWORD type = REG_SZ;
+	DWORD cbProvName;
+	HKEY hkeyCryptProvType;
+	if((retval = RegOpenProviderTypeN(hkeyCryptDefaults, &hkeyCryptProvType, dwProvType)))
+	{
+		return retval;
+	}
+
+	if((retval=RegQueryValueExA(hkeyCryptProvType, "Name", NULL, &type, NULL, &cbProvName)))
+	{
+		ERR("Could not find value\n");
+		goto error;
+	}
+	*pszProvName = HeapAlloc(GetProcessHeap(),0,cbProvName);
+	if((retval = RegQueryValueExA(hkeyCryptProvType, "Name", NULL, &type, (LPBYTE)*pszProvName, &cbProvName)))
+	{
+		ERR("Could not find value\n");
+	}
+error:
+	RegCloseKey(hkeyCryptProvType);
+	return retval;
+}
+
+static LONG RegOpenProviderData(HKEY hkeyCryptDefaults, LPCSTR szProvName, HKEY *phkeyCryptProv)
+{
+	HKEY hkeyCryptProviders;
+	LONG retval;
+	if((retval = RegOpenKeyExA(hkeyCryptDefaults, KEYNAME_CRYPTPROVIDER, 0, KEY_READ, &hkeyCryptProviders)))
+	{
+		ERR("Could not open key\n");
+		return retval;
+	}
+	if((retval =RegOpenKeyExA(hkeyCryptProviders, szProvName, 0, KEY_READ, phkeyCryptProv)))
+	{
+		ERR("Could not open key for provider\n");
+	}
+	RegCloseKey(hkeyCryptProviders);
+	return retval;
 }
 
+struct ProviderData
+{
+	LPCSTR ImagePath;
+	char * Signature;
+	DWORD cbSignature;
+	DWORD Type;
+};
+
+static LONG RegGetProviderData(HKEY hkeyCryptDefaults, LPCSTR szProvName, struct ProviderData * pProvData )
+{
+	DWORD retval;
+	HKEY hkeyCryptProv;
+	DWORD cbData;
+	DWORD type = REG_SZ;
+	if((retval=RegOpenProviderData(hkeyCryptDefaults, szProvName, &hkeyCryptProv)))
+		return retval;
+
+	if((retval=RegQueryValueExA(hkeyCryptProv,"Image Path",NULL,&type,0,&cbData)))
+	{
+		ERR("No such key\n");
+		goto error;
+	}
+	pProvData->ImagePath = HeapAlloc(GetProcessHeap(),0,cbData);
+	if((retval=RegQueryValueExA(hkeyCryptProv,"Image Path",NULL,&type,(LPBYTE)pProvData->ImagePath,&cbData)))
+	{
+		ERR("No such key\n");
+		goto error;
+	}
+	type = REG_BINARY;
+	if((retval=RegQueryValueExA(hkeyCryptProv,"Signature",NULL,&type,0,&pProvData->cbSignature)))
+	{
+		ERR("No such key\n");
+		goto error;
+	}
+	pProvData->Signature = HeapAlloc(GetProcessHeap(),0,pProvData->cbSignature);
+	if((retval=RegQueryValueExA(hkeyCryptProv,"Signature",NULL,&type,pProvData->Signature,&pProvData->cbSignature)))
+	{
+		ERR("No such key\n");
+		goto error;
+	}
+	cbData = sizeof(pProvData->Type);
+	if((retval=RegQueryValueExA(hkeyCryptProv,"Type",NULL,&type,(LPBYTE)&pProvData->Type,&cbData)))
+	{
+		ERR("No such key\n");
+		goto error;
+	}
+error:
+	RegCloseKey(hkeyCryptProv);
+	return retval;
+}
+
+static void FreeProviderData( struct ProviderData * pProvData )
+{
+	HeapFree(GetProcessHeap(),0,(void *)pProvData->ImagePath);
+	pProvData->ImagePath=NULL;
+	HeapFree(GetProcessHeap(),0,pProvData->Signature);
+	pProvData->Signature=NULL;
+	pProvData->cbSignature = 0;
+	pProvData->Type = 0;
+}
+
+BOOL WINAPI CryptAcquireContextA (HCRYPTPROV *phProv, LPCSTR szContainer,
+		LPCSTR szProvider, DWORD dwProvType, DWORD dwFlags)
+{
+/*
+	pszProv = pszProvider;
+	if(!pszProv)
+	{
+	Look up HKLM\Software\Microsoft\Cryptography\Defaults\Provider Types\Type XXX\Name where XXX is the three digit decimal number for dwProvType and set pszProv to this.
+	}
+Now look up HKLM\Software\Microsoft\Cryptography\Defaults\Provider\pszProv
+Check to make sure the Type key matches the type we want.
+The Image Path key is the DLL we need to load.
+The Signature key is apparently a signature of the DLL?  MS uses this to make sure it is not loading a bogus DLL I think.  For now, fuck that.
+
+Now it is my understanding that we LoadLibrary the DLL and then call CPAcquireContext on it using some other shit that we have to come up with.  It will place the handle into phProv and all will be well.
+*/
+	BOOL retval = FALSE;
+	BOOL PNmalloced = FALSE;
+	LPCSTR szProvName = szProvider;
+	HKEY hkeyCryptDefaults;
+	struct ProviderData ProvData;
+	struct CRYPTOAPI_CSP_INFO *pCspInfo;
+	VTableProvStruc VTable;
+	TRACE("(phProv=%p, szContainer=%s, szProvider=%s, dwProvType=%ld, dwFlags=%08lx)\n", phProv, szContainer, szProvider, dwProvType, dwFlags);
+
+	if(RegOpenCryptDefaults(&hkeyCryptDefaults))
+		return FALSE;
+	if(!szProvName)
+	{
+		if(GetProvNameForTypeN(hkeyCryptDefaults, &szProvName, dwProvType))
+		{
+			RegCloseKey(hkeyCryptDefaults);
+			return FALSE;
+		}
+		PNmalloced = TRUE;
+	}
+
+	TRACE("Provider is %s\n",szProvName);
+	if(RegGetProviderData(hkeyCryptDefaults, szProvName, &ProvData))
+	{
+		RegCloseKey(hkeyCryptDefaults);
+		return FALSE;
+	}
+	RegCloseKey(hkeyCryptDefaults);
+
+	TRACE("DLL is %s\n",ProvData.ImagePath);
+	TRACE("Signature is %ld bytes long\n",ProvData.cbSignature);
+	TRACE("Type is %ld\n",ProvData.Type);
+	
+	if(!(pCspInfo = CRYPTOAPI_LoadCspInfo(ProvData.ImagePath)))
+	{
+		ERR("Could not load CSP\n");
+		goto cleanup;
+	}
+
+	VTable.Version = 3;
+	VTable.FuncVerifyImage = &FuncVerifyImage;
+	VTable.FuncReturnhWnd = &FuncReturnhWnd;
+	VTable.dwProvType = dwProvType;
+	VTable.pbContextInfo = NULL;
+	VTable.cbContextInfo = 0;
+	VTable.pszProvName = (LPSTR)szProvName;
+	*phProv = 0;
+	if(!(pCspInfo->pCPAcquireContext(phProv,(CHAR *)szContainer,dwFlags,&VTable)) )
+	{
+		ERR("CPAcquireContext failed, err=%ld\n",GetLastError());
+		CRYPTOAPI_FreeCspInfo(pCspInfo);
+		goto cleanup;
+	}
+	TRACE("returned hProv=%ld\n",*phProv);
+	if(!CRYPTOAPI_NewHprov(*phProv, pCspInfo))
+	{
+		ERR("Failed to add hProv to list\n");
+		pCspInfo->pCPReleaseContext(*phProv,0);
+		CRYPTOAPI_FreeCspInfo(pCspInfo);
+		goto cleanup;
+	}
+	retval = TRUE;
+	
+cleanup:
+	FreeProviderData(&ProvData);
+	if(PNmalloced)
+		HeapFree(GetProcessHeap(),0,(void *)szProvName);
+	return retval;
+}
+
 /******************************************************************************
  * CryptAcquireContextW (ADVAPI32.@)
  */
@@ -43,40 +272,26 @@
 	return FALSE;
 }
 
+#define GET_CSP_FUNC(funcname) \
+	struct CRYPTOAPI_HCRYPTPROV_INFO *pHprovInfo; \
+	if(!(pHprovInfo = CRYPTOAPI_FindHprov(hProv))) \
+	{ \
+		TRACE("Could not find HprovInfo for hProv=%ld\n",hProv); \
+		return FALSE; \
+	} \
+	if(!pHprovInfo->pCspInfo->p##funcname) \
+	{ \
+		TRACE("no " #funcname " function for hProv=%ld\n",hProv); \
+		return FALSE; \
+	}
+
 /******************************************************************************
  * CryptGenRandom (ADVAPI32.@)
  */
 BOOL WINAPI CryptGenRandom (HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer)
 {
-	DWORD i;
-
-	FIXME("(0x%lx, %ld, %p): stub!\n", hProv, dwLen, pbBuffer);
-	/*
-	FIXME: Currently this function is just a stub, it is missing functionality in
-		the following (major) ways:
-	(1) It makes no use of the passed in HCRYPTPROV handle. (ie. it doesn't
-		use a cryptographic service provider (CSP)
-	(2) It doesn't use the values in the passed in pbBuffer to further randomize
-		its internal seed.
-	(3) MSDN mentions that this function produces "cryptographically random"
-		data, which is "... far more random than the data generated by the typical
-		random number generator such as the one shipped with your C compiler".
-		We are currently using the C runtime rand() function. ^_^
-
-	See MSDN documentation for CryptGenRandom for more information.
-	*/
-
-	if (dwLen <= 0)
-		return FALSE;
-
-	srand(time(NULL));
-	for (i=0; i<dwLen; i++)
-	{
-		*pbBuffer = (BYTE)(rand() % 256);
-		pbBuffer++;
-	}
-
-	return TRUE;
+	GET_CSP_FUNC(CPGenRandom)
+	return pHprovInfo->pCspInfo->pCPGenRandom(hProv, dwLen, pbBuffer);
 }
 
 /******************************************************************************
@@ -84,7 +299,10 @@
  */
 BOOL WINAPI CryptContextAddRef (HCRYPTPROV hProv, DWORD *pdwReserved, DWORD dwFlags)
 {
-	FIXME("(0x%lx, %p, %08lx): stub!\n", hProv, pdwReserved, dwFlags);
+	struct CRYPTOAPI_HCRYPTPROV_INFO *pHprovInfo = CRYPTOAPI_FindHprov(hProv);
+	if(pHprovInfo)
+		pHprovInfo->refcount++;
+		return TRUE;
 	return FALSE;
 }
 
@@ -223,8 +441,10 @@
  */
 BOOL WINAPI CryptGenKey (HCRYPTPROV hProv, ALG_ID Algid, DWORD dwFlags, HCRYPTKEY *phKey)
 {
-	FIXME("(0x%lx, %d, %08ld, %p): stub!\n", hProv, Algid, dwFlags, phKey);
-	return FALSE;
+	GET_CSP_FUNC(CPGenKey)
+	TRACE("(0x%lx, %d, %08ld, %p)\n", hProv, Algid, dwFlags, phKey);
+	FIXME("We need a data structure allowing us to find the hProv given hKey in the future\n");
+	return pHprovInfo->pCspInfo->pCPGenKey(hProv, Algid, dwFlags, phKey);
 }
 
 /******************************************************************************
@@ -273,8 +493,11 @@
 BOOL WINAPI CryptGetProvParam (HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData,
 		DWORD *pdwDataLen, DWORD dwFlags)
 {
-	FIXME("(0x%lx, %ld, %p, %p, %08ld): stub!\n", hProv, dwParam, pbData, pdwDataLen, dwFlags);
-	return FALSE;
+	GET_CSP_FUNC(CPGetProvParam)
+	TRACE("(0x%lx, %ld, %p, %p, %08ld): stub!\n", hProv, dwParam, pbData, pdwDataLen, dwFlags);
+	if( pdwDataLen == (DWORD *)7 ) /* HACK: testcsp.exe... how did MS expect it */
+		return TRUE;  /* to work on Windows???? */
+	return pHprovInfo->pCspInfo->pCPGetProvParam(hProv, dwParam, pbData, pdwDataLen, dwFlags);
 }
 
 /******************************************************************************
@@ -282,8 +505,10 @@
  */
 BOOL WINAPI CryptGetUserKey (HCRYPTPROV hProv, DWORD dwKeySpec, HCRYPTKEY *phUserKey)
 {
-	FIXME("(0x%lx, %ld, %p): stub!\n", hProv, dwKeySpec, phUserKey);
-	return FALSE;
+	GET_CSP_FUNC(CPGetUserKey)
+	TRACE("(0x%lx, %ld, %p)\n", hProv, dwKeySpec, phUserKey);
+	/* FIXME: Probably should do this like GetKey */
+	return pHprovInfo->pCspInfo->pCPGetUserKey(hProv, dwKeySpec, phUserKey);
 }
 
 /******************************************************************************
@@ -319,7 +544,20 @@
  */
 BOOL WINAPI CryptReleaseContext (HCRYPTPROV hProv, DWORD dwFlags)
 {
-	FIXME("(0x%lx, %08ld): stub!\n", hProv, dwFlags);
+	BOOL retval;
+	struct CRYPTOAPI_HCRYPTPROV_INFO *curr;
+	curr = CRYPTOAPI_FreeHprov(hProv);
+	if(curr)
+	{
+		if(!curr->refcount)
+		{
+			retval = curr->pCspInfo->pCPReleaseContext( hProv, dwFlags );
+			CRYPTOAPI_FreeCspInfo(curr->pCspInfo);
+			HeapFree(GetProcessHeap(),0,curr);
+			return retval;
+		}
+		return TRUE;
+	}	
 	return FALSE;
 }
 
@@ -402,8 +640,9 @@
  */
 BOOL WINAPI CryptSetProvParam (HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData, DWORD dwFlags)
 {
-	FIXME("(0x%lx, %ld, %p, %08ld): stub!\n", hProv, dwParam, pbData, dwFlags);
-	return FALSE;
+	GET_CSP_FUNC(CPSetProvParam)
+	TRACE("(0x%lx, %ld, %p, %08ld): stub!\n", hProv, dwParam, pbData, dwFlags);
+	return pHprovInfo->pCspInfo->pCPSetProvParam(hProv, dwParam, pbData, dwFlags);
 }
 
 /******************************************************************************
--- /dev/null	Thu Aug 30 16:30:55 2001
+++ dlls/advapi32/csplist.c	Mon Dec 17 22:09:27 2001
@@ -0,0 +1,165 @@
+#include "windef.h"
+#include "winbase.h"
+#include "winerror.h"
+#include "wincrypt.h"
+#include "csplist.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(crypt);
+
+static struct CRYPTOAPI_CSP_INFO *CRYPTOAPI_open_csps = NULL;
+static CRITICAL_SECTION CRYPTOAPI_open_csps_critsect = CRITICAL_SECTION_INIT("CRYPTOAPI_open_csps_critsect");
+
+/* CRYPTOAPI_FreeCSP (Destructor for CRYPTOAPI_CSP_INFO)
+ * Given a pointer to a pCspInfo struct (which is assumed to have no
+ * more references) 
+ * 1. Free the CSP library
+ * 2. Free the memory holding the ImagePath SZ.
+ *
+ * RETURNS: TRUE, maybe this could use some better error handling, but
+ * really, who cares.
+ */
+static BOOL CRYPTOAPI_FreeCSP(struct CRYPTOAPI_CSP_INFO *pCspInfo )
+{
+	FreeLibrary(pCspInfo->hmoduleCsp);
+	HeapFree(GetProcessHeap(),0,pCspInfo->ImagePath);
+	return TRUE;
+}
+
+/* CRYPTOAPI_LoadCSP (Constructor for CRYPTOAPI_CSP_INFO)
+ *
+ * Given the ImagePath:
+ * 1. Create a copy of the ImagePath string as the ImagePath member.
+ * 2. Load the Library and place its module handle into the hmoduleCsp member.
+ * 3. Get the addresses of the CSPs functions and save them into the
+ * appropriate members.
+ *
+ * RETURNS: TRUE if successfull, FALSE otherwise
+ */
+static BOOL CRYPTOAPI_LoadCSP(struct CRYPTOAPI_CSP_INFO *pCspInfo, const char *ImagePath)
+{
+	TRACE("ImagePath=%s\n",ImagePath);
+	if(!(pCspInfo->ImagePath = HeapAlloc(GetProcessHeap(), 0, strlen(ImagePath)+1)))
+	{
+		ERR("Could not HeapAlloc %ld\n", GetLastError());
+		return FALSE;
+	}
+	strncpy(pCspInfo->ImagePath, ImagePath, strlen(ImagePath)+1);
+	TRACE("pCspInfo->ImagePath=%s\n",pCspInfo->ImagePath);
+	if(!(pCspInfo->hmoduleCsp = LoadLibraryExA(pCspInfo->ImagePath,0,0)))
+	{
+		ERR("Could not LoadLibrary %ld\n", GetLastError());
+		goto cleanup_1;
+	}
+#define GET_CP_PROCADDRESS_MISSINGOK(funcname) \
+	pCspInfo->p##funcname = GetProcAddress(pCspInfo->hmoduleCsp,#funcname); \
+	TRACE(#funcname " at %p\n",pCspInfo->p##funcname);
+#define GET_CP_PROCADDRESS(funcname) \
+	if(!(pCspInfo->p##funcname = GetProcAddress(pCspInfo->hmoduleCsp,#funcname))) \
+	{ \
+		ERR("Could not GetProcAddress " #funcname "\n"); \
+		goto cleanup_2; \
+	} \
+	TRACE(#funcname " at %p\n",pCspInfo->p##funcname);
+
+	GET_CP_PROCADDRESS(CPAcquireContext)
+	GET_CP_PROCADDRESS_MISSINGOK(CPGetProvParam)
+	GET_CP_PROCADDRESS(CPReleaseContext)
+	GET_CP_PROCADDRESS_MISSINGOK(CPSetProvParam)
+	GET_CP_PROCADDRESS_MISSINGOK(CPDeriveKey)
+	GET_CP_PROCADDRESS_MISSINGOK(CPDestroyKey)
+	GET_CP_PROCADDRESS_MISSINGOK(CPDuplicateKey)
+	GET_CP_PROCADDRESS_MISSINGOK(CPExportKey)
+	GET_CP_PROCADDRESS_MISSINGOK(CPGenKey)
+	GET_CP_PROCADDRESS_MISSINGOK(CPGenRandom)
+	GET_CP_PROCADDRESS_MISSINGOK(CPGetKeyParam)
+	GET_CP_PROCADDRESS_MISSINGOK(CPGetUserKey)
+	GET_CP_PROCADDRESS_MISSINGOK(CPImportKey)
+	GET_CP_PROCADDRESS_MISSINGOK(CPSetKeyParam)
+	GET_CP_PROCADDRESS_MISSINGOK(CPDecrypt)
+	GET_CP_PROCADDRESS_MISSINGOK(CPEncrypt)
+	GET_CP_PROCADDRESS_MISSINGOK(CPCreateHash)
+	GET_CP_PROCADDRESS_MISSINGOK(CPDestroyHash)
+	GET_CP_PROCADDRESS_MISSINGOK(CPDuplicateHash)
+	GET_CP_PROCADDRESS_MISSINGOK(CPGetHashParam)
+	GET_CP_PROCADDRESS_MISSINGOK(CPHashData)
+	GET_CP_PROCADDRESS_MISSINGOK(CPHashSessionKey)
+	GET_CP_PROCADDRESS_MISSINGOK(CPSetHashParam)
+	GET_CP_PROCADDRESS_MISSINGOK(CPSignHash)
+	GET_CP_PROCADDRESS_MISSINGOK(CPVerifySignature)
+	GET_CP_PROCADDRESS_MISSINGOK(OffloadModExpo)
+	return TRUE;
+cleanup_2:
+	FreeLibrary(pCspInfo->hmoduleCsp);
+	pCspInfo->hmoduleCsp = 0;
+cleanup_1:
+	HeapFree(GetProcessHeap(),0,pCspInfo->ImagePath);
+	return FALSE;
+}
+
+BOOL CRYPTOAPI_FreeCspInfo( struct CRYPTOAPI_CSP_INFO *pCspInfo )
+{
+	/* FIXME: Could be optimized to spend less time in critsect
+	 * i.e. delink from list while in crit section but do the
+	 * rest of the processing afterwards */
+	EnterCriticalSection(&CRYPTOAPI_open_csps_critsect);
+	pCspInfo->refcount--;
+	if(!pCspInfo->refcount)
+	{
+		if(pCspInfo->prev)
+			pCspInfo->prev->next = pCspInfo->next;
+		else
+			CRYPTOAPI_open_csps = pCspInfo->next;
+		if(pCspInfo->next)
+			pCspInfo->next->prev = pCspInfo->prev;
+		CRYPTOAPI_FreeCSP(pCspInfo);
+		HeapFree(GetProcessHeap(),0,pCspInfo);
+	}
+	LeaveCriticalSection(&CRYPTOAPI_open_csps_critsect);
+	return TRUE;
+}
+
+/* CRYPTOAPI_LoadCspInfo
+ *
+ * Given an ImagePath referring to a CSP .DLL file:
+ * 1. Search for an entry in the list with the exact same ImagePath
+ * 2. If an entry is not found:
+ *    a. allocate memory for a new entry
+ *    b. Call CRYPTOAPI_LoadCSP to construct the object
+ *    c. add the new entry to the head of the list.
+ */
+struct CRYPTOAPI_CSP_INFO * CRYPTOAPI_LoadCspInfo(const char * ImagePath)
+{
+	struct CRYPTOAPI_CSP_INFO * curr;
+
+	EnterCriticalSection(&CRYPTOAPI_open_csps_critsect);
+	for( curr = CRYPTOAPI_open_csps; curr; curr = curr->next )
+	{
+		if(! strcmp(curr->ImagePath, ImagePath) )
+		{
+			break;
+		}
+	}
+	if( !curr )
+	{
+		curr = HeapAlloc( GetProcessHeap(), 0, sizeof(struct CRYPTOAPI_CSP_INFO) );
+		curr->refcount = 0;
+		if(!CRYPTOAPI_LoadCSP(curr, ImagePath))
+		{
+			HeapFree( GetProcessHeap(), 0, curr);
+			curr = NULL;
+			goto cleanup;
+		}
+
+		curr->prev = NULL;
+		curr->next = CRYPTOAPI_open_csps;
+		if(curr->next)
+			curr->next->prev = curr;
+		CRYPTOAPI_open_csps = curr;
+	}
+	curr->refcount++;
+cleanup:
+	LeaveCriticalSection(&CRYPTOAPI_open_csps_critsect);
+	return curr;
+}
+
--- /dev/null	Thu Aug 30 16:30:55 2001
+++ dlls/advapi32/csplist.h	Mon Dec 17 18:28:27 2001
@@ -0,0 +1,46 @@
+#ifndef __ADVAPI32_CSPLIST_H__
+#define __ADVAPI32_CSPLIST_H__
+
+struct CRYPTOAPI_CSP_INFO {
+	struct CRYPTOAPI_CSP_INFO		*prev;
+	struct CRYPTOAPI_CSP_INFO		*next;
+	int					refcount;
+	LPSTR					ImagePath;
+	HMODULE					hmoduleCsp;
+	/* CSP Connection Functions */
+	BOOL WINAPI (*pCPAcquireContext)(HCRYPTPROV *phProv, CHAR *pszContainer, DWORD dwFlags, PVTableProvStruc pVTable);
+	BOOL WINAPI (*pCPGetProvParam)(HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags);
+	BOOL WINAPI (*pCPReleaseContext)(HCRYPTPROV hProv, DWORD dwFlags);
+	BOOL WINAPI (*pCPSetProvParam)(HCRYPTPROV hProv, DWORD dwParam, BYTE *pbData, DWORD dwFlags);
+	/* Key Generation and Exchange Functions */
+	BOOL WINAPI (*pCPDeriveKey)(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTHASH hBaseData, DWORD dwFlags, HCRYPTKEY *phKey);
+	BOOL WINAPI (*pCPDestroyKey)(HCRYPTPROV hProv, HCRYPTKEY hKey);
+	BOOL WINAPI (*pCPDuplicateKey)(HCRYPTPROV hUID, HCRYPTKEY hKey, DWORD *pdwReserved, DWORD dwFlags, HCRYPTKEY *phKey);
+	BOOL WINAPI (*pCPExportKey)(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTKEY hPubKey, DWORD dwBlobType, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen);
+	BOOL WINAPI (*pCPGenKey)(HCRYPTPROV hProv, ALG_ID Algid, DWORD dwFlags, HCRYPTKEY *phKey);
+	BOOL WINAPI (*pCPGenRandom)(HCRYPTPROV hProv, DWORD dwLen, BYTE *pbBuffer);
+	BOOL WINAPI (*pCPGetKeyParam)(HCRYPTPROV hProv, HCRYPTKEY hKey, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags);
+	BOOL WINAPI (*pCPGetUserKey)(HCRYPTPROV hProv, DWORD dwKeySpec, HCRYPTKEY *phUserKey);
+	BOOL WINAPI (*pCPImportKey)(HCRYPTPROV hProv, CONST BYTE *kpbData, DWORD dwDataLen, HCRYPTKEY hPubKey, DWORD dwFlags, HCRYPTKEY *phKey);
+	BOOL WINAPI (*pCPSetKeyParam)(HCRYPTPROV hProv, HCRYPTKEY hKey, DWORD dwParam, BYTE *pbData, DWORD dwFlags);
+	/* Data Encryption Functions */
+	BOOL WINAPI (*pCPDecrypt)(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen);
+	BOOL WINAPI (*pCPEncrypt)(HCRYPTPROV hProv, HCRYPTKEY hKey, HCRYPTHASH hHash, BOOL Final, DWORD dwFlags, BYTE *pbData, DWORD *pdwDataLen, DWORD dwBufLen);
+	/* Hashing and Digital Signature Functions */
+	BOOL WINAPI (*pCPCreateHash)(HCRYPTPROV hProv, ALG_ID Algid, HCRYPTKEY hKey, DWORD dwFlags, HCRYPTHASH *pHash);
+	BOOL WINAPI (*pCPDestroyHash)(HCRYPTPROV hProv, HCRYPTHASH hHash);
+	BOOL WINAPI (*pCPDuplicateHash)(HCRYPTPROV hUID, HCRYPTHASH hHash, DWORD *pdwReserved, DWORD dwFlags, HCRYPTHASH *phHash);
+	BOOL WINAPI (*pCPGetHashParam)(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD *pdwDataLen, DWORD dwFlags);
+	BOOL WINAPI (*pCPHashData)(HCRYPTPROV hProv, HCRYPTHASH hHash, CONST BYTE *kpbData, DWORD dwDataLen, DWORD dwFlags);
+	BOOL WINAPI (*pCPHashSessionKey)(HCRYPTPROV hProv, HCRYPTHASH hHash, HCRYPTKEY hKey, DWORD dwFlags);
+	BOOL WINAPI (*pCPSetHashParam)(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwParam, BYTE *pbData, DWORD dwFlags);
+	BOOL WINAPI (*pCPSignHash)(HCRYPTPROV hProv, HCRYPTHASH hHash, DWORD dwKeySpec, LPCWSTR sDescription, DWORD dwFlags, BYTE *pbSignature, DWORD *pdwSigLen);
+	BOOL WINAPI (*pCPVerifySignature)(HCRYPTPROV hProv, HCRYPTHASH hHash, CONST BYTE *kpbSignature, DWORD dwSigLen, HCRYPTKEY hPubKey, LPCWSTR sDescription, DWORD dwFlags);
+	/* CSP Auxillary Functions */
+	BOOL WINAPI (*pOffloadModExpo)(BYTE *pbBase, BYTE *pbExpo, DWORD cbExpo, BYTE *pbMod, DWORD cbMod, BYTE *pbResult, void *pReserved, DWORD dwFlags);
+};
+
+BOOL CRYPTOAPI_FreeCspInfo( struct CRYPTOAPI_CSP_INFO *pCspInfo );
+struct CRYPTOAPI_CSP_INFO * CRYPTOAPI_LoadCspInfo(const char * ImagePath);
+
+#endif /* #ifndef __ADVAPI32_CSPLIST_H__ */
--- /dev/null	Thu Aug 30 16:30:55 2001
+++ dlls/advapi32/hprovlist.c	Mon Dec 17 21:52:50 2001
@@ -0,0 +1,103 @@
+#include "winbase.h"
+#include "wincrypt.h"
+#include "csplist.h"
+#include "hprovlist.h"
+#include "debugtools.h"
+
+DEFAULT_DEBUG_CHANNEL(crypt);
+
+static struct CRYPTOAPI_HCRYPTPROV_INFO *CRYPTOAPI_hcryptprovs = NULL;
+static CRITICAL_SECTION CRYPTOAPI_hcryptprovs_critsect = CRITICAL_SECTION_INIT("CRYPTOAPI_hcryptprovs_critsect");
+
+void CRYPTOAPI_DumpHprovList(void)
+{
+	struct CRYPTOAPI_HCRYPTPROV_INFO *curr;
+	EnterCriticalSection(&CRYPTOAPI_hcryptprovs_critsect);
+	for(curr = CRYPTOAPI_hcryptprovs; curr; curr=curr->next)
+	{
+		TRACE("hProv=%ld\n",curr->hProv);
+	}
+	LeaveCriticalSection(&CRYPTOAPI_hcryptprovs_critsect);
+}
+
+struct CRYPTOAPI_HCRYPTPROV_INFO * CRYPTOAPI_FindHprov( HCRYPTPROV hProv )
+{
+	struct CRYPTOAPI_HCRYPTPROV_INFO *curr;
+	TRACE("hProv=%ld\n",hProv);
+	EnterCriticalSection(&CRYPTOAPI_hcryptprovs_critsect);
+	for(curr = CRYPTOAPI_hcryptprovs; curr; curr=curr->next)
+	{
+		if(curr->hProv == hProv)
+			break;
+	}
+	LeaveCriticalSection(&CRYPTOAPI_hcryptprovs_critsect);
+	return curr;
+}
+
+/* CRYPTOAPI_FreeHprov
+ * 
+ * Searches for hProv int he linked list of provider handles and decrements
+ * its reference count.  If the reference count becomes zero, then unlink
+ * it from the list.
+ *
+ * RETURNS: The list item that was found or NULL if none was found.
+ * The caller must check the items refcount and if it is zero should
+ * free the memory (since it has been delinked from the list).
+ */
+struct CRYPTOAPI_HCRYPTPROV_INFO * CRYPTOAPI_FreeHprov( HCRYPTPROV hProv )
+{
+	struct CRYPTOAPI_HCRYPTPROV_INFO *curr;
+	TRACE("hProv=%ld\n",hProv);
+	EnterCriticalSection(&CRYPTOAPI_hcryptprovs_critsect);
+	for(curr = CRYPTOAPI_hcryptprovs; curr; curr=curr->next)
+	{
+		if(curr->hProv == hProv)
+		{
+			curr->refcount--;
+			if(!curr->refcount)
+			{
+				if(curr->prev)
+					curr->prev->next = curr->next;
+				else
+					CRYPTOAPI_hcryptprovs = curr->next;
+				if( curr->next )
+					curr->next->prev = curr->prev;
+				curr->prev = NULL;
+				curr->next = NULL;
+			}
+			break;
+		}
+	}
+	LeaveCriticalSection(&CRYPTOAPI_hcryptprovs_critsect);
+	return curr;
+}
+
+/* CRYPTOAPI_NewHprov
+ *
+ * Inserts hProv into the list with the appropriate CSP information.
+ * The CSP information should have already had its refcount increased.
+ *
+ * RETURNS: The item linked into the list
+ */
+struct CRYPTOAPI_HCRYPTPROV_INFO * CRYPTOAPI_NewHprov( HCRYPTPROV hProv, struct CRYPTOAPI_CSP_INFO *pCspInfo )
+{
+	struct CRYPTOAPI_HCRYPTPROV_INFO *pHcryptprovInfo;
+	TRACE("hProv=%ld, pCspInfo=%p\n",hProv,pCspInfo);
+	if(!(pHcryptprovInfo = HeapAlloc(GetProcessHeap(),0,sizeof(struct CRYPTOAPI_HCRYPTPROV_INFO))))
+	{
+		return NULL;
+	};
+	pHcryptprovInfo->refcount = 1;
+	pHcryptprovInfo->hProv = hProv;
+	pHcryptprovInfo->pCspInfo = pCspInfo;
+
+	EnterCriticalSection(&CRYPTOAPI_hcryptprovs_critsect);
+	pHcryptprovInfo->prev = NULL;
+	pHcryptprovInfo->next = CRYPTOAPI_hcryptprovs;
+	if(pHcryptprovInfo->next)
+		pHcryptprovInfo->next->prev = pHcryptprovInfo;
+	CRYPTOAPI_hcryptprovs = pHcryptprovInfo;
+	LeaveCriticalSection(&CRYPTOAPI_hcryptprovs_critsect);
+	return pHcryptprovInfo;
+}
+
--- /dev/null	Thu Aug 30 16:30:55 2001
+++ dlls/advapi32/hprovlist.h	Mon Dec 17 18:33:03 2001
@@ -0,0 +1,16 @@
+#ifndef __ADVAPI32_HPROVLIST_H__
+#define __ADVAPI32_HPROVLIST_H__
+
+struct CRYPTOAPI_HCRYPTPROV_INFO {
+	struct CRYPTOAPI_HCRYPTPROV_INFO	*prev;
+	struct CRYPTOAPI_HCRYPTPROV_INFO	*next;
+	int					refcount;
+	HCRYPTPROV				hProv;
+	struct CRYPTOAPI_CSP_INFO		*pCspInfo;
+};
+
+struct CRYPTOAPI_HCRYPTPROV_INFO * CRYPTOAPI_NewHprov( HCRYPTPROV hProv, struct CRYPTOAPI_CSP_INFO *pCspInfo );
+struct CRYPTOAPI_HCRYPTPROV_INFO * CRYPTOAPI_FindHprov( HCRYPTPROV hProv );
+struct CRYPTOAPI_HCRYPTPROV_INFO * CRYPTOAPI_FreeHprov( HCRYPTPROV hProv );
+void CRYPTOAPI_DumpHprovList(void);
+#endif /* #ifndef __ADVAPI32_HPROVLIST_H__ */
