crypt32: Use the HRESULT synonyms for converted Win32 error codes.
[wine] / dlls / crypt32 / tests / oid.c
1 /*
2  * Unit test suite for crypt32.dll's OID support functions.
3  *
4  * Copyright 2005 Juan Lang
5  *
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.
10  *
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.
15  *
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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  */
20 #include <stdio.h>
21 #include <stdarg.h>
22 #include <windef.h>
23 #include <winbase.h>
24 #include <winerror.h>
25 #include <wincrypt.h>
26
27 #include "wine/test.h"
28
29 struct OIDToAlgID
30 {
31     LPCSTR oid;
32     DWORD algID;
33 };
34
35 static const struct OIDToAlgID oidToAlgID[] = {
36  { szOID_RSA_RSA, CALG_RSA_KEYX },
37  { szOID_RSA_MD2RSA, CALG_MD2 },
38  { szOID_RSA_MD4RSA, CALG_MD4 },
39  { szOID_RSA_MD5RSA, CALG_MD5 },
40  { szOID_RSA_SHA1RSA, CALG_SHA },
41  { szOID_RSA_DH, CALG_DH_SF },
42  { szOID_RSA_SMIMEalgESDH, CALG_DH_EPHEM },
43  { szOID_RSA_SMIMEalgCMS3DESwrap, CALG_3DES },
44  { szOID_RSA_SMIMEalgCMSRC2wrap, CALG_RC2 },
45  { szOID_RSA_MD2, CALG_MD2 },
46  { szOID_RSA_MD4, CALG_MD4 },
47  { szOID_RSA_MD5, CALG_MD5 },
48  { szOID_RSA_RC2CBC, CALG_RC2 },
49  { szOID_RSA_RC4, CALG_RC4 },
50  { szOID_RSA_DES_EDE3_CBC, CALG_3DES },
51  { szOID_ANSI_X942_DH, CALG_DH_SF },
52  { szOID_X957_DSA, CALG_DSS_SIGN },
53  { szOID_X957_SHA1DSA, CALG_SHA },
54  { szOID_OIWSEC_md4RSA, CALG_MD4 },
55  { szOID_OIWSEC_md5RSA, CALG_MD5 },
56  { szOID_OIWSEC_md4RSA2, CALG_MD4 },
57  { szOID_OIWSEC_desCBC, CALG_DES },
58  { szOID_OIWSEC_dsa, CALG_DSS_SIGN },
59  { szOID_OIWSEC_shaDSA, CALG_SHA },
60  { szOID_OIWSEC_shaRSA, CALG_SHA },
61  { szOID_OIWSEC_sha, CALG_SHA },
62  { szOID_OIWSEC_rsaXchg, CALG_RSA_KEYX },
63  { szOID_OIWSEC_sha1, CALG_SHA },
64  { szOID_OIWSEC_dsaSHA1, CALG_SHA },
65  { szOID_OIWSEC_sha1RSASign, CALG_SHA },
66  { szOID_OIWDIR_md2RSA, CALG_MD2 },
67  { szOID_INFOSEC_mosaicUpdatedSig, CALG_SHA },
68  { szOID_INFOSEC_mosaicKMandUpdSig, CALG_DSS_SIGN },
69 };
70
71 static const struct OIDToAlgID algIDToOID[] = {
72  { szOID_RSA_RSA, CALG_RSA_KEYX },
73  { szOID_RSA_SMIMEalgESDH, CALG_DH_EPHEM },
74  { szOID_RSA_MD2, CALG_MD2 },
75  { szOID_RSA_MD4, CALG_MD4 },
76  { szOID_RSA_MD5, CALG_MD5 },
77  { szOID_RSA_RC2CBC, CALG_RC2 },
78  { szOID_RSA_RC4, CALG_RC4 },
79  { szOID_RSA_DES_EDE3_CBC, CALG_3DES },
80  { szOID_ANSI_X942_DH, CALG_DH_SF },
81  { szOID_X957_DSA, CALG_DSS_SIGN },
82  { szOID_OIWSEC_desCBC, CALG_DES },
83  { szOID_OIWSEC_sha1, CALG_SHA },
84 };
85
86 static void testOIDToAlgID(void)
87 {
88     int i;
89     DWORD alg;
90
91     /* Test with a bogus one */
92     SetLastError(0xdeadbeef);
93     alg = CertOIDToAlgId("1.2.3");
94     ok(!alg && (GetLastError() == 0xdeadbeef ||
95      GetLastError() == ERROR_RESOURCE_NAME_NOT_FOUND),
96      "Expected ERROR_RESOURCE_NAME_NOT_FOUND or no error set, got %08lx\n",
97      GetLastError());
98
99     for (i = 0; i < sizeof(oidToAlgID) / sizeof(oidToAlgID[0]); i++)
100     {
101         alg = CertOIDToAlgId(oidToAlgID[i].oid);
102         /* Not all Windows installations support all these, so make sure it's
103          * at least not the wrong one.
104          */
105         ok(alg == 0 || alg == oidToAlgID[i].algID,
106          "Expected %ld, got %ld\n", oidToAlgID[i].algID, alg);
107     }
108 }
109
110 static void testAlgIDToOID(void)
111 {
112     int i;
113     LPCSTR oid;
114
115     /* Test with a bogus one */
116     SetLastError(0xdeadbeef);
117     oid = CertAlgIdToOID(ALG_CLASS_SIGNATURE | ALG_TYPE_ANY | 80);
118     ok(!oid && GetLastError() == 0xdeadbeef,
119      "Didn't expect last error (%08lx) to be set\n", GetLastError());
120     for (i = 0; i < sizeof(algIDToOID) / sizeof(algIDToOID[0]); i++)
121     {
122         oid = CertAlgIdToOID(algIDToOID[i].algID);
123         /* Allow failure, not every version of Windows supports every algo */
124         if (oid)
125             ok(!strcmp(oid, algIDToOID[i].oid), 
126              "Expected %s, got %s\n", algIDToOID[i].oid, oid);
127     }
128 }
129
130 static void test_oidFunctionSet(void)
131 {
132     HCRYPTOIDFUNCSET set1, set2;
133     BOOL ret;
134     LPWSTR buf = NULL;
135     DWORD size;
136
137     /* This crashes
138     set = CryptInitOIDFunctionSet(NULL, 0);
139      */
140
141     /* The name doesn't mean much */
142     set1 = CryptInitOIDFunctionSet("funky", 0);
143     ok(set1 != 0, "CryptInitOIDFunctionSet failed: %08lx\n", GetLastError());
144     if (set1)
145     {
146         /* These crash
147         ret = CryptGetDefaultOIDDllList(NULL, 0, NULL, NULL);
148         ret = CryptGetDefaultOIDDllList(NULL, 0, NULL, &size);
149          */
150         size = 0;
151         ret = CryptGetDefaultOIDDllList(set1, 0, NULL, &size);
152         ok(ret, "CryptGetDefaultOIDDllList failed: %08lx\n", GetLastError());
153         if (ret)
154         {
155             buf = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR));
156             if (buf)
157             {
158                 ret = CryptGetDefaultOIDDllList(set1, 0, buf, &size);
159                 ok(ret, "CryptGetDefaultOIDDllList failed: %08lx\n",
160                  GetLastError());
161                 ok(!*buf, "Expected empty DLL list\n");
162                 HeapFree(GetProcessHeap(), 0, buf);
163             }
164         }
165     }
166
167     /* MSDN says flags must be 0, but it's not checked */
168     set1 = CryptInitOIDFunctionSet("", 1);
169     ok(set1 != 0, "CryptInitOIDFunctionSet failed: %08lx\n", GetLastError());
170     set2 = CryptInitOIDFunctionSet("", 0);
171     ok(set2 != 0, "CryptInitOIDFunctionSet failed: %08lx\n", GetLastError());
172     /* There isn't a free function, so there must be only one set per name to
173      * limit leaks.  (I guess the sets are freed when crypt32 is unloaded.)
174      */
175     ok(set1 == set2, "Expected identical sets\n");
176     if (set1)
177     {
178         /* The empty name function set used here seems to correspond to
179          * DEFAULT.
180          */
181     }
182
183     /* There's no installed function for a built-in encoding. */
184     set1 = CryptInitOIDFunctionSet("CryptDllEncodeObject", 0);
185     ok(set1 != 0, "CryptInitOIDFunctionSet failed: %08lx\n", GetLastError());
186     if (set1)
187     {
188         void *funcAddr;
189         HCRYPTOIDFUNCADDR hFuncAddr;
190
191         ret = CryptGetOIDFunctionAddress(set1, X509_ASN_ENCODING, X509_CERT, 0,
192          &funcAddr, &hFuncAddr);
193         ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
194          "Expected ERROR_FILE_NOT_FOUND, got %08lx\n", GetLastError());
195     }
196 }
197
198 typedef int (*funcY)(int);
199
200 static int funky(int x)
201 {
202     return x;
203 }
204
205 static void test_installOIDFunctionAddress(void)
206 {
207     BOOL ret;
208     CRYPT_OID_FUNC_ENTRY entry = { CRYPT_DEFAULT_OID, funky };
209     HCRYPTOIDFUNCSET set;
210
211     /* This crashes
212     ret = CryptInstallOIDFunctionAddress(NULL, 0, NULL, 0, NULL, 0);
213      */
214
215     /* Installing zero functions should work */
216     SetLastError(0xdeadbeef);
217     ret = CryptInstallOIDFunctionAddress(NULL, 0, "CryptDllEncodeObject", 0,
218      NULL, 0);
219     ok(ret && GetLastError() == 0xdeadbeef, "Expected success, got %08lx\n",
220      GetLastError());
221
222     /* The function name doesn't much matter */
223     SetLastError(0xdeadbeef);
224     ret = CryptInstallOIDFunctionAddress(NULL, 0, "OhSoFunky", 0, NULL, 0);
225     ok(ret && GetLastError() == 0xdeadbeef, "Expected success, got %08lx\n",
226      GetLastError());
227     SetLastError(0xdeadbeef);
228     entry.pszOID = X509_CERT;
229     ret = CryptInstallOIDFunctionAddress(NULL, 0, "OhSoFunky", 1, &entry, 0);
230     ok(ret && GetLastError() == 0xdeadbeef, "Expected success, got %08lx\n",
231      GetLastError());
232     set = CryptInitOIDFunctionSet("OhSoFunky", 0);
233     ok(set != 0, "CryptInitOIDFunctionSet failed: %08lx\n", GetLastError());
234     if (set)
235     {
236         funcY funcAddr = NULL;
237         HCRYPTOIDFUNCADDR hFuncAddr = NULL;
238
239         /* This crashes
240         ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, 0, 0, NULL,
241          NULL);
242          */
243         ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, 0, 0,
244          (void **)&funcAddr, &hFuncAddr);
245         ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
246          "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
247         ret = CryptGetOIDFunctionAddress(set, X509_ASN_ENCODING, X509_CERT, 0,
248          (void **)&funcAddr, &hFuncAddr);
249         ok(!ret && GetLastError() == ERROR_FILE_NOT_FOUND,
250          "Expected ERROR_FILE_NOT_FOUND, got %ld\n", GetLastError());
251         ret = CryptGetOIDFunctionAddress(set, 0, X509_CERT, 0,
252          (void **)&funcAddr, &hFuncAddr);
253         ok(ret, "CryptGetOIDFunctionAddress failed: %ld\n", GetLastError());
254         if (funcAddr)
255         {
256             int y = funcAddr(0xabadc0da);
257
258             ok(y == 0xabadc0da, "Unexpected return (%d) from function\n", y);
259             CryptFreeOIDFunctionAddress(hFuncAddr, 0);
260         }
261     }
262 }
263
264 static void test_registerOIDFunction(void)
265 {
266     static const WCHAR bogusDll[] = { 'b','o','g','u','s','.','d','l','l',0 };
267     BOOL ret;
268
269     /* oddly, this succeeds under WinXP; the function name key is merely
270      * omitted.  This may be a side effect of the registry code, I don't know.
271      * I don't check it because I doubt anyone would depend on it.
272     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, NULL,
273      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
274      */
275     /* On windows XP, GetLastError is incorrectly being set with an HRESULT,
276      * E_INVALIDARG
277      */
278     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo", NULL, bogusDll,
279      NULL);
280     ok(!ret && GetLastError() == E_INVALIDARG,
281      "Expected E_INVALIDARG: %ld\n", GetLastError());
282     /* This has no effect, but "succeeds" on XP */
283     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "foo",
284      "1.2.3.4.5.6.7.8.9.10", NULL, NULL);
285     ok(ret, "Expected pseudo-success, got %ld\n", GetLastError());
286     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
287      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
288     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
289     ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "CryptDllEncodeObject",
290      "1.2.3.4.5.6.7.8.9.10");
291     ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
292     ret = CryptRegisterOIDFunction(X509_ASN_ENCODING, "bogus",
293      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
294     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
295     ret = CryptUnregisterOIDFunction(X509_ASN_ENCODING, "bogus",
296      "1.2.3.4.5.6.7.8.9.10");
297     ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
298     /* This has no effect */
299     ret = CryptRegisterOIDFunction(PKCS_7_ASN_ENCODING, "CryptDllEncodeObject",
300      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
301     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
302     /* Check with bogus encoding type: */
303     ret = CryptRegisterOIDFunction(0, "CryptDllEncodeObject",
304      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
305     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
306     /* This is written with value 3 verbatim.  Thus, the encoding type isn't
307      * (for now) treated as a mask.
308      */
309     ret = CryptRegisterOIDFunction(3, "CryptDllEncodeObject",
310      "1.2.3.4.5.6.7.8.9.10", bogusDll, NULL);
311     ok(ret, "CryptRegisterOIDFunction failed: %ld\n", GetLastError());
312     ret = CryptUnregisterOIDFunction(3, "CryptDllEncodeObject",
313      "1.2.3.4.5.6.7.8.9.10");
314     ok(ret, "CryptUnregisterOIDFunction failed: %ld\n", GetLastError());
315 }
316
317 static BOOL WINAPI countOidInfo(PCCRYPT_OID_INFO pInfo, void *pvArg)
318 {
319     (*(DWORD *)pvArg)++;
320     return TRUE;
321 }
322
323 static BOOL WINAPI noOidInfo(PCCRYPT_OID_INFO pInfo, void *pvArg)
324 {
325     return FALSE;
326 }
327
328 static void test_enumOIDInfo(void)
329 {
330     BOOL ret;
331     DWORD count = 0;
332
333     /* This crashes
334     ret = CryptEnumOIDInfo(7, 0, NULL, NULL);
335      */
336
337     /* Silly tests, check that more than one thing is enumerated */
338     ret = CryptEnumOIDInfo(0, 0, &count, countOidInfo);
339     ok(ret && count > 0, "Expected more than item enumerated\n");
340     ret = CryptEnumOIDInfo(0, 0, NULL, noOidInfo);
341     ok(!ret, "Expected FALSE\n");
342 }
343
344 static void test_findOIDInfo(void)
345 {
346     static const WCHAR sha1[] = { 's','h','a','1',0 };
347     ALG_ID alg = CALG_SHA1;
348     ALG_ID algs[2] = { CALG_MD5, CALG_RSA_SIGN };
349     PCCRYPT_OID_INFO info;
350
351     info = CryptFindOIDInfo(0, NULL, 0);
352     ok(info == NULL, "Expected NULL\n");
353     info = CryptFindOIDInfo(CRYPT_OID_INFO_OID_KEY, szOID_RSA_MD5, 0);
354     ok(info != NULL, "Expected to find szOID_RSA_MD5\n");
355     if (info)
356     {
357         ok(!strcmp(info->pszOID, szOID_RSA_MD5), "Expected %s, got %s\n",
358          szOID_RSA_MD5, info->pszOID);
359         ok(U(*info).Algid == CALG_MD5, "Expected CALG_MD5, got %d\n",
360            U(*info).Algid);
361     }
362     info = CryptFindOIDInfo(CRYPT_OID_INFO_NAME_KEY, (void *)sha1, 0);
363     ok(info != NULL, "Expected to find sha1\n");
364     if (info)
365     {
366         ok(!strcmp(info->pszOID, szOID_OIWSEC_sha1), "Expected %s, got %s\n",
367          szOID_OIWSEC_sha1, info->pszOID);
368         ok(U(*info).Algid == CALG_SHA1, "Expected CALG_SHA1, got %d\n",
369            U(*info).Algid);
370     }
371     info = CryptFindOIDInfo(CRYPT_OID_INFO_ALGID_KEY, &alg, 0);
372     ok(info != NULL, "Expected to find sha1\n");
373     if (info)
374     {
375         ok(!strcmp(info->pszOID, szOID_OIWSEC_sha1), "Expected %s, got %s\n",
376          szOID_OIWSEC_sha1, info->pszOID);
377         ok(U(*info).Algid == CALG_SHA1, "Expected CALG_SHA1, got %d\n",
378            U(*info).Algid);
379     }
380     info = CryptFindOIDInfo(CRYPT_OID_INFO_SIGN_KEY, algs, 0);
381     ok(info != NULL, "Expected to find md5RSA\n");
382     if (info)
383     {
384         ok(!strcmp(info->pszOID, szOID_RSA_MD5RSA), "Expected %s, got %s\n",
385          szOID_RSA_MD5RSA, info->pszOID);
386         ok(U(*info).Algid == CALG_MD5, "Expected CALG_MD5, got %d\n",
387            U(*info).Algid);
388     }
389 }
390
391 START_TEST(oid)
392 {
393     testOIDToAlgID();
394     testAlgIDToOID();
395     test_enumOIDInfo();
396     test_findOIDInfo();
397     test_oidFunctionSet();
398     test_installOIDFunctionAddress();
399     test_registerOIDFunction();
400 }