Moved in win32
[reactos.git] / reactos / dll / win32 / crypt32 / oid.c
1 /*
2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2005 Juan Lang
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
19 #include <stdio.h>
20 #include <stdarg.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "wincrypt.h"
24 #include "winreg.h"
25 #include "wine/debug.h"
26 #include "wine/list.h"
27 #include "crypt32_private.h"
28
29 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
30
31 static const WCHAR DllW[] = { 'D','l','l',0 };
32 CRITICAL_SECTION funcSetCS;
33 struct list funcSets;
34
35 struct OIDFunctionSet
36 {
37 LPSTR name;
38 CRITICAL_SECTION cs; /* protects functions */
39 struct list functions;
40 struct list next;
41 };
42
43 struct OIDFunction
44 {
45 DWORD encoding;
46 CRYPT_OID_FUNC_ENTRY entry;
47 struct list next;
48 };
49
50 void CRYPT_InitFunctionSets(void)
51 {
52 InitializeCriticalSection(&funcSetCS);
53 list_init(&funcSets);
54 }
55
56 void CRYPT_FreeFunctionSets(void)
57 {
58 struct OIDFunctionSet *setCursor, *setNext;
59
60 LIST_FOR_EACH_ENTRY_SAFE(setCursor, setNext, &funcSets,
61 struct OIDFunctionSet, next)
62 {
63 struct OIDFunction *functionCursor, *funcNext;
64
65 list_remove(&setCursor->next);
66 CryptMemFree(setCursor->name);
67 CryptMemFree(setCursor);
68 LIST_FOR_EACH_ENTRY_SAFE(functionCursor, funcNext,
69 &setCursor->functions, struct OIDFunction, next)
70 {
71 list_remove(&functionCursor->next);
72 CryptMemFree(functionCursor);
73 }
74 DeleteCriticalSection(&setCursor->cs);
75 }
76 DeleteCriticalSection(&funcSetCS);
77 }
78
79 /* There is no free function associated with this; therefore, the sets are
80 * freed when crypt32.dll is unloaded.
81 */
82 HCRYPTOIDFUNCSET WINAPI CryptInitOIDFunctionSet(LPCSTR pszFuncName,
83 DWORD dwFlags)
84 {
85 struct OIDFunctionSet *cursor, *ret = NULL;
86
87 TRACE("(%s, %lx)\n", debugstr_a(pszFuncName), dwFlags);
88
89 EnterCriticalSection(&funcSetCS);
90 LIST_FOR_EACH_ENTRY(cursor, &funcSets, struct OIDFunctionSet, next)
91 {
92 if (!strcasecmp(pszFuncName, cursor->name))
93 {
94 ret = (HCRYPTOIDFUNCSET)cursor;
95 break;
96 }
97 }
98 if (!ret)
99 {
100 ret = CryptMemAlloc(sizeof(struct OIDFunctionSet));
101 if (ret)
102 {
103 memset(ret, 0, sizeof(*ret));
104 ret->name = CryptMemAlloc(strlen(pszFuncName) + 1);
105 if (ret->name)
106 {
107 InitializeCriticalSection(&ret->cs);
108 list_init(&ret->functions);
109 strcpy(ret->name, pszFuncName);
110 list_add_tail(&funcSets, &ret->next);
111 }
112 else
113 {
114 CryptMemFree(ret);
115 ret = NULL;
116 }
117 }
118 }
119 LeaveCriticalSection(&funcSetCS);
120
121 return (HCRYPTOIDFUNCSET)ret;
122 }
123
124 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
125 LPCSTR pszOID)
126 {
127 static const char szEncodingTypeFmt[] =
128 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
129 UINT len;
130 char numericOID[7]; /* enough for "#65535" */
131 const char *oid;
132 LPSTR szKey;
133
134 /* MSDN says the encoding type is a mask, but it isn't treated that way.
135 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
136 * "EncodingType 2" would be expected if it were a mask. Instead native
137 * stores values in "EncodingType 3".
138 */
139 if (!HIWORD(pszOID))
140 {
141 snprintf(numericOID, sizeof(numericOID), "#%d", LOWORD(pszOID));
142 oid = numericOID;
143 }
144 else
145 oid = pszOID;
146
147 /* This is enough: the lengths of the two string parameters are explicitly
148 * counted, and we need up to five additional characters for the encoding
149 * type. These are covered by the "%d", "%s", and "%s" characters in the
150 * format specifier that are removed by sprintf.
151 */
152 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
153 szKey = CryptMemAlloc(len);
154 if (szKey)
155 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
156 return szKey;
157 }
158
159 BOOL WINAPI CryptGetDefaultOIDDllList(HCRYPTOIDFUNCSET hFuncSet,
160 DWORD dwEncodingType, LPWSTR pwszDllList, DWORD *pcchDllList)
161 {
162 BOOL ret = TRUE;
163 struct OIDFunctionSet *set = (struct OIDFunctionSet *)hFuncSet;
164 char *keyName;
165 HKEY key;
166 long rc;
167
168 TRACE("(%p, %ld, %p, %p)\n", hFuncSet, dwEncodingType, pwszDllList,
169 pcchDllList);
170
171 keyName = CRYPT_GetKeyName(dwEncodingType, set->name, "DEFAULT");
172 rc = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, NULL, 0,
173 KEY_READ, NULL, &key, NULL);
174 if (!rc)
175 {
176 DWORD size = *pcchDllList * sizeof(WCHAR);
177
178 rc = RegQueryValueExW(key, DllW, NULL, NULL, (LPBYTE)pwszDllList,
179 &size);
180 if (!rc)
181 *pcchDllList = size / sizeof(WCHAR);
182 else
183 {
184 /* No value, return an empty list */
185 if (*pcchDllList)
186 *pwszDllList = '\0';
187 *pcchDllList = 1;
188 }
189 RegCloseKey(key);
190 }
191 else
192 {
193 SetLastError(rc);
194 ret = FALSE;
195 }
196 CryptMemFree(keyName);
197
198 return ret;
199 }
200
201 BOOL WINAPI CryptInstallOIDFunctionAddress(HMODULE hModule,
202 DWORD dwEncodingType, LPCSTR pszFuncName, DWORD cFuncEntry,
203 const CRYPT_OID_FUNC_ENTRY rgFuncEntry[], DWORD dwFlags)
204 {
205 BOOL ret = TRUE;
206 struct OIDFunctionSet *set;
207
208 TRACE("(%p, %ld, %s, %ld, %p, %08lx)\n", hModule, dwEncodingType,
209 debugstr_a(pszFuncName), cFuncEntry, rgFuncEntry, dwFlags);
210
211 set = (struct OIDFunctionSet *)CryptInitOIDFunctionSet(pszFuncName, 0);
212 if (set)
213 {
214 DWORD i;
215
216 EnterCriticalSection(&set->cs);
217 for (i = 0; ret && i < cFuncEntry; i++)
218 {
219 struct OIDFunction *func;
220
221 if (HIWORD(rgFuncEntry[i].pszOID))
222 func = CryptMemAlloc(sizeof(struct OIDFunction)
223 + strlen(rgFuncEntry[i].pszOID) + 1);
224 else
225 func = CryptMemAlloc(sizeof(struct OIDFunction));
226 if (func)
227 {
228 func->encoding = dwEncodingType;
229 if (HIWORD(rgFuncEntry[i].pszOID))
230 {
231 func->entry.pszOID = (LPSTR)((LPBYTE)func + sizeof(*func));
232 strcpy((LPSTR)func->entry.pszOID, rgFuncEntry[i].pszOID);
233 }
234 else
235 func->entry.pszOID = rgFuncEntry[i].pszOID;
236 func->entry.pvFuncAddr = rgFuncEntry[i].pvFuncAddr;
237 list_add_tail(&set->functions, &func->next);
238 }
239 else
240 ret = FALSE;
241 }
242 LeaveCriticalSection(&set->cs);
243 }
244 else
245 ret = FALSE;
246 return ret;
247 }
248
249 static BOOL CRYPT_GetFuncFromReg(DWORD dwEncodingType, LPCSTR pszOID,
250 LPCSTR szFuncName, LPVOID *ppvFuncAddr, HCRYPTOIDFUNCADDR *phFuncAddr)
251 {
252 BOOL ret = FALSE;
253 char *keyName;
254 const char *funcName;
255 HKEY key;
256 long rc;
257
258 keyName = CRYPT_GetKeyName(dwEncodingType, szFuncName, pszOID);
259 rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &key);
260 if (!rc)
261 {
262 DWORD type, size = 0;
263
264 rc = RegQueryValueExA(key, "FuncName", NULL, &type, NULL, &size);
265 if (rc == ERROR_MORE_DATA && type == REG_SZ)
266 {
267 funcName = CryptMemAlloc(size);
268 rc = RegQueryValueExA(key, "FuncName", NULL, &type,
269 (LPBYTE)funcName, &size);
270 }
271 else
272 funcName = szFuncName;
273 rc = RegQueryValueExW(key, DllW, NULL, &type, NULL, &size);
274 if (rc == ERROR_MORE_DATA && type == REG_SZ)
275 {
276 LPWSTR dllName = CryptMemAlloc(size);
277
278 if (dllName)
279 {
280 rc = RegQueryValueExW(key, DllW, NULL, NULL,
281 (LPBYTE)dllName, &size);
282 if (!rc)
283 {
284 HMODULE lib;
285
286 /* This is a bit of a hack; MSDN describes a more
287 * complicated unload routine than this will allow.
288 * Still, this seems to suffice for now.
289 */
290 lib = LoadLibraryW(dllName);
291 if (lib)
292 {
293 *ppvFuncAddr = GetProcAddress(lib, szFuncName);
294 if (*ppvFuncAddr)
295 {
296 *phFuncAddr = (HCRYPTOIDFUNCADDR)lib;
297 ret = TRUE;
298 }
299 else
300 {
301 /* Unload the library, the caller doesn't want
302 * to unload it when the return value is NULL.
303 */
304 FreeLibrary(lib);
305 }
306 }
307 }
308 else
309 SetLastError(rc);
310 CryptMemFree(dllName);
311 }
312 }
313 else
314 SetLastError(rc);
315 if (funcName != szFuncName)
316 CryptMemFree((char *)funcName);
317 RegCloseKey(key);
318 }
319 else
320 SetLastError(rc);
321 CryptMemFree(keyName);
322 return ret;
323 }
324
325 BOOL WINAPI CryptGetOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet,
326 DWORD dwEncodingType, LPCSTR pszOID, DWORD dwFlags, void **ppvFuncAddr,
327 HCRYPTOIDFUNCADDR *phFuncAddr)
328 {
329 BOOL ret = FALSE;
330 struct OIDFunctionSet *set = (struct OIDFunctionSet *)hFuncSet;
331
332 TRACE("(%p, %ld, %s, %08lx, %p, %p)\n", hFuncSet, dwEncodingType,
333 debugstr_a(pszOID), dwFlags, ppvFuncAddr, phFuncAddr);
334
335 *ppvFuncAddr = NULL;
336 if (!(dwFlags & CRYPT_GET_INSTALLED_OID_FUNC_FLAG))
337 {
338 struct OIDFunction *function;
339
340 EnterCriticalSection(&set->cs);
341 LIST_FOR_EACH_ENTRY(function, &set->functions, struct OIDFunction, next)
342 {
343 if (function->encoding == dwEncodingType)
344 {
345 if (HIWORD(pszOID))
346 {
347 if (HIWORD(function->entry.pszOID &&
348 !strcasecmp(function->entry.pszOID, pszOID)))
349 {
350 *ppvFuncAddr = function->entry.pvFuncAddr;
351 *phFuncAddr = NULL; /* FIXME: what should it be? */
352 ret = TRUE;
353 break;
354 }
355 }
356 else if (function->entry.pszOID == pszOID)
357 {
358 *ppvFuncAddr = function->entry.pvFuncAddr;
359 *phFuncAddr = NULL; /* FIXME: what should it be? */
360 ret = TRUE;
361 break;
362 }
363 }
364 }
365 LeaveCriticalSection(&set->cs);
366 }
367 if (!*ppvFuncAddr)
368 ret = CRYPT_GetFuncFromReg(dwEncodingType, pszOID, set->name,
369 ppvFuncAddr, phFuncAddr);
370 return ret;
371 }
372
373 BOOL WINAPI CryptFreeOIDFunctionAddress(HCRYPTOIDFUNCADDR hFuncAddr,
374 DWORD dwFlags)
375 {
376 TRACE("(%p, %08lx)\n", hFuncAddr, dwFlags);
377
378 /* FIXME: as MSDN states, need to check for DllCanUnloadNow in the DLL,
379 * and only unload it if it can be unloaded. Also need to implement ref
380 * counting on the functions.
381 */
382 FreeLibrary((HMODULE)hFuncAddr);
383 return TRUE;
384 }
385
386 BOOL WINAPI CryptRegisterDefaultOIDFunction(DWORD dwEncodingType,
387 LPCSTR pszFuncName, DWORD dwIndex, LPCWSTR pwszDll)
388 {
389 FIXME("(%lx,%s,%lx,%s) stub!\n", dwEncodingType, pszFuncName, dwIndex,
390 debugstr_w(pwszDll));
391 return FALSE;
392 }
393
394 BOOL WINAPI CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType,
395 LPCSTR pszFuncName, LPCWSTR pwszDll)
396 {
397 FIXME("(%lx %s %s): stub\n", dwEncodingType, debugstr_a(pszFuncName),
398 debugstr_w(pwszDll));
399 return FALSE;
400 }
401
402 BOOL WINAPI CryptGetDefaultOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet,
403 DWORD dwEncodingType, LPCWSTR pwszDll, DWORD dwFlags, void *ppvFuncAddr,
404 HCRYPTOIDFUNCADDR *phFuncAddr)
405 {
406 FIXME("(%p, %ld, %s, %08lx, %p, %p): stub\n", hFuncSet, dwEncodingType,
407 debugstr_w(pwszDll), dwFlags, ppvFuncAddr, phFuncAddr);
408 return FALSE;
409 }
410
411 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
412 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
413 {
414 LONG r;
415 HKEY hKey;
416 LPSTR szKey;
417
418 TRACE("(%lx, %s, %s, %s, %s)\n", dwEncodingType, pszFuncName, pszOID,
419 debugstr_w(pwszDll), pszOverrideFuncName);
420
421 /* This only registers functions for encoding certs, not messages */
422 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
423 return TRUE;
424
425 /* Native does nothing pwszDll is NULL */
426 if (!pwszDll)
427 return TRUE;
428
429 /* I'm not matching MS bug for bug here, because I doubt any app depends on
430 * it: native "succeeds" if pszFuncName is NULL, but the nonsensical entry
431 * it creates would never be used.
432 */
433 if (!pszFuncName || !pszOID)
434 {
435 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
436 return FALSE;
437 }
438
439 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
440 TRACE("Key name is %s\n", debugstr_a(szKey));
441
442 if (!szKey)
443 return FALSE;
444
445 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
446 CryptMemFree(szKey);
447 if(r != ERROR_SUCCESS)
448 return FALSE;
449
450 /* write the values */
451 if (pszOverrideFuncName)
452 RegSetValueExA(hKey, "FuncName", 0, REG_SZ,
453 (const BYTE*)pszOverrideFuncName, lstrlenA(pszOverrideFuncName) + 1);
454 RegSetValueExW(hKey, DllW, 0, REG_SZ, (const BYTE*) pwszDll,
455 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
456
457 RegCloseKey(hKey);
458 return TRUE;
459 }
460
461 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
462 LPCSTR pszOID)
463 {
464 LPSTR szKey;
465 LONG rc;
466
467 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
468
469 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
470 return TRUE;
471
472 if (!pszFuncName || !pszOID)
473 {
474 SetLastError(ERROR_INVALID_PARAMETER);
475 return FALSE;
476 }
477
478 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
479 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
480 CryptMemFree(szKey);
481 if (rc)
482 SetLastError(rc);
483 return rc ? FALSE : TRUE;
484 }
485
486 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
487 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
488 DWORD *pcbValueData)
489 {
490 LPSTR szKey;
491 LONG rc;
492 HKEY hKey;
493
494 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
495 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
496 pcbValueData);
497
498 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
499 return TRUE;
500
501 if (!pszFuncName || !pszOID || !pwszValueName)
502 {
503 SetLastError(ERROR_INVALID_PARAMETER);
504 return FALSE;
505 }
506
507 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
508 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
509 CryptMemFree(szKey);
510 if (rc)
511 SetLastError(rc);
512 else
513 {
514 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
515 pbValueData, pcbValueData);
516 if (rc)
517 SetLastError(rc);
518 RegCloseKey(hKey);
519 }
520 return rc ? FALSE : TRUE;
521 }
522
523 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
524 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
525 const BYTE *pbValueData, DWORD cbValueData)
526 {
527 LPSTR szKey;
528 LONG rc;
529 HKEY hKey;
530
531 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
532 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
533 cbValueData);
534
535 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
536 return TRUE;
537
538 if (!pszFuncName || !pszOID || !pwszValueName)
539 {
540 SetLastError(ERROR_INVALID_PARAMETER);
541 return FALSE;
542 }
543
544 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
545 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
546 CryptMemFree(szKey);
547 if (rc)
548 SetLastError(rc);
549 else
550 {
551 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
552 cbValueData);
553 if (rc)
554 SetLastError(rc);
555 RegCloseKey(hKey);
556 }
557 return rc ? FALSE : TRUE;
558 }