Reimplementation of CryptAcquireContextA

Michael Jung mjung at vlsi.informatik.tu-darmstadt.de
Sun Jul 18 18:11:25 CDT 2004


Hello,

The original CryptAcquireContextA had some issues with memory management
in failure conditions, resulting in heap corruption under certain
cirumstances. I've reimplemented this function, checking behaviour against
Windows XP Prof. There is also a unit test included in the patch, which
tests CryptAcquireContext and successfully runs to completion on
both Windows XP and Wine. The patch looks worse than it is, since diff
believes to have found similarities between my new implementation and the
original CryptAcquireContextA.

Greetings,
Michael

Changelog:
	Reimplemented CryptAcquireContextA to prevent heap corruption
	Added unit tests for CryptAcquireContext

--
Michael Jung, MSc                             Be liberal in what you accept,
Integrated Circuits and Systems Lab       and conservative in what you send.
University of Technology, Darmstadt     -- Jonathan Postel, Internet Pioneer
phone: +49(6151)16-6692 / email: mjung at iss.tu-darmstadt.de
-------------- next part --------------
Index: dlls/advapi32/crypt.c
===================================================================
RCS file: /home/wine/wine/dlls/advapi32/crypt.c,v
retrieving revision 1.39
diff -u -r1.39 crypt.c
--- dlls/advapi32/crypt.c	16 Jul 2004 19:19:00 -0000	1.39
+++ dlls/advapi32/crypt.c	18 Jul 2004 22:55:19 -0000
@@ -239,6 +239,45 @@
 #undef CRYPT_GetProvFunc
 #undef CRYPT_GetProvFuncOpt
 
+struct acquire_context_resources {
+	HKEY  hKey;
+	PCHAR pszProvKeyName;
+	PCHAR pszTemp;
+	PCHAR pszImagePath;
+	PBYTE pSignature;
+};
+
+/******************************************************************************
+ *  acquire_context_release_resources  [Internal]
+ *  
+ * Helper function for CryptAcquireContext. Releases the resources used by
+ * CryptAcquireContext, sets last error to error_code and returns TRUE if
+ * error_code == ERROR_SUCCESS, else FALSE.
+ * 
+ * PARAMS
+ *  resources  [I] Pointer to an acquire_context_resources struct, which holds 
+ *                 pointers to resources used by CryptAcquireContext
+ *  error_code [I] Error code, which the "last error" is set to.
+ *
+ * RETURNS
+ *  TRUE,  iff error_code == ERROR_SUCCESS
+ *  FALSE, otherwise
+ */
+inline BOOL acquire_context_release_resources(struct acquire_context_resources *resources, DWORD error_code)
+{
+	if (resources->hKey != (HKEY)INVALID_HANDLE_VALUE)
+		RegCloseKey(resources->hKey);
+	if (resources->pszProvKeyName != NULL)
+		HeapFree(GetProcessHeap(), 0, resources->pszProvKeyName);
+	if (resources->pszTemp != NULL)
+		HeapFree(GetProcessHeap(), 0, resources->pszTemp);
+	if (resources->pszImagePath != NULL)
+		HeapFree(GetProcessHeap(), 0, resources->pszImagePath);
+	if (resources->pSignature != NULL)
+		HeapFree(GetProcessHeap(), 0, resources->pSignature);
+	SetLastError(error_code);
+	return error_code == ERROR_SUCCESS;
+}
 
 /******************************************************************************
  * CryptAcquireContextA (ADVAPI32.@)
@@ -253,199 +292,142 @@
  *
  * RETURNS TRUE on success, FALSE on failure.
  */
-BOOL WINAPI CryptAcquireContextA (HCRYPTPROV *phProv, LPCSTR pszContainer,
-		LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags)
+BOOL WINAPI CryptAcquireContextA(HCRYPTPROV *phProv, LPCSTR pszContainer, 
+        LPCSTR pszProvider, DWORD dwProvType, DWORD dwFlags)
 {
-	PCRYPTPROV pProv = NULL;
-	HKEY key;
-	PSTR imagepath = NULL, keyname = NULL, provname = NULL, temp = NULL;
-	BYTE* signature;
-	DWORD keytype, type, len;
-	ULONG r;
-
-	TRACE("(%p, %s, %s, %ld, %08lx)\n", phProv, pszContainer,
-		pszProvider, dwProvType, dwFlags);
-
-	if (!phProv || !dwProvType)
-	{
-		SetLastError(ERROR_INVALID_PARAMETER);
-		return FALSE;
-	}
-	if (dwProvType > MAXPROVTYPES)
-	{
-		SetLastError(NTE_BAD_PROV_TYPE);
-		return FALSE;
-	}
+	struct acquire_context_resources rc;
+	HKEY hCurrentUser;
+	CHAR szProvTypeKeyName[65];
+	DWORD cbBytes, dwActualProvType, dwValueType;
+	PCRYPTPROV pProv;
+	LONG result;
+
+	rc.hKey = (HKEY)INVALID_HANDLE_VALUE;
+	rc.pszProvKeyName = NULL;
+	rc.pszTemp = NULL;
+	rc.pszImagePath = NULL;
+	rc.pSignature = NULL;
+	
+	if (dwProvType < 1 || dwProvType > 999)
+		return acquire_context_release_resources(&rc, NTE_BAD_PROV_TYPE);
 
-	if (!pszProvider)
+	/* if pszContainer == NULL, or else pszContainer points to empty string. */
+	if (!pszProvider ? 1 : pszProvider[0] == '\0')
 	{
-		/* No CSP name specified so try the user default CSP first
-		 * then try the machine default CSP
-		 */
-		if ( !(keyname = CRYPT_GetTypeKeyName(dwProvType, TRUE)) ) {
-			FIXME("No provider registered for crypto provider type %ld.\n", dwProvType);
-			SetLastError(NTE_PROV_TYPE_NOT_DEF);
-			return FALSE;
-		}
-		if (RegOpenKeyA(HKEY_CURRENT_USER, keyname, &key))
+		rc.hKey = (HKEY)INVALID_HANDLE_VALUE;
+		if (RegOpenCurrentUser(KEY_READ, &hCurrentUser) == ERROR_SUCCESS)
 		{
-			CRYPT_Free(keyname);
-			if ( !(keyname = CRYPT_GetTypeKeyName(dwProvType, FALSE)) ) {
-				FIXME("No type registered for crypto provider type %ld.\n", dwProvType);
-				RegCloseKey(key);
-				SetLastError(NTE_PROV_TYPE_NOT_DEF);
-				goto error;
-			}
-			if (RegOpenKeyA(HKEY_LOCAL_MACHINE, keyname, &key)) {
-				FIXME("Did not find registry entry of crypto provider for %s.\n", debugstr_a(keyname));
-				CRYPT_Free(keyname);
-				RegCloseKey(key);
-				SetLastError(NTE_PROV_TYPE_NOT_DEF);
-				goto error;
-			}
+			sprintf(szProvTypeKeyName, "Software\\Microsoft\\Cryptography\\Provider Type %03d", (int)dwProvType);
+			if (RegOpenKeyExA(hCurrentUser, szProvTypeKeyName, 0, KEY_QUERY_VALUE, &rc.hKey) != ERROR_SUCCESS)
+				rc.hKey = (HKEY)INVALID_HANDLE_VALUE;
+			RegCloseKey(hCurrentUser);
 		}
-		CRYPT_Free(keyname);
-		r = RegQueryValueExA(key, "Name", NULL, &keytype, NULL, &len);
-		if( r != ERROR_SUCCESS || !len || keytype != REG_SZ)
+		if (rc.hKey == (HKEY)INVALID_HANDLE_VALUE)
 		{
-			TRACE("error %ld reading size of 'Name' from registry\n", r );
-			RegCloseKey(key);
-			SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
-			goto error;
-		}
-		if(!(provname = CRYPT_Alloc(len)))
-		{
-			RegCloseKey(key);
-			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-			goto error;
-		}
-		r = RegQueryValueExA(key, "Name", NULL, NULL, provname, &len);
-		if( r != ERROR_SUCCESS )
-		{
-			TRACE("error %ld reading 'Name' from registry\n", r );
-			RegCloseKey(key);
-			SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
-			goto error;
-		}
-		RegCloseKey(key);
-	} else {
-		if ( !(provname = CRYPT_Alloc(strlen(pszProvider) +1)) )
-		{
-			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-			goto error;
+			sprintf(szProvTypeKeyName, "Software\\Microsoft\\Cryptography\\Defaults\\Provider Types\\Type %03d", (int)dwProvType);
+			if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, szProvTypeKeyName, 0, KEY_QUERY_VALUE, &rc.hKey) != ERROR_SUCCESS)
+				rc.hKey = (HKEY)INVALID_HANDLE_VALUE;
 		}
-		strcpy(provname, pszProvider);
-	}
-
-	keyname = CRYPT_GetProvKeyName(provname);
-	r = RegOpenKeyA(HKEY_LOCAL_MACHINE, keyname, &key);
-	CRYPT_Free(keyname);
-	if (r) goto error;
-	len = sizeof(DWORD);
-	r = RegQueryValueExA(key, "Type", NULL, NULL, (BYTE*)&type, &len);
-	if (r != ERROR_SUCCESS || type != dwProvType)
-	{
-		FIXME("Crypto provider has wrong type (%ld vs expected %ld).\n", type, dwProvType);
-		SetLastError(NTE_BAD_PROV_TYPE);
-		goto error;
-	}
+		
+		if (rc.hKey == (HKEY)INVALID_HANDLE_VALUE)
+			return acquire_context_release_resources(&rc, NTE_PROV_TYPE_NOT_DEF);
+		
+		result = RegQueryValueExA(rc.hKey, "Name", NULL, &dwValueType, NULL, &cbBytes);
+		if (result != ERROR_SUCCESS || dwValueType != REG_SZ)
+			return acquire_context_release_resources(&rc, NTE_PROV_TYPE_ENTRY_BAD);
+
+		rc.pszProvKeyName = (PCHAR)HeapAlloc(GetProcessHeap(), 0, cbBytes + 51);
+		if (rc.pszProvKeyName == NULL)
+			return acquire_context_release_resources(&rc, ERROR_NOT_ENOUGH_MEMORY);
+
+		strcpy(rc.pszProvKeyName, "Software\\Microsoft\\Cryptography\\Defaults\\Provider\\");
+		if (RegQueryValueExA(rc.hKey, "Name", NULL, NULL, &rc.pszProvKeyName[50], &cbBytes) != ERROR_SUCCESS) 
+			return acquire_context_release_resources(&rc, NTE_PROV_TYPE_ENTRY_BAD);
 
-	r = RegQueryValueExA(key, "Image Path", NULL, &keytype, NULL, &len);
-	if ( r != ERROR_SUCCESS || keytype != REG_SZ)
-	{
-		TRACE("error %ld reading size of 'Image Path' from registry\n", r );
-		RegCloseKey(key);
-		SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
-		goto error;
-	}
-	if (!(temp = CRYPT_Alloc(len)))
-	{
-		RegCloseKey(key);
-		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-		goto error;
-	}
-	r = RegQueryValueExA(key, "Image Path", NULL, NULL, temp, &len);
-	if( r != ERROR_SUCCESS )
-	{
-		TRACE("error %ld reading 'Image Path' from registry\n", r );
-		RegCloseKey(key);
-		SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
-		goto error;
-	}
-
-	r = RegQueryValueExA(key, "Signature", NULL, &keytype, NULL, &len);
-	if ( r == ERROR_SUCCESS && keytype == REG_BINARY )
-	{
-		if (!(signature = CRYPT_Alloc(len)))
-		{
-			RegCloseKey(key);
-			SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-			goto error;
-		}
-		r = RegQueryValueExA(key, "Signature", NULL, NULL, signature, &len);
-		if ( r != ERROR_SUCCESS )
-		{
-			TRACE("error %ld reading 'Signature'\n", r );
-			RegCloseKey(key);
-			SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
-			goto error;
-		}
+		RegCloseKey(rc.hKey);
 	}
 	else
 	{
-		r = RegQueryValueExA(key, "SigInFile", NULL, &keytype, NULL, &len);
-		if (r != ERROR_SUCCESS)
-		{
-			TRACE("error %ld reading size of 'SigInFile'\n", r );
-			RegCloseKey(key);
-			SetLastError(NTE_PROV_TYPE_ENTRY_BAD);
-			goto error;
-		}
-		else
-		{
-			/* FIXME: The presence of the SigInFile value indicates the
-			 * provider's signature is in its resources, so need to read it.
-			 * But since CRYPT_VerifyImage is stubbed, provide any old thing
-			 * for now.
-			 */
-			if (!(signature = CRYPT_Alloc(1)))
-			{
-				RegCloseKey(key);
-				SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-				goto error;
-			}
-		}
-	}
-	RegCloseKey(key);
-	len = ExpandEnvironmentStringsA(temp, NULL, 0);
-	if ( !(imagepath = CRYPT_Alloc(len)) )
-	{
-		CRYPT_Free(signature);
-		SetLastError(ERROR_NOT_ENOUGH_MEMORY);
-		goto error;
+		rc.pszProvKeyName = (PCHAR)HeapAlloc(GetProcessHeap(), 0, strlen(pszProvider) + 51);
+		if (rc.pszProvKeyName == NULL)
+			return acquire_context_release_resources(&rc, ERROR_NOT_ENOUGH_MEMORY);
+		
+		strcpy(rc.pszProvKeyName, "Software\\Microsoft\\Cryptography\\Defaults\\Provider\\");
+		strcpy(&rc.pszProvKeyName[50], pszProvider);
+	}
+
+	if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, rc.pszProvKeyName, 0, KEY_QUERY_VALUE, &rc.hKey) != ERROR_SUCCESS)
+		return acquire_context_release_resources(&rc, NTE_KEYSET_NOT_DEF);
+
+	cbBytes = sizeof(DWORD);
+	result = RegQueryValueExA(rc.hKey, "Type", NULL, &dwValueType, (LPBYTE)&dwActualProvType, &cbBytes);
+	if (result != ERROR_SUCCESS || dwValueType != REG_DWORD)
+		return acquire_context_release_resources(&rc, NTE_PROV_TYPE_ENTRY_BAD);
+
+	if (dwActualProvType != dwProvType)
+		return acquire_context_release_resources(&rc, NTE_PROV_TYPE_NO_MATCH);
+	
+	result = RegQueryValueExA(rc.hKey, "Image Path", NULL, &dwValueType, NULL, &cbBytes);
+	if (result != ERROR_SUCCESS || dwValueType != REG_SZ)
+		return acquire_context_release_resources(&rc, NTE_PROV_TYPE_ENTRY_BAD);
+
+	rc.pszTemp = HeapAlloc(GetProcessHeap(), 0, cbBytes);
+	if (rc.pszTemp == NULL)
+		return acquire_context_release_resources(&rc, ERROR_NOT_ENOUGH_MEMORY);
+
+	if (RegQueryValueExA(rc.hKey, "Image Path", NULL, NULL, (LPBYTE)rc.pszTemp, &cbBytes) != ERROR_SUCCESS)
+		return acquire_context_release_resources(&rc, NTE_PROV_TYPE_ENTRY_BAD);
+	
+	cbBytes = ExpandEnvironmentStringsA(rc.pszTemp, NULL, 0);
+	rc.pszImagePath = (PCHAR)HeapAlloc(GetProcessHeap(), 0, cbBytes);
+	if (rc.pszImagePath == NULL)
+		return acquire_context_release_resources(&rc, ERROR_NOT_ENOUGH_MEMORY);
+
+	if (ExpandEnvironmentStringsA(rc.pszTemp, rc.pszImagePath, cbBytes) == 0)
+		return acquire_context_release_resources(&rc, ERROR_NOT_ENOUGH_MEMORY);
+	
+	if (phProv == NULL)
+		return acquire_context_release_resources(&rc, ERROR_INVALID_PARAMETER);
+	
+	if (RegQueryValueExA(rc.hKey, "Signature", NULL, &dwValueType, NULL, &cbBytes) == ERROR_SUCCESS)
+	{
+		if (dwValueType != REG_BINARY)
+			return acquire_context_release_resources(&rc, NTE_PROV_TYPE_ENTRY_BAD);
+			
+		rc.pSignature = HeapAlloc(GetProcessHeap(), 0, cbBytes);
+		if (rc.pSignature == NULL) 
+			return acquire_context_release_resources(&rc, ERROR_NOT_ENOUGH_MEMORY);
+		RegQueryValueExA(rc.hKey, "Signature", NULL, NULL, rc.pSignature, &cbBytes);
 	}
-	if (!ExpandEnvironmentStringsA(temp, imagepath, len))
+	else
 	{
-		CRYPT_Free(signature);
-		/* ExpandEnvironmentStrings will call SetLastError */
-		goto error;
+		result = RegQueryValueExA(rc.hKey, "SigInFile", NULL, &dwValueType, NULL, &cbBytes);
+		if (result != ERROR_SUCCESS || dwValueType != REG_DWORD)
+			return acquire_context_release_resources(&rc, NTE_PROV_TYPE_ENTRY_BAD);
+				
+		/* FIXME: The presence of the SigInFile value indicates the
+		 * provider's signature is in its resources, so need to read it.
+		 * But since CRYPT_VerifyImage is stubbed, provide any old thing
+		 * for now.
+		 */
+		rc.pSignature = HeapAlloc(GetProcessHeap(), 0, 1);
+		if (rc.pSignature == NULL)
+			return acquire_context_release_resources(&rc, ERROR_NOT_ENOUGH_MEMORY);
 	}
 
-	if (!CRYPT_VerifyImage(imagepath, signature))
-	{
-		CRYPT_Free(signature);
-		SetLastError(NTE_SIGNATURE_FILE_BAD);
-		goto error;
-	}
-	pProv = CRYPT_LoadProvider(imagepath);
-	CRYPT_Free(temp);
-	CRYPT_Free(signature);
-	if (!pProv) {
-		/* CRYPT_LoadProvider calls SetLastError */
-		goto error;
-	}
+	if (!CRYPT_VerifyImage(rc.pszImagePath, rc.pSignature))
+		return acquire_context_release_resources(&rc, NTE_BAD_SIGNATURE);
+
+	pProv = CRYPT_LoadProvider(rc.pszImagePath);
+	if (!pProv) 
+		return acquire_context_release_resources(&rc, GetLastError());
+
 	pProv->pVTable->dwProvType = dwProvType;
-	pProv->pVTable->pszProvName = provname;
+	pProv->pVTable->pszProvName = CRYPT_Alloc(strlen(&rc.pszProvKeyName[50])+1);
+	if (pProv->pVTable->pszProvName == NULL)
+		return acquire_context_release_resources(&rc, ERROR_NOT_ENOUGH_MEMORY);
+	strcpy(pProv->pVTable->pszProvName, &rc.pszProvKeyName[50]);
+	
 	if (pProv->pFuncs->pCPAcquireContext(&pProv->hPrivate, (CHAR*)pszContainer, dwFlags, pProv->pVTable))
 	{
 		/* MSDN: When this flag is set, the value returned in phProv is undefined,
@@ -455,29 +437,19 @@
 		if (dwFlags & CRYPT_DELETEKEYSET)
 		{
 			FreeLibrary(pProv->hModule);
-			CRYPT_Free(provname);
+			CRYPT_Free(pProv->pVTable->pszProvName);
+			CRYPT_Free(pProv->pVTable);
 			CRYPT_Free(pProv->pFuncs);
 			CRYPT_Free(pProv);
 		} else {
 			*phProv = (HCRYPTPROV)pProv;
 		}
-		return TRUE;
+		return acquire_context_release_resources(&rc, ERROR_SUCCESS);
 	}
-	/* FALLTHROUGH TO ERROR IF FALSE - CSP internal error! */
-error:
-	if (pProv)
-	{
-		FreeLibrary(pProv->hModule);
-		CRYPT_Free(pProv->pVTable);
-		CRYPT_Free(pProv->pFuncs);
-		CRYPT_Free(pProv);
-	}
-	CRYPT_Free(provname);
-	CRYPT_Free(temp);
-	CRYPT_Free(imagepath);
-	return FALSE;
-}
 
+	return acquire_context_release_resources(&rc, GetLastError());
+}
+		
 /******************************************************************************
  * CryptAcquireContextW (ADVAPI32.@)
  *
Index: dlls/advapi32/tests/Makefile.in
===================================================================
RCS file: /home/wine/wine/dlls/advapi32/tests/Makefile.in,v
retrieving revision 1.2
diff -u -r1.2 Makefile.in
--- dlls/advapi32/tests/Makefile.in	8 Dec 2003 21:46:06 -0000	1.2
+++ dlls/advapi32/tests/Makefile.in	18 Jul 2004 22:55:19 -0000
@@ -6,7 +6,8 @@
 IMPORTS   = advapi32 kernel32
 
 CTESTS = \
-	registry.c
+	registry.c \
+	crypt.c
 
 @MAKE_TEST_RULES@
 
--- /dev/null	2004-06-05 20:01:53.000000000 +0200
+++ dlls/advapi32/tests/crypt.c	2004-07-19 00:53:54.000000000 +0200
@@ -0,0 +1,125 @@
+/*
+ * Unit tests for crypt functions
+ *
+ * Copyright (c) 2004 Michael Jung
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
+ */
+
+#include <stdio.h>
+
+#include "wine/test.h"
+#include "windef.h"
+#include "winbase.h"
+#include "wincrypt.h"
+#include "winerror.h"
+
+static const char szRsaBaseProv[] = MS_DEF_PROV_A;
+static const char szNonExistentProv[] = "Wine Non Existent Cryptographic Provider v11.2";
+static const char szKeySet[] = "wine_test_keyset";
+static const char szBadKeySet[] = "wine_test_bad_keyset";
+#define NON_DEF_PROV_TYPE 999
+
+static void init_environment(void)
+{
+	HCRYPTPROV hProv;
+	
+	/* Ensure that container "wine_test_keyset" does exist */
+	if (!CryptAcquireContext(&hProv, szKeySet, szRsaBaseProv, PROV_RSA_FULL, 0))
+	{
+		CryptAcquireContext(&hProv, szKeySet, szRsaBaseProv, PROV_RSA_FULL, CRYPT_NEWKEYSET);
+	}
+	CryptReleaseContext(hProv, 0);
+
+	/* Ensure that container "wine_test_keyset" does exist in default PROV_RSA_FULL type provider */
+	if (!CryptAcquireContext(&hProv, szKeySet, NULL, PROV_RSA_FULL, 0))
+	{
+		CryptAcquireContext(&hProv, szKeySet, NULL, PROV_RSA_FULL, CRYPT_NEWKEYSET);
+	}
+	CryptReleaseContext(hProv, 0);
+
+	/* Ensure that container "wine_test_bad_keyset" does not exist. */
+	if (CryptAcquireContext(&hProv, szBadKeySet, szRsaBaseProv, PROV_RSA_FULL, 0))
+	{
+		CryptReleaseContext(hProv, 0);
+		CryptAcquireContext(&hProv, szBadKeySet, szRsaBaseProv, PROV_RSA_FULL, CRYPT_DELETEKEYSET);
+	}
+}
+
+static void clean_up_environment(void)
+{
+	HCRYPTPROV hProv;
+
+	/* Remove container "wine_test_keyset" */
+	if (CryptAcquireContext(&hProv, szKeySet, szRsaBaseProv, PROV_RSA_FULL, 0))
+	{
+		CryptReleaseContext(hProv, 0);
+		CryptAcquireContext(&hProv, szKeySet, szRsaBaseProv, PROV_RSA_FULL, CRYPT_DELETEKEYSET);
+	}
+
+	/* Remove container "wine_test_keyset" from default PROV_RSA_FULL type provider */
+	if (CryptAcquireContext(&hProv, szKeySet, NULL, PROV_RSA_FULL, 0))
+	{
+		CryptReleaseContext(hProv, 0);
+		CryptAcquireContext(&hProv, szKeySet, NULL, PROV_RSA_FULL, CRYPT_DELETEKEYSET);
+	}
+}
+
+static void test_acquire_context(void)
+{
+	BOOL result;
+	HCRYPTPROV hProv;
+
+	/* Provoke all kinds of error conditions (which are easy to provoke). 
+	 * The order of the error tests seems to match Windows XP's rsaenh.dll CSP,
+	 * but since this is likely to change between CSP versions, we don't check
+	 * this. Please don't change the order of tests. */
+	result = CryptAcquireContext(&hProv, NULL, NULL, 0, 0);
+	ok(!result && GetLastError()==NTE_BAD_PROV_TYPE, "%08x\n", (unsigned int)GetLastError());
+
+	result = CryptAcquireContext(&hProv, NULL, NULL, 1000, 0);
+	ok(!result && GetLastError()==NTE_BAD_PROV_TYPE, "%08x\n", (unsigned int)GetLastError());
+
+	result = CryptAcquireContext(&hProv, NULL, NULL, NON_DEF_PROV_TYPE, 0);
+	ok(!result && GetLastError()==NTE_PROV_TYPE_NOT_DEF, "%08x\n", (unsigned int)GetLastError());
+
+	result = CryptAcquireContext(&hProv, szKeySet, szNonExistentProv, PROV_RSA_FULL, 0);
+	ok(!result && GetLastError()==NTE_KEYSET_NOT_DEF, "%08x\n", (unsigned int)GetLastError());
+
+	result = CryptAcquireContext(&hProv, szKeySet, szRsaBaseProv, NON_DEF_PROV_TYPE, 0);
+	ok(!result && GetLastError()==NTE_PROV_TYPE_NO_MATCH, "%08x\n", (unsigned int)GetLastError());
+
+	result = CryptAcquireContext(NULL, szKeySet, szRsaBaseProv, PROV_RSA_FULL, 0);
+	ok(!result && GetLastError()==ERROR_INVALID_PARAMETER, "%08x\n", (unsigned int)GetLastError());
+	
+	/* Last not least, try to really acquire a context. */
+	result = CryptAcquireContext(&hProv, szKeySet, szRsaBaseProv, PROV_RSA_FULL, 0);
+	ok(result, "%08x\n", (unsigned int)GetLastError());
+
+	CryptReleaseContext(hProv, 0);
+
+	/* Try again, witch an empty ("\0") szProvider parameter */
+	result = CryptAcquireContext(&hProv, szKeySet, "", PROV_RSA_FULL, 0);
+	ok(result, "%08x\n", (unsigned int)GetLastError());
+
+	CryptReleaseContext(hProv, 0);
+}
+
+START_TEST(crypt)
+{
+	init_environment();
+	test_acquire_context();
+	clean_up_environment();
+}


More information about the wine-patches mailing list