2 * wintrust softpub functions tests
4 * Copyright 2007 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
32 #include "wine/test.h"
34 /* Just in case we're being built with borked headers, redefine function
35 * pointers to have the correct calling convention.
37 typedef void *(WINAPI *SAFE_MEM_ALLOC)(DWORD);
38 typedef void (WINAPI *SAFE_MEM_FREE)(void *);
39 typedef BOOL (WINAPI *SAFE_ADD_STORE)(CRYPT_PROVIDER_DATA *,
41 typedef BOOL (WINAPI *SAFE_ADD_SGNR)(CRYPT_PROVIDER_DATA *,
42 BOOL, DWORD, struct _CRYPT_PROVIDER_SGNR *);
43 typedef BOOL (WINAPI *SAFE_ADD_CERT)(CRYPT_PROVIDER_DATA *,
44 DWORD, BOOL, DWORD, PCCERT_CONTEXT);
45 typedef BOOL (WINAPI *SAFE_ADD_PRIVDATA)(CRYPT_PROVIDER_DATA *,
46 CRYPT_PROVIDER_PRIVDATA *);
47 typedef HRESULT (WINAPI *SAFE_PROVIDER_INIT_CALL)(CRYPT_PROVIDER_DATA *);
48 typedef HRESULT (WINAPI *SAFE_PROVIDER_OBJTRUST_CALL)(CRYPT_PROVIDER_DATA *);
49 typedef HRESULT (WINAPI *SAFE_PROVIDER_SIGTRUST_CALL)(CRYPT_PROVIDER_DATA *);
50 typedef HRESULT (WINAPI *SAFE_PROVIDER_CERTTRUST_CALL)(CRYPT_PROVIDER_DATA *);
51 typedef HRESULT (WINAPI *SAFE_PROVIDER_FINALPOLICY_CALL)(CRYPT_PROVIDER_DATA *);
52 typedef HRESULT (WINAPI *SAFE_PROVIDER_TESTFINALPOLICY_CALL)(
53 CRYPT_PROVIDER_DATA *);
54 typedef HRESULT (WINAPI *SAFE_PROVIDER_CLEANUP_CALL)(CRYPT_PROVIDER_DATA *);
55 typedef BOOL (WINAPI *SAFE_PROVIDER_CERTCHKPOLICY_CALL)(
56 CRYPT_PROVIDER_DATA *, DWORD, BOOL, DWORD);
58 typedef struct _SAFE_PROVIDER_FUNCTIONS
61 SAFE_MEM_ALLOC pfnAlloc;
62 SAFE_MEM_FREE pfnFree;
63 SAFE_ADD_STORE pfnAddStore2Chain;
64 SAFE_ADD_SGNR pfnAddSgnr2Chain;
65 SAFE_ADD_CERT pfnAddCert2Chain;
66 SAFE_ADD_PRIVDATA pfnAddPrivData2Chain;
67 SAFE_PROVIDER_INIT_CALL pfnInitialize;
68 SAFE_PROVIDER_OBJTRUST_CALL pfnObjectTrust;
69 SAFE_PROVIDER_SIGTRUST_CALL pfnSignatureTrust;
70 SAFE_PROVIDER_CERTTRUST_CALL pfnCertificateTrust;
71 SAFE_PROVIDER_FINALPOLICY_CALL pfnFinalPolicy;
72 SAFE_PROVIDER_CERTCHKPOLICY_CALL pfnCertCheckPolicy;
73 SAFE_PROVIDER_TESTFINALPOLICY_CALL pfnTestFinalPolicy;
74 struct _CRYPT_PROVUI_FUNCS *psUIpfns;
75 SAFE_PROVIDER_CLEANUP_CALL pfnCleanupPolicy;
76 } SAFE_PROVIDER_FUNCTIONS;
78 static const BYTE v1CertWithPubKey[] = {
79 0x30,0x81,0x95,0x02,0x01,0x01,0x30,0x02,0x06,0x00,0x30,0x15,0x31,0x13,0x30,
80 0x11,0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,
81 0x6e,0x67,0x00,0x30,0x22,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,0x30,0x31,
82 0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x18,0x0f,0x31,0x36,0x30,0x31,0x30,0x31,
83 0x30,0x31,0x30,0x30,0x30,0x30,0x30,0x30,0x5a,0x30,0x15,0x31,0x13,0x30,0x11,
84 0x06,0x03,0x55,0x04,0x03,0x13,0x0a,0x4a,0x75,0x61,0x6e,0x20,0x4c,0x61,0x6e,
85 0x67,0x00,0x30,0x22,0x30,0x0d,0x06,0x09,0x2a,0x86,0x48,0x86,0xf7,0x0d,0x01,
86 0x01,0x01,0x05,0x00,0x03,0x11,0x00,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,
87 0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,0xa3,0x16,0x30,0x14,0x30,0x12,0x06,
88 0x03,0x55,0x1d,0x13,0x01,0x01,0xff,0x04,0x08,0x30,0x06,0x01,0x01,0xff,0x02,
91 static void test_utils(SAFE_PROVIDER_FUNCTIONS *funcs)
93 CRYPT_PROVIDER_DATA data = { 0 };
95 CRYPT_PROVIDER_SGNR sgnr = { 0 };
99 ret = funcs->pfnAddStore2Chain(NULL, NULL);
100 ret = funcs->pfnAddStore2Chain(&data, NULL);
102 store = CertOpenStore(CERT_STORE_PROV_MEMORY, X509_ASN_ENCODING, 0,
103 CERT_STORE_CREATE_NEW_FLAG, NULL);
106 ret = funcs->pfnAddStore2Chain(&data, store);
107 ok(ret, "pfnAddStore2Chain failed: %08x\n", GetLastError());
108 ok(data.chStores == 1, "Expected 1 store, got %d\n", data.chStores);
109 ok(data.pahStores != NULL, "Expected pahStores to be allocated\n");
112 ok(data.pahStores[0] == store, "Unexpected store\n");
113 CertCloseStore(data.pahStores[0], 0);
114 funcs->pfnFree(data.pahStores);
115 data.pahStores = NULL;
117 CertCloseStore(store, 0);
122 skip("CertOpenStore failed: %08x\n", GetLastError());
125 ret = funcs->pfnAddSgnr2Chain(NULL, FALSE, 0, NULL);
126 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, NULL);
128 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
129 ok(ret, "pfnAddSgnr2Chain failed: %08x\n", GetLastError());
130 ok(data.csSigners == 1, "Expected 1 signer, got %d\n", data.csSigners);
131 ok(data.pasSigners != NULL, "Expected pasSigners to be allocated\n");
136 ok(!memcmp(&data.pasSigners[0], &sgnr, sizeof(sgnr)),
137 "Unexpected data in signer\n");
138 /* Adds into the location specified by the index */
139 sgnr.cbStruct = sizeof(CRYPT_PROVIDER_SGNR);
140 sgnr.sftVerifyAsOf.dwLowDateTime = 0xdeadbeef;
141 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 1, &sgnr);
142 ok(ret, "pfnAddSgnr2Chain failed: %08x\n", GetLastError());
143 ok(data.csSigners == 2, "Expected 2 signers, got %d\n", data.csSigners);
144 ok(!memcmp(&data.pasSigners[1], &sgnr, sizeof(sgnr)),
145 "Unexpected data in signer\n");
146 /* This also adds, but the data aren't copied */
147 sgnr.cbStruct = sizeof(DWORD);
148 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
149 ok(ret, "pfnAddSgnr2Chain failed: %08x\n", GetLastError());
150 ok(data.csSigners == 3, "Expected 3 signers, got %d\n", data.csSigners);
151 ok(data.pasSigners[0].cbStruct == 0, "Unexpected data size %d\n",
152 data.pasSigners[0].cbStruct);
153 ok(data.pasSigners[0].sftVerifyAsOf.dwLowDateTime == 0,
154 "Unexpected verify time %d\n",
155 data.pasSigners[0].sftVerifyAsOf.dwLowDateTime);
156 /* But too large a thing isn't added */
157 sgnr.cbStruct = sizeof(sgnr) + sizeof(DWORD);
158 SetLastError(0xdeadbeef);
159 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
160 ok(!ret && GetLastError() == ERROR_INVALID_PARAMETER,
161 "Expected ERROR_INVALID_PARAMETER, got %d\n", GetLastError());
164 ret = funcs->pfnAddCert2Chain(NULL, 0, FALSE, 0, NULL);
165 ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, NULL);
167 cert = CertCreateCertificateContext(X509_ASN_ENCODING, v1CertWithPubKey,
168 sizeof(v1CertWithPubKey));
171 /* Notes on behavior that are hard to test:
172 * 1. If pasSigners is invalid, pfnAddCert2Chain crashes
173 * 2. An invalid signer index isn't checked.
175 ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, cert);
176 ok(ret, "pfnAddCert2Chain failed: %08x\n", GetLastError());
177 ok(data.pasSigners[0].csCertChain == 1, "Expected 1 cert, got %d\n",
178 data.pasSigners[0].csCertChain);
179 ok(data.pasSigners[0].pasCertChain != NULL,
180 "Expected pasCertChain to be allocated\n");
181 if (data.pasSigners[0].pasCertChain)
182 ok(data.pasSigners[0].pasCertChain[0].pCert == cert,
183 "Unexpected cert\n");
184 CertFreeCertificateContext(cert);
187 skip("CertCreateCertificateContext failed: %08x\n", GetLastError());
191 static void testInitialize(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
194 CRYPT_PROVIDER_DATA data = { 0 };
195 WINTRUST_DATA wintrust_data = { 0 };
197 if (!funcs->pfnInitialize)
199 skip("missing pfnInitialize\n");
204 ret = funcs->pfnInitialize(NULL);
206 memset(&data, 0, sizeof(data));
207 ret = funcs->pfnInitialize(&data);
208 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
209 data.padwTrustStepErrors =
210 funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
211 /* Without wintrust data set, crashes when padwTrustStepErrors is set */
212 data.pWintrustData = &wintrust_data;
213 if (data.padwTrustStepErrors)
215 /* Apparently, cdwTrustStepErrors does not need to be set. */
216 ret = funcs->pfnInitialize(&data);
217 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
218 data.cdwTrustStepErrors = 1;
219 ret = funcs->pfnInitialize(&data);
220 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
221 memset(data.padwTrustStepErrors, 0xba,
222 TRUSTERROR_MAX_STEPS * sizeof(DWORD));
223 ret = funcs->pfnInitialize(&data);
224 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
225 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_WVTINIT] = 0;
226 ret = funcs->pfnInitialize(&data);
227 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
228 funcs->pfnFree(data.padwTrustStepErrors);
232 static void testObjTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
235 CRYPT_PROVIDER_DATA data = { 0 };
236 WINTRUST_DATA wintrust_data = { 0 };
237 WINTRUST_CERT_INFO certInfo = { sizeof(WINTRUST_CERT_INFO), 0 };
238 WINTRUST_FILE_INFO fileInfo = { sizeof(WINTRUST_FILE_INFO), 0 };
240 if (!funcs->pfnObjectTrust)
242 skip("missing pfnObjectTrust\n");
247 ret = funcs->pfnObjectTrust(NULL);
249 data.pWintrustData = &wintrust_data;
250 data.padwTrustStepErrors =
251 funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
252 if (data.padwTrustStepErrors)
254 static const CHAR notepad[] = "\\notepad.exe";
255 CHAR notepadPath[MAX_PATH];
256 WCHAR notepadPathW[MAX_PATH];
257 PROVDATA_SIP provDataSIP = { 0 };
258 static const GUID unknown = { 0xC689AAB8, 0x8E78, 0x11D0, { 0x8C,0x47,
259 0x00,0xC0,0x4F,0xC2,0x95,0xEE } };
261 ret = funcs->pfnObjectTrust(&data);
262 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
263 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
264 ERROR_INVALID_PARAMETER,
265 "Expected ERROR_INVALID_PARAMETER, got %08x\n",
266 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
267 U(wintrust_data).pCert = &certInfo;
268 wintrust_data.dwUnionChoice = WTD_CHOICE_CERT;
269 ret = funcs->pfnObjectTrust(&data);
270 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
271 certInfo.psCertContext = (PCERT_CONTEXT)CertCreateCertificateContext(
272 X509_ASN_ENCODING, v1CertWithPubKey, sizeof(v1CertWithPubKey));
273 ret = funcs->pfnObjectTrust(&data);
274 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
275 CertFreeCertificateContext(certInfo.psCertContext);
276 certInfo.psCertContext = NULL;
277 wintrust_data.dwUnionChoice = WTD_CHOICE_FILE;
278 U(wintrust_data).pFile = NULL;
279 ret = funcs->pfnObjectTrust(&data);
280 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
281 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
282 ERROR_INVALID_PARAMETER,
283 "Expected ERROR_INVALID_PARAMETER, got %08x\n",
284 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
285 U(wintrust_data).pFile = &fileInfo;
287 ret = funcs->pfnObjectTrust(&data);
289 /* Workaround missing W-functions for win9x */
290 GetWindowsDirectoryA(notepadPath, MAX_PATH);
291 lstrcatA(notepadPath, notepad);
292 MultiByteToWideChar(0, 0, notepadPath, -1, notepadPathW, MAX_PATH);
293 fileInfo.pcwszFilePath = notepadPathW;
294 /* pfnObjectTrust now crashes unless both pPDSip and psPfns are set */
295 U(data).pPDSip = &provDataSIP;
296 data.psPfns = (CRYPT_PROVIDER_FUNCTIONS *)funcs;
297 ret = funcs->pfnObjectTrust(&data);
298 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
299 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV] ==
300 TRUST_E_NOSIGNATURE, "Expected TRUST_E_NOSIGNATURE, got %08x\n",
301 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_OBJPROV]);
302 ok(!memcmp(&provDataSIP.gSubject, &unknown, sizeof(unknown)),
303 "Unexpected subject GUID\n");
304 ok(provDataSIP.pSip != NULL, "Expected a SIP\n");
305 ok(provDataSIP.psSipSubjectInfo != NULL, "Expected a subject info\n");
306 funcs->pfnFree(data.padwTrustStepErrors);
310 static const BYTE selfSignedCert[] = {
311 0x30, 0x82, 0x01, 0x1f, 0x30, 0x81, 0xce, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02,
312 0x10, 0xeb, 0x0d, 0x57, 0x2a, 0x9c, 0x09, 0xba, 0xa4, 0x4a, 0xb7, 0x25, 0x49,
313 0xd9, 0x3e, 0xb5, 0x73, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1d,
314 0x05, 0x00, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03, 0x55, 0x04, 0x03,
315 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e, 0x67, 0x00, 0x30,
316 0x1e, 0x17, 0x0d, 0x30, 0x36, 0x30, 0x36, 0x32, 0x39, 0x30, 0x35, 0x30, 0x30,
317 0x34, 0x36, 0x5a, 0x17, 0x0d, 0x30, 0x37, 0x30, 0x36, 0x32, 0x39, 0x31, 0x31,
318 0x30, 0x30, 0x34, 0x36, 0x5a, 0x30, 0x15, 0x31, 0x13, 0x30, 0x11, 0x06, 0x03,
319 0x55, 0x04, 0x03, 0x13, 0x0a, 0x4a, 0x75, 0x61, 0x6e, 0x20, 0x4c, 0x61, 0x6e,
320 0x67, 0x00, 0x30, 0x5c, 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7,
321 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00, 0x03, 0x4b, 0x00, 0x30, 0x48, 0x02, 0x41,
322 0x00, 0xe2, 0x54, 0x3a, 0xa7, 0x83, 0xb1, 0x27, 0x14, 0x3e, 0x59, 0xbb, 0xb4,
323 0x53, 0xe6, 0x1f, 0xe7, 0x5d, 0xf1, 0x21, 0x68, 0xad, 0x85, 0x53, 0xdb, 0x6b,
324 0x1e, 0xeb, 0x65, 0x97, 0x03, 0x86, 0x60, 0xde, 0xf3, 0x6c, 0x38, 0x75, 0xe0,
325 0x4c, 0x61, 0xbb, 0xbc, 0x62, 0x17, 0xa9, 0xcd, 0x79, 0x3f, 0x21, 0x4e, 0x96,
326 0xcb, 0x0e, 0xdc, 0x61, 0x94, 0x30, 0x18, 0x10, 0x6b, 0xd0, 0x1c, 0x10, 0x79,
327 0x02, 0x03, 0x01, 0x00, 0x01, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02,
328 0x1d, 0x05, 0x00, 0x03, 0x41, 0x00, 0x25, 0x90, 0x53, 0x34, 0xd9, 0x56, 0x41,
329 0x5e, 0xdb, 0x7e, 0x01, 0x36, 0xec, 0x27, 0x61, 0x5e, 0xb7, 0x4d, 0x90, 0x66,
330 0xa2, 0xe1, 0x9d, 0x58, 0x76, 0xd4, 0x9c, 0xba, 0x2c, 0x84, 0xc6, 0x83, 0x7a,
331 0x22, 0x0d, 0x03, 0x69, 0x32, 0x1a, 0x6d, 0xcb, 0x0c, 0x15, 0xb3, 0x6b, 0xc7,
332 0x0a, 0x8c, 0xb4, 0x5c, 0x34, 0x78, 0xe0, 0x3c, 0x9c, 0xe9, 0xf3, 0x30, 0x9f,
333 0xa8, 0x76, 0x57, 0x92, 0x36 };
335 static void testCertTrust(SAFE_PROVIDER_FUNCTIONS *funcs, GUID *actionID)
337 CRYPT_PROVIDER_DATA data = { 0 };
338 CRYPT_PROVIDER_SGNR sgnr = { sizeof(sgnr), { 0 } };
341 data.padwTrustStepErrors =
342 funcs->pfnAlloc(TRUSTERROR_MAX_STEPS * sizeof(DWORD));
343 if (!data.padwTrustStepErrors)
345 skip("pfnAlloc failed\n");
348 ret = funcs->pfnCertificateTrust(&data);
349 ok(ret == S_FALSE, "Expected S_FALSE, got %08x\n", ret);
350 ok(data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV] ==
351 TRUST_E_NOSIGNATURE, "Expected TRUST_E_NOSIGNATURE, got %08x\n",
352 data.padwTrustStepErrors[TRUSTERROR_STEP_FINAL_CERTPROV]);
353 ret = funcs->pfnAddSgnr2Chain(&data, FALSE, 0, &sgnr);
358 /* An empty signer "succeeds," even though there's no cert */
359 ret = funcs->pfnCertificateTrust(&data);
360 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
361 cert = CertCreateCertificateContext(X509_ASN_ENCODING, selfSignedCert,
362 sizeof(selfSignedCert));
365 WINTRUST_DATA wintrust_data = { 0 };
367 ret = funcs->pfnAddCert2Chain(&data, 0, FALSE, 0, cert);
368 /* If pWintrustData isn't set, crashes attempting to access
369 * pWintrustData->fdwRevocationChecks
371 data.pWintrustData = &wintrust_data;
372 /* If psPfns isn't set, crashes attempting to access
373 * psPfns->pfnCertCheckPolicy
375 data.psPfns = (CRYPT_PROVIDER_FUNCTIONS *)funcs;
376 ret = funcs->pfnCertificateTrust(&data);
377 ok(ret == S_OK, "Expected S_OK, got %08x\n", ret);
378 ok(data.csSigners == 1, "Unexpected number of signers %d\n",
380 ok(data.pasSigners[0].pChainContext != NULL,
381 "Expected a certificate chain\n");
382 ok(data.pasSigners[0].csCertChain == 1,
383 "Unexpected number of chain elements %d\n",
384 data.pasSigners[0].csCertChain);
385 /* pasSigners and pasSigners[0].pasCertChain are guaranteed to be
386 * initialized, see tests for pfnAddSgnr2Chain and pfnAddCert2Chain
388 ok(!data.pasSigners[0].pasCertChain[0].fTrustedRoot,
389 "Didn't expect cert to be trusted\n");
390 ok(data.pasSigners[0].pasCertChain[0].fSelfSigned,
391 "Expected cert to be self-signed\n");
392 ok(data.pasSigners[0].pasCertChain[0].dwConfidence ==
393 (CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST),
394 "Expected CERT_CONFIDENCE_SIG | CERT_CONFIDENCE_TIMENEST, got %08x\n",
395 data.pasSigners[0].pasCertChain[0].dwConfidence);
396 CertFreeCertificateContext(cert);
403 static GUID generic_verify_v2 = WINTRUST_ACTION_GENERIC_VERIFY_V2;
404 SAFE_PROVIDER_FUNCTIONS funcs = { sizeof(SAFE_PROVIDER_FUNCTIONS), 0 };
407 ret = WintrustLoadFunctionPointers(&generic_verify_v2,
408 (CRYPT_PROVIDER_FUNCTIONS *)&funcs);
410 skip("WintrustLoadFunctionPointers failed\n");
414 testInitialize(&funcs, &generic_verify_v2);
415 testObjTrust(&funcs, &generic_verify_v2);
416 testCertTrust(&funcs, &generic_verify_v2);