4 * Copyright 2006 Juan Lang
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 #define SECURITY_WIN32
30 #include "wine/test.h"
32 static HMODULE secdll, crypt32dll;
34 static ACQUIRE_CREDENTIALS_HANDLE_FN_A pAcquireCredentialsHandleA;
35 static ENUMERATE_SECURITY_PACKAGES_FN_A pEnumerateSecurityPackagesA;
36 static FREE_CONTEXT_BUFFER_FN pFreeContextBuffer;
37 static FREE_CREDENTIALS_HANDLE_FN pFreeCredentialsHandle;
38 static QUERY_CREDENTIALS_ATTRIBUTES_FN_A pQueryCredentialsAttributesA;
39 static INITIALIZE_SECURITY_CONTEXT_FN_A pInitializeSecurityContextA;
40 static QUERY_CONTEXT_ATTRIBUTES_FN_A pQueryContextAttributesA;
41 static DELETE_SECURITY_CONTEXT_FN pDeleteSecurityContext;
42 static DECRYPT_MESSAGE_FN pDecryptMessage;
43 static ENCRYPT_MESSAGE_FN pEncryptMessage;
45 static PCCERT_CONTEXT (WINAPI *pCertCreateCertificateContext)(DWORD,const BYTE*,DWORD);
46 static BOOL (WINAPI *pCertFreeCertificateContext)(PCCERT_CONTEXT);
47 static BOOL (WINAPI *pCertSetCertificateContextProperty)(PCCERT_CONTEXT,DWORD,DWORD,const void*);
48 static PCCERT_CONTEXT (WINAPI *pCertEnumCertificatesInStore)(HCERTSTORE,PCCERT_CONTEXT);
50 static BOOL (WINAPI *pCryptAcquireContextW)(HCRYPTPROV*, LPCWSTR, LPCWSTR, DWORD, DWORD);
51 static BOOL (WINAPI *pCryptDestroyKey)(HCRYPTKEY);
52 static BOOL (WINAPI *pCryptImportKey)(HCRYPTPROV,CONST BYTE*,DWORD,HCRYPTKEY,DWORD,HCRYPTKEY*);
53 static BOOL (WINAPI *pCryptReleaseContext)(HCRYPTPROV,ULONG_PTR);
55 static const BYTE bigCert[] = { 0x30, 0x7a, 0x02, 0x01, 0x01, 0x30, 0x02, 0x06,
56 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13,
57 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x22,
58 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30,
59 0x30, 0x30, 0x30, 0x5a, 0x18, 0x0f, 0x31, 0x36, 0x30, 0x31, 0x30, 0x31, 0x30,
60 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30,
61 0x11, 0x06, 0x03, 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20,
62 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30, 0x07, 0x30, 0x02, 0x06, 0x00, 0x03, 0x01,
63 0x00, 0xa3, 0x16, 0x30, 0x14, 0x30, 0x12, 0x06, 0x03, 0x55, 0x1d, 0x13, 0x01,
64 0x01, 0xff, 0x04, 0x08, 0x30, 0x06, 0x01, 0x01, 0xff, 0x02, 0x01, 0x01 };
65 static WCHAR cspNameW[] = { 'W','i','n','e','C','r','y','p','t','T','e',
67 static BYTE privKey[] = {
68 0x07, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x32, 0x00,
69 0x02, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x79, 0x10, 0x1c, 0xd0, 0x6b, 0x10,
70 0x18, 0x30, 0x94, 0x61, 0xdc, 0x0e, 0xcb, 0x96, 0x4e, 0x21, 0x3f, 0x79, 0xcd,
71 0xa9, 0x17, 0x62, 0xbc, 0xbb, 0x61, 0x4c, 0xe0, 0x75, 0x38, 0x6c, 0xf3, 0xde,
72 0x60, 0x86, 0x03, 0x97, 0x65, 0xeb, 0x1e, 0x6b, 0xdb, 0x53, 0x85, 0xad, 0x68,
73 0x21, 0xf1, 0x5d, 0xe7, 0x1f, 0xe6, 0x53, 0xb4, 0xbb, 0x59, 0x3e, 0x14, 0x27,
74 0xb1, 0x83, 0xa7, 0x3a, 0x54, 0xe2, 0x8f, 0x65, 0x8e, 0x6a, 0x4a, 0xcf, 0x3b,
75 0x1f, 0x65, 0xff, 0xfe, 0xf1, 0x31, 0x3a, 0x37, 0x7a, 0x8b, 0xcb, 0xc6, 0xd4,
76 0x98, 0x50, 0x36, 0x67, 0xe4, 0xa1, 0xe8, 0x7e, 0x8a, 0xc5, 0x23, 0xf2, 0x77,
77 0xf5, 0x37, 0x61, 0x49, 0x72, 0x59, 0xe8, 0x3d, 0xf7, 0x60, 0xb2, 0x77, 0xca,
78 0x78, 0x54, 0x6d, 0x65, 0x9e, 0x03, 0x97, 0x1b, 0x61, 0xbd, 0x0c, 0xd8, 0x06,
79 0x63, 0xe2, 0xc5, 0x48, 0xef, 0xb3, 0xe2, 0x6e, 0x98, 0x7d, 0xbd, 0x4e, 0x72,
80 0x91, 0xdb, 0x31, 0x57, 0xe3, 0x65, 0x3a, 0x49, 0xca, 0xec, 0xd2, 0x02, 0x4e,
81 0x22, 0x7e, 0x72, 0x8e, 0xf9, 0x79, 0x84, 0x82, 0xdf, 0x7b, 0x92, 0x2d, 0xaf,
82 0xc9, 0xe4, 0x33, 0xef, 0x89, 0x5c, 0x66, 0x99, 0xd8, 0x80, 0x81, 0x47, 0x2b,
83 0xb1, 0x66, 0x02, 0x84, 0x59, 0x7b, 0xc3, 0xbe, 0x98, 0x45, 0x4a, 0x3d, 0xdd,
84 0xea, 0x2b, 0xdf, 0x4e, 0xb4, 0x24, 0x6b, 0xec, 0xe7, 0xd9, 0x0c, 0x45, 0xb8,
85 0xbe, 0xca, 0x69, 0x37, 0x92, 0x4c, 0x38, 0x6b, 0x96, 0x6d, 0xcd, 0x86, 0x67,
86 0x5c, 0xea, 0x54, 0x94, 0xa4, 0xca, 0xa4, 0x02, 0xa5, 0x21, 0x4d, 0xae, 0x40,
87 0x8f, 0x9d, 0x51, 0x83, 0xf2, 0x3f, 0x33, 0xc1, 0x72, 0xb4, 0x1d, 0x94, 0x6e,
88 0x7d, 0xe4, 0x27, 0x3f, 0xea, 0xff, 0xe5, 0x9b, 0xa7, 0x5e, 0x55, 0x8e, 0x0d,
89 0x69, 0x1c, 0x7a, 0xff, 0x81, 0x9d, 0x53, 0x52, 0x97, 0x9a, 0x76, 0x79, 0xda,
90 0x93, 0x32, 0x16, 0xec, 0x69, 0x51, 0x1a, 0x4e, 0xc3, 0xf1, 0x72, 0x80, 0x78,
91 0x5e, 0x66, 0x4a, 0x8d, 0x85, 0x2f, 0x3f, 0xb2, 0xa7 };
93 static const BYTE selfSignedCert[] = {
94 0x30, 0x82, 0x01, 0x1f, 0x30, 0x81, 0xce, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
95 0x10, 0xeb, 0x0d, 0x57, 0x2a, 0x9c, 0x09, 0xba, 0xa4, 0x4a, 0xb7, 0x25, 0x49,
96 0xd9, 0x3e, 0xb5, 0x73, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d,
97 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
98 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30,
99 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x36, 0x32, 0x39, 0x30, 0x35, 0x30, 0x30,
100 0x34, 0x36, 0x5a, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x36, 0x32, 0x39, 0x31, 0x31,
101 0x30, 0x30, 0x34, 0x36, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
102 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e,
103 0x67, 0x00, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
104 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
105 0x00, 0xe2, 0x54, 0x3a, 0xa7, 0x83, 0xb1, 0x27, 0x14, 0x3e, 0x59, 0xbb, 0xb4,
106 0x53, 0xe6, 0x1f, 0xe7, 0x5d, 0xf1, 0x21, 0x68, 0xad, 0x85, 0x53, 0xdb, 0x6b,
107 0x1e, 0xeb, 0x65, 0x97, 0x03, 0x86, 0x60, 0xde, 0xf3, 0x6c, 0x38, 0x75, 0xe0,
108 0x4c, 0x61, 0xbb, 0xbc, 0x62, 0x17, 0xa9, 0xcd, 0x79, 0x3f, 0x21, 0x4e, 0x96,
109 0xcb, 0x0e, 0xdc, 0x61, 0x94, 0x30, 0x18, 0x10, 0x6b, 0xd0, 0x1c, 0x10, 0x79,
110 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
111 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x25, 0x90, 0x53, 0x34, 0xd9, 0x56, 0x41,
112 0x5e, 0xdb, 0x7e, 0x01, 0x36, 0xec, 0x27, 0x61, 0x5e, 0xb7, 0x4d, 0x90, 0x66,
113 0xa2, 0xe1, 0x9d, 0x58, 0x76, 0xd4, 0x9c, 0xba, 0x2c, 0x84, 0xc6, 0x83, 0x7a,
114 0x22, 0x0d, 0x03, 0x69, 0x32, 0x1a, 0x6d, 0xcb, 0x0c, 0x15, 0xb3, 0x6b, 0xc7,
115 0x0a, 0x8c, 0xb4, 0x5c, 0x34, 0x78, 0xe0, 0x3c, 0x9c, 0xe9, 0xf3, 0x30, 0x9f,
116 0xa8, 0x76, 0x57, 0x92, 0x36 };
118 static void InitFunctionPtrs(void)
122 crypt32dll = LoadLibraryA("crypt32.dll");
123 secdll = LoadLibraryA("secur32.dll");
125 secdll = LoadLibraryA("security.dll");
126 advapi32dll = GetModuleHandleA("advapi32.dll");
128 #define GET_PROC(h, func) p ## func = (void*)GetProcAddress(h, #func)
132 GET_PROC(secdll, AcquireCredentialsHandleA);
133 GET_PROC(secdll, EnumerateSecurityPackagesA);
134 GET_PROC(secdll, FreeContextBuffer);
135 GET_PROC(secdll, FreeCredentialsHandle);
136 GET_PROC(secdll, QueryCredentialsAttributesA);
137 GET_PROC(secdll, InitializeSecurityContextA);
138 GET_PROC(secdll, QueryContextAttributesA);
139 GET_PROC(secdll, DeleteSecurityContext);
140 GET_PROC(secdll, DecryptMessage);
141 GET_PROC(secdll, EncryptMessage);
144 GET_PROC(advapi32dll, CryptAcquireContextW);
145 GET_PROC(advapi32dll, CryptDestroyKey);
146 GET_PROC(advapi32dll, CryptImportKey);
147 GET_PROC(advapi32dll, CryptReleaseContext);
149 GET_PROC(crypt32dll, CertFreeCertificateContext);
150 GET_PROC(crypt32dll, CertSetCertificateContextProperty);
151 GET_PROC(crypt32dll, CertCreateCertificateContext);
152 GET_PROC(crypt32dll, CertEnumCertificatesInStore);
157 static void test_strength(PCredHandle handle)
159 SecPkgCred_CipherStrengths strength = {-1,-1};
162 st = pQueryCredentialsAttributesA(handle, SECPKG_ATTR_CIPHER_STRENGTHS, &strength);
163 ok(st == SEC_E_OK, "QueryCredentialsAttributesA failed: %u\n", GetLastError());
164 ok(strength.dwMinimumCipherStrength, "dwMinimumCipherStrength not changed\n");
165 ok(strength.dwMaximumCipherStrength, "dwMaximumCipherStrength not changed\n");
166 trace("strength %d - %d\n", strength.dwMinimumCipherStrength, strength.dwMaximumCipherStrength);
169 static void testAcquireSecurityContext(void)
171 BOOL has_schannel = FALSE;
172 SecPkgInfoA *package_info;
177 SCHANNEL_CRED schanCred;
178 PCCERT_CONTEXT certs[2];
180 static CHAR unisp_name_a[] = UNISP_NAME_A;
181 WCHAR ms_def_prov_w[MAX_PATH];
184 CRYPT_KEY_PROV_INFO keyProvInfo;
186 if (!pAcquireCredentialsHandleA || !pCertCreateCertificateContext ||
187 !pEnumerateSecurityPackagesA || !pFreeContextBuffer ||
188 !pFreeCredentialsHandle || !pCryptAcquireContextW)
190 win_skip("Needed functions are not available\n");
194 if (SUCCEEDED(pEnumerateSecurityPackagesA(&i, &package_info)))
198 if (!strcmp(package_info[i].Name, unisp_name_a))
204 pFreeContextBuffer(package_info);
208 skip("Schannel not available\n");
212 lstrcpyW(ms_def_prov_w, MS_DEF_PROV_W);
214 keyProvInfo.pwszContainerName = cspNameW;
215 keyProvInfo.pwszProvName = ms_def_prov_w;
216 keyProvInfo.dwProvType = PROV_RSA_FULL;
217 keyProvInfo.dwFlags = 0;
218 keyProvInfo.cProvParam = 0;
219 keyProvInfo.rgProvParam = NULL;
220 keyProvInfo.dwKeySpec = AT_SIGNATURE;
222 certs[0] = pCertCreateCertificateContext(X509_ASN_ENCODING, bigCert,
224 certs[1] = pCertCreateCertificateContext(X509_ASN_ENCODING, selfSignedCert,
225 sizeof(selfSignedCert));
227 SetLastError(0xdeadbeef);
228 ret = pCryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
230 if (!ret && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
232 /* WinMe would crash on some tests */
233 win_skip("CryptAcquireContextW is not implemented\n");
237 st = pAcquireCredentialsHandleA(NULL, NULL, 0, NULL, NULL, NULL, NULL, NULL,
239 ok(st == SEC_E_SECPKG_NOT_FOUND,
240 "Expected SEC_E_SECPKG_NOT_FOUND, got %08x\n", st);
243 /* Crashes on Win2K */
244 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, 0, NULL, NULL, NULL,
246 ok(st == SEC_E_NO_CREDENTIALS, "Expected SEC_E_NO_CREDENTIALS, got %08x\n", st);
248 /* Crashes on WinNT */
249 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_BOTH, NULL,
250 NULL, NULL, NULL, NULL, NULL);
251 ok(st == SEC_E_NO_CREDENTIALS, "Expected SEC_E_NO_CREDENTIALS, got %08x\n", st);
253 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
254 NULL, NULL, NULL, NULL, NULL, NULL);
255 ok(st == SEC_E_NO_CREDENTIALS, "Expected SEC_E_NO_CREDENTIALS, got %08x\n", st);
258 pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
259 NULL, NULL, NULL, NULL, NULL, NULL);
261 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
262 NULL, NULL, NULL, NULL, &cred, NULL);
263 ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08x\n", st);
265 pFreeCredentialsHandle(&cred);
266 memset(&cred, 0, sizeof(cred));
267 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
268 NULL, NULL, NULL, NULL, &cred, &exp);
269 ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08x\n", st);
270 /* expriy is indeterminate in win2k3 */
271 trace("expiry: %08x%08x\n", exp.HighPart, exp.LowPart);
272 pFreeCredentialsHandle(&cred);
274 /* Bad version in SCHANNEL_CRED */
275 memset(&schanCred, 0, sizeof(schanCred));
276 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
277 NULL, &schanCred, NULL, NULL, NULL, NULL);
278 ok(st == SEC_E_INTERNAL_ERROR ||
279 st == SEC_E_UNKNOWN_CREDENTIALS /* Vista/win2k8 */ ||
280 st == SEC_E_INVALID_TOKEN /* WinNT */, "st = %08x\n", st);
281 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
282 NULL, &schanCred, NULL, NULL, NULL, NULL);
283 ok(st == SEC_E_INTERNAL_ERROR ||
284 st == SEC_E_UNKNOWN_CREDENTIALS /* Vista/win2k8 */ ||
285 st == SEC_E_INVALID_TOKEN /* WinNT */, "st = %08x\n", st);
287 /* No cert in SCHANNEL_CRED succeeds for outbound.. */
288 schanCred.dwVersion = SCHANNEL_CRED_VERSION;
289 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
290 NULL, &schanCred, NULL, NULL, &cred, NULL);
291 ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08x\n", st);
292 pFreeCredentialsHandle(&cred);
293 /* but fails for inbound. */
294 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
295 NULL, &schanCred, NULL, NULL, &cred, NULL);
296 ok(st == SEC_E_NO_CREDENTIALS ||
297 st == SEC_E_OK /* Vista/win2k8 */,
298 "Expected SEC_E_NO_CREDENTIALS or SEC_E_OK, got %08x\n", st);
302 /* Crashes with bad paCred pointer */
303 schanCred.cCreds = 1;
304 pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
305 NULL, &schanCred, NULL, NULL, NULL, NULL);
308 /* Bogus cert in SCHANNEL_CRED. Windows fails with
309 * SEC_E_UNKNOWN_CREDENTIALS, but I'll accept SEC_E_NO_CREDENTIALS too.
311 schanCred.cCreds = 1;
312 schanCred.paCred = &certs[0];
313 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
314 NULL, &schanCred, NULL, NULL, NULL, NULL);
315 ok(st == SEC_E_UNKNOWN_CREDENTIALS ||
316 st == SEC_E_NO_CREDENTIALS ||
317 st == SEC_E_INVALID_TOKEN /* WinNT */, "st = %08x\n", st);
318 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
319 NULL, &schanCred, NULL, NULL, NULL, NULL);
320 ok(st == SEC_E_UNKNOWN_CREDENTIALS ||
321 st == SEC_E_NO_CREDENTIALS ||
322 st == SEC_E_INVALID_TOKEN /* WinNT */, "st = %08x\n", st);
324 /* Good cert, but missing private key. Windows fails with
325 * SEC_E_NO_CREDENTIALS, but I'll accept SEC_E_UNKNOWN_CREDENTIALS too.
327 schanCred.cCreds = 1;
328 schanCred.paCred = &certs[1];
329 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
330 NULL, &schanCred, NULL, NULL, &cred, NULL);
331 ok(st == SEC_E_UNKNOWN_CREDENTIALS || st == SEC_E_NO_CREDENTIALS ||
332 st == SEC_E_INTERNAL_ERROR, /* win2k */
333 "Expected SEC_E_UNKNOWN_CREDENTIALS, SEC_E_NO_CREDENTIALS "
334 "or SEC_E_INTERNAL_ERROR, got %08x\n", st);
335 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
336 NULL, &schanCred, NULL, NULL, NULL, NULL);
337 ok(st == SEC_E_UNKNOWN_CREDENTIALS || st == SEC_E_NO_CREDENTIALS ||
338 st == SEC_E_INTERNAL_ERROR, /* win2k */
339 "Expected SEC_E_UNKNOWN_CREDENTIALS, SEC_E_NO_CREDENTIALS "
340 "or SEC_E_INTERNAL_ERROR, got %08x\n", st);
342 /* Good cert, with CRYPT_KEY_PROV_INFO set before it's had a key loaded. */
343 if (pCertSetCertificateContextProperty)
345 ret = pCertSetCertificateContextProperty(certs[1],
346 CERT_KEY_PROV_INFO_PROP_ID, 0, &keyProvInfo);
347 schanCred.dwVersion = SCH_CRED_V3;
348 ok(ret, "CertSetCertificateContextProperty failed: %08x\n", GetLastError());
349 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
350 NULL, &schanCred, NULL, NULL, &cred, NULL);
351 ok(st == SEC_E_UNKNOWN_CREDENTIALS || st == SEC_E_INTERNAL_ERROR /* WinNT */,
352 "Expected SEC_E_UNKNOWN_CREDENTIALS or SEC_E_INTERNAL_ERROR, got %08x\n", st);
353 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
354 NULL, &schanCred, NULL, NULL, &cred, NULL);
355 ok(st == SEC_E_UNKNOWN_CREDENTIALS || st == SEC_E_INTERNAL_ERROR /* WinNT */,
356 "Expected SEC_E_UNKNOWN_CREDENTIALS or SEC_E_INTERNAL_ERROR, got %08x\n", st);
359 ret = pCryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
361 ok(ret, "CryptAcquireContextW failed: %08x\n", GetLastError());
365 ret = pCryptImportKey(csp, privKey, sizeof(privKey), 0, 0, &key);
366 ok(ret, "CryptImportKey failed: %08x\n", GetLastError());
375 pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
376 NULL, &schanCred, NULL, NULL, NULL, NULL);
378 /* Crashes on WinNT */
379 /* Good cert with private key, bogus version */
380 schanCred.dwVersion = SCH_CRED_V1;
381 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
382 NULL, &schanCred, NULL, NULL, &cred, NULL);
383 ok(st == SEC_E_INTERNAL_ERROR ||
384 st == SEC_E_UNKNOWN_CREDENTIALS /* Vista/win2k8 */,
385 "Expected SEC_E_INTERNAL_ERROR or SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st);
386 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
387 NULL, &schanCred, NULL, NULL, &cred, NULL);
388 ok(st == SEC_E_INTERNAL_ERROR ||
389 st == SEC_E_UNKNOWN_CREDENTIALS /* Vista/win2k8 */,
390 "Expected SEC_E_INTERNAL_ERROR or SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st);
391 schanCred.dwVersion = SCH_CRED_V2;
392 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
393 NULL, &schanCred, NULL, NULL, &cred, NULL);
394 ok(st == SEC_E_INTERNAL_ERROR ||
395 st == SEC_E_UNKNOWN_CREDENTIALS /* Vista/win2k8 */,
396 "Expected SEC_E_INTERNAL_ERROR or SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st);
397 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
398 NULL, &schanCred, NULL, NULL, &cred, NULL);
399 ok(st == SEC_E_INTERNAL_ERROR ||
400 st == SEC_E_UNKNOWN_CREDENTIALS /* Vista/win2k8 */,
401 "Expected SEC_E_INTERNAL_ERROR or SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st);
404 /* Succeeds on V3 or higher */
405 schanCred.dwVersion = SCH_CRED_V3;
406 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
407 NULL, &schanCred, NULL, NULL, &cred, NULL);
408 ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08x\n", st);
409 pFreeCredentialsHandle(&cred);
410 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
411 NULL, &schanCred, NULL, NULL, &cred, NULL);
413 st == SEC_E_UNKNOWN_CREDENTIALS, /* win2k3 */
414 "AcquireCredentialsHandleA failed: %08x\n", st);
415 pFreeCredentialsHandle(&cred);
416 schanCred.dwVersion = SCHANNEL_CRED_VERSION;
417 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
418 NULL, &schanCred, NULL, NULL, &cred, NULL);
419 ok(st == SEC_E_OK, "AcquireCredentialsHandleA failed: %08x\n", st);
420 pFreeCredentialsHandle(&cred);
421 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
422 NULL, &schanCred, NULL, NULL, &cred, NULL);
424 st == SEC_E_UNKNOWN_CREDENTIALS, /* win2k3 */
425 "AcquireCredentialsHandleA failed: %08x\n", st);
426 if (st == SEC_E_OK) test_strength(&cred);
427 pFreeCredentialsHandle(&cred);
429 /* How about more than one cert? */
430 schanCred.cCreds = 2;
431 schanCred.paCred = certs;
432 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
433 NULL, &schanCred, NULL, NULL, &cred, NULL);
434 ok(st == SEC_E_UNKNOWN_CREDENTIALS ||
435 st == SEC_E_NO_CREDENTIALS /* Vista/win2k8 */ ||
436 st == SEC_E_INVALID_TOKEN /* WinNT */, "st = %08x\n", st);
437 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
438 NULL, &schanCred, NULL, NULL, &cred, NULL);
439 ok(st == SEC_E_UNKNOWN_CREDENTIALS ||
440 st == SEC_E_NO_CREDENTIALS ||
441 st == SEC_E_INVALID_TOKEN /* WinNT */, "st = %08x\n", st);
445 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_OUTBOUND,
446 NULL, &schanCred, NULL, NULL, &cred, NULL);
447 ok(st == SEC_E_UNKNOWN_CREDENTIALS ||
448 st == SEC_E_NO_CREDENTIALS ||
449 st == SEC_E_INVALID_TOKEN /* WinNT */, "st = %08x\n", st);
450 st = pAcquireCredentialsHandleA(NULL, unisp_name_a, SECPKG_CRED_INBOUND,
451 NULL, &schanCred, NULL, NULL, &cred, NULL);
452 ok(st == SEC_E_UNKNOWN_CREDENTIALS,
453 "Expected SEC_E_UNKNOWN_CREDENTIALS, got %08x\n", st);
454 /* FIXME: what about two valid certs? */
456 if (pCryptDestroyKey)
457 pCryptDestroyKey(key);
460 if (pCryptReleaseContext)
461 pCryptReleaseContext(csp, 0);
462 pCryptAcquireContextW(&csp, cspNameW, MS_DEF_PROV_W, PROV_RSA_FULL,
465 if (pCertFreeCertificateContext)
467 pCertFreeCertificateContext(certs[0]);
468 pCertFreeCertificateContext(certs[1]);
472 static void test_remote_cert(PCCERT_CONTEXT remote_cert)
474 PCCERT_CONTEXT iter = NULL;
475 BOOL incl_remote = FALSE;
476 unsigned cert_cnt = 0;
478 ok(remote_cert->hCertStore != NULL, "hCertStore == NULL\n");
480 while((iter = pCertEnumCertificatesInStore(remote_cert->hCertStore, iter))) {
481 if(iter == remote_cert)
486 ok(cert_cnt == 2, "cert_cnt = %u\n", cert_cnt);
487 ok(incl_remote, "context does not contain cert itself\n");
490 static const char http_request[] = "HEAD /test.html HTTP/1.1\r\nHost: www.codeweavers.com\r\nConnection: close\r\n\r\n";
492 static void init_cred(SCHANNEL_CRED *cred)
494 cred->dwVersion = SCHANNEL_CRED_VERSION;
497 cred->hRootStore = NULL;
499 cred->aphMappers = NULL;
500 cred->cSupportedAlgs = 0;
501 cred->palgSupportedAlgs = NULL;
502 cred->grbitEnabledProtocols = SP_PROT_SSL3_CLIENT;
503 cred->dwMinimumCipherStrength = 0;
504 cred->dwMaximumCipherStrength = 0;
505 cred->dwSessionLifespan = 0;
509 static void init_buffers(SecBufferDesc *desc, unsigned count, unsigned size)
511 desc->ulVersion = SECBUFFER_VERSION;
512 desc->cBuffers = count;
513 desc->pBuffers = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, count*sizeof(SecBuffer));
515 desc->pBuffers[0].cbBuffer = size;
516 desc->pBuffers[0].pvBuffer = HeapAlloc(GetProcessHeap(), 0, size);
519 static void reset_buffers(SecBufferDesc *desc)
523 for (i = 0; i < desc->cBuffers; ++i)
525 desc->pBuffers[i].BufferType = SECBUFFER_EMPTY;
528 desc->pBuffers[i].cbBuffer = 0;
529 desc->pBuffers[i].pvBuffer = NULL;
534 static void free_buffers(SecBufferDesc *desc)
536 HeapFree(GetProcessHeap(), 0, desc->pBuffers[0].pvBuffer);
537 HeapFree(GetProcessHeap(), 0, desc->pBuffers);
540 static int receive_data(SOCKET sock, SecBuffer *buf)
542 unsigned received = 0;
546 unsigned char *data = buf->pvBuffer;
547 unsigned expected = 0;
550 ret = recv(sock, (char *)data+received, buf->cbBuffer-received, 0);
553 skip("recv failed\n");
558 skip("connection closed\n");
563 while (expected < received)
565 unsigned frame_size = 5 + ((data[3]<<8) | data[4]);
566 expected += frame_size;
570 if (expected == received)
574 buf->cbBuffer = received;
579 static void test_communication(void)
585 struct hostent *host;
586 struct sockaddr_in addr;
588 SECURITY_STATUS status;
592 CredHandle cred_handle;
594 SecPkgContext_StreamSizes sizes;
597 SecBufferDesc buffers[2];
599 unsigned buf_size = 4000;
603 if (!pAcquireCredentialsHandleA || !pFreeCredentialsHandle ||
604 !pInitializeSecurityContextA || !pDeleteSecurityContext ||
605 !pQueryContextAttributesA || !pDecryptMessage || !pEncryptMessage)
607 skip("Required secur32 functions not available\n");
611 /* Create a socket and connect to www.codeweavers.com */
612 ret = WSAStartup(0x0202, &wsa_data);
615 skip("Can't init winsock 2.2\n");
619 host = gethostbyname("www.codeweavers.com");
622 skip("Can't resolve www.codeweavers.com\n");
626 addr.sin_family = host->h_addrtype;
627 addr.sin_addr = *(struct in_addr *)host->h_addr_list[0];
628 addr.sin_port = htons(443);
629 sock = socket(host->h_addrtype, SOCK_STREAM, 0);
630 if (sock == SOCKET_ERROR)
632 skip("Can't create socket\n");
636 ret = connect(sock, (struct sockaddr *)&addr, sizeof(addr));
637 if (ret == SOCKET_ERROR)
639 skip("Can't connect to www.codeweavers.com\n");
643 /* Create client credentials */
645 cred.dwFlags = SCH_CRED_NO_DEFAULT_CREDS|SCH_CRED_MANUAL_CRED_VALIDATION;
647 status = pAcquireCredentialsHandleA(NULL, (SEC_CHAR *)UNISP_NAME, SECPKG_CRED_OUTBOUND, NULL,
648 &cred, NULL, NULL, &cred_handle, NULL);
649 ok(status == SEC_E_OK, "AcquireCredentialsHandleA failed: %08x\n", status);
650 if (status != SEC_E_OK) return;
652 /* Initialize the connection */
653 init_buffers(&buffers[0], 4, buf_size);
654 init_buffers(&buffers[1], 4, buf_size);
656 buffers[0].pBuffers[0].BufferType = SECBUFFER_TOKEN;
657 status = pInitializeSecurityContextA(&cred_handle, NULL, (SEC_CHAR *)"localhost",
658 ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
659 0, 0, NULL, 0, &context, &buffers[0], &attrs, NULL);
660 ok(status == SEC_I_CONTINUE_NEEDED, "Expected SEC_I_CONTINUE_NEEDED, got %08x\n", status);
662 buffers[1].cBuffers = 1;
663 buffers[1].pBuffers[0].BufferType = SECBUFFER_TOKEN;
664 status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
665 ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
666 0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
667 ok(status == SEC_E_INVALID_TOKEN, "Expected SEC_E_INVALID_TOKEN, got %08x\n", status);
669 buffers[0].pBuffers[0].cbBuffer = buf_size;
671 status = pInitializeSecurityContextA(&cred_handle, NULL, (SEC_CHAR *)"localhost",
672 ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
673 0, 0, NULL, 0, &context, &buffers[0], &attrs, NULL);
674 ok(status == SEC_I_CONTINUE_NEEDED, "Expected SEC_I_CONTINUE_NEEDED, got %08x\n", status);
676 buf = &buffers[0].pBuffers[0];
677 send(sock, buf->pvBuffer, buf->cbBuffer, 0);
678 buf->cbBuffer = buf_size;
680 status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
681 ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
682 0, 0, NULL, 0, NULL, &buffers[0], &attrs, NULL);
683 ok(status == SEC_E_INCOMPLETE_MESSAGE, "Got unexpected status %#x.\n", status);
684 ok(buffers[0].pBuffers[0].cbBuffer == buf_size, "Output buffer size changed.\n");
685 ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_TOKEN, "Output buffer type changed.\n");
687 buffers[1].cBuffers = 4;
688 buffers[1].pBuffers[0].cbBuffer = 0;
690 status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
691 ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
692 0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
693 ok(status == SEC_E_INCOMPLETE_MESSAGE, "Got unexpected status %#x.\n", status);
694 ok(buffers[0].pBuffers[0].cbBuffer == buf_size, "Output buffer size changed.\n");
695 ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_TOKEN, "Output buffer type changed.\n");
697 buf = &buffers[1].pBuffers[0];
698 buf->cbBuffer = buf_size;
699 ret = receive_data(sock, buf);
703 buffers[1].pBuffers[0].cbBuffer = 4;
704 status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
705 ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
706 0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
707 ok(status == SEC_E_INCOMPLETE_MESSAGE, "Got unexpected status %#x.\n", status);
708 ok(buffers[0].pBuffers[0].cbBuffer == buf_size, "Output buffer size changed.\n");
709 ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_TOKEN, "Output buffer type changed.\n");
711 buffers[1].pBuffers[0].cbBuffer = 5;
712 status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
713 ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
714 0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
715 ok(status == SEC_E_INCOMPLETE_MESSAGE, "Got unexpected status %#x.\n", status);
716 ok(buffers[0].pBuffers[0].cbBuffer == buf_size, "Output buffer size changed.\n");
717 ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_TOKEN, "Output buffer type changed.\n");
719 buffers[1].pBuffers[0].cbBuffer = ret;
720 status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
721 ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
722 0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
723 buffers[1].pBuffers[0].cbBuffer = buf_size;
724 while (status == SEC_I_CONTINUE_NEEDED)
726 buf = &buffers[0].pBuffers[0];
727 send(sock, buf->pvBuffer, buf->cbBuffer, 0);
728 buf->cbBuffer = buf_size;
730 buf = &buffers[1].pBuffers[0];
731 ret = receive_data(sock, buf);
735 buf->BufferType = SECBUFFER_TOKEN;
737 status = pInitializeSecurityContextA(&cred_handle, &context, (SEC_CHAR *)"localhost",
738 ISC_REQ_CONFIDENTIALITY|ISC_REQ_STREAM,
739 0, 0, &buffers[1], 0, NULL, &buffers[0], &attrs, NULL);
740 buffers[1].pBuffers[0].cbBuffer = buf_size;
743 ok(status == SEC_E_OK || broken(status == SEC_E_INVALID_TOKEN) /* WinNT */,
744 "InitializeSecurityContext failed: %08x\n", status);
745 if(status != SEC_E_OK) {
746 win_skip("Handshake failed\n");
750 status = pQueryContextAttributesA(&context, SECPKG_ATTR_REMOTE_CERT_CONTEXT, (void*)&cert);
751 ok(status == SEC_E_OK, "QueryContextAttributesW(SECPKG_ATTR_REMOTE_CERT_CONTEXT) failed: %08x\n", status);
752 if(status == SEC_E_OK) {
753 test_remote_cert(cert);
754 pCertFreeCertificateContext(cert);
757 pQueryContextAttributesA(&context, SECPKG_ATTR_STREAM_SIZES, &sizes);
759 reset_buffers(&buffers[0]);
761 /* Send a simple request so we get data for testing DecryptMessage */
762 buf = &buffers[0].pBuffers[0];
763 data = buf->pvBuffer;
764 buf->BufferType = SECBUFFER_STREAM_HEADER;
765 buf->cbBuffer = sizes.cbHeader;
767 buf->BufferType = SECBUFFER_DATA;
768 buf->pvBuffer = data + sizes.cbHeader;
769 buf->cbBuffer = sizeof(http_request) - 1;
770 memcpy(buf->pvBuffer, http_request, sizeof(http_request) - 1);
772 buf->BufferType = SECBUFFER_STREAM_TRAILER;
773 buf->pvBuffer = data + sizes.cbHeader + sizeof(http_request) -1;
774 buf->cbBuffer = sizes.cbTrailer;
776 status = pEncryptMessage(&context, 0, &buffers[0], 0);
777 ok(status == SEC_E_OK, "EncryptMessage failed: %08x\n", status);
778 if (status != SEC_E_OK)
781 buf = &buffers[0].pBuffers[0];
782 send(sock, buf->pvBuffer, buffers[0].pBuffers[0].cbBuffer + buffers[0].pBuffers[1].cbBuffer + buffers[0].pBuffers[2].cbBuffer, 0);
784 reset_buffers(&buffers[0]);
785 buf->cbBuffer = buf_size;
786 data_size = receive_data(sock, buf);
788 /* Too few buffers */
789 --buffers[0].cBuffers;
790 status = pDecryptMessage(&context, &buffers[0], 0, NULL);
791 ok(status == SEC_E_INVALID_TOKEN, "Expected SEC_E_INVALID_TOKEN, got %08x\n", status);
794 ++buffers[0].cBuffers;
795 status = pDecryptMessage(&context, &buffers[0], 0, NULL);
796 ok(status == SEC_E_INVALID_TOKEN, "Expected SEC_E_INVALID_TOKEN, got %08x\n", status);
798 /* Two data buffers */
799 buffers[0].pBuffers[0].BufferType = SECBUFFER_DATA;
800 buffers[0].pBuffers[1].BufferType = SECBUFFER_DATA;
801 status = pDecryptMessage(&context, &buffers[0], 0, NULL);
802 ok(status == SEC_E_INVALID_TOKEN, "Expected SEC_E_INVALID_TOKEN, got %08x\n", status);
804 /* Too few empty buffers */
805 buffers[0].pBuffers[1].BufferType = SECBUFFER_EXTRA;
806 status = pDecryptMessage(&context, &buffers[0], 0, NULL);
807 ok(status == SEC_E_INVALID_TOKEN, "Expected SEC_E_INVALID_TOKEN, got %08x\n", status);
809 /* Incomplete data */
810 buffers[0].pBuffers[1].BufferType = SECBUFFER_EMPTY;
811 buffers[0].pBuffers[0].cbBuffer = (data[3]<<8) | data[4];
812 status = pDecryptMessage(&context, &buffers[0], 0, NULL);
813 ok(status == SEC_E_INCOMPLETE_MESSAGE, "Expected SEC_E_INCOMPLETE_MESSAGE, got %08x\n", status);
814 ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_MISSING, "Expected first buffer to be SECBUFFER_MISSING\n");
815 ok(buffers[0].pBuffers[0].cbBuffer == 5, "Expected first buffer to be a five bytes\n");
817 buffers[0].pBuffers[0].cbBuffer = data_size;
818 buffers[0].pBuffers[0].BufferType = SECBUFFER_DATA;
819 buffers[0].pBuffers[1].BufferType = SECBUFFER_EMPTY;
820 status = pDecryptMessage(&context, &buffers[0], 0, NULL);
821 ok(status == SEC_E_OK, "DecryptMessage failed: %08x\n", status);
822 if (status == SEC_E_OK)
824 ok(buffers[0].pBuffers[0].BufferType == SECBUFFER_STREAM_HEADER, "Expected first buffer to be SECBUFFER_STREAM_HEADER\n");
825 ok(buffers[0].pBuffers[1].BufferType == SECBUFFER_DATA, "Expected second buffer to be SECBUFFER_DATA\n");
826 ok(buffers[0].pBuffers[2].BufferType == SECBUFFER_STREAM_TRAILER, "Expected third buffer to be SECBUFFER_STREAM_TRAILER\n");
828 data = buffers[0].pBuffers[1].pvBuffer;
829 data[buffers[0].pBuffers[1].cbBuffer] = 0;
832 pDeleteSecurityContext(&context);
833 pFreeCredentialsHandle(&cred_handle);
835 free_buffers(&buffers[0]);
836 free_buffers(&buffers[1]);
845 testAcquireSecurityContext();
846 test_communication();
851 FreeLibrary(crypt32dll);