1 /*
2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2005-2006 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., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
18 */
19
20 #include "config.h"
21 #include "wine/port.h"
22
23 #include <stdio.h>
24 #include <stdarg.h>
25 #define NONAMELESSUNION
26 #include "windef.h"
27 #include "winbase.h"
28 #include "wincrypt.h"
29 #include "winreg.h"
30 #include "winuser.h"
31 #include "wine/debug.h"
32 #include "wine/list.h"
33 #include "crypt32_private.h"
34 #include "cryptres.h"
35
36 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
37
38 static const WCHAR DllW[] = { 'D','l','l',0 };
39
40 static void init_oid_info(HINSTANCE hinst);
41 static void free_function_sets(void);
42 static void free_oid_info(void);
43
44 void crypt_oid_init(HINSTANCE hinst)
45 {
46 init_oid_info(hinst);
47 }
48
49 void crypt_oid_free(void)
50 {
51 free_function_sets();
52 free_oid_info();
53 }
54
55 static CRITICAL_SECTION funcSetCS;
56 static CRITICAL_SECTION_DEBUG funcSetCSDebug =
57 {
58 0, 0, &funcSetCS,
59 { &funcSetCSDebug.ProcessLocksList, &funcSetCSDebug.ProcessLocksList },
60 0, 0, { (DWORD_PTR)(__FILE__ ": funcSetCS") }
61 };
62 static CRITICAL_SECTION funcSetCS = { &funcSetCSDebug, -1, 0, 0, 0, 0 };
63 static struct list funcSets = { &funcSets, &funcSets };
64
65 struct OIDFunctionSet
66 {
67 LPSTR name;
68 CRITICAL_SECTION cs; /* protects functions */
69 struct list functions;
70 struct list next;
71 };
72
73 struct OIDFunction
74 {
75 DWORD encoding;
76 CRYPT_OID_FUNC_ENTRY entry;
77 struct list next;
78 };
79
80 static const WCHAR ROOT[] = {'R','O','O','T',0};
81 static const WCHAR MY[] = {'M','Y',0};
82 static const WCHAR CA[] = {'C','A',0};
83 static const WCHAR ADDRESSBOOK[] = {'A','D','D','R','E','S','S','B','O','O','K',0};
84 static const LPCWSTR LocalizedKeys[] = {ROOT,MY,CA,ADDRESSBOOK};
85 static WCHAR LocalizedNames[4][256];
86
87 static void free_function_sets(void)
88 {
89 struct OIDFunctionSet *setCursor, *setNext;
90
91 LIST_FOR_EACH_ENTRY_SAFE(setCursor, setNext, &funcSets,
92 struct OIDFunctionSet, next)
93 {
94 struct OIDFunction *functionCursor, *funcNext;
95
96 list_remove(&setCursor->next);
97 CryptMemFree(setCursor->name);
98 LIST_FOR_EACH_ENTRY_SAFE(functionCursor, funcNext,
99 &setCursor->functions, struct OIDFunction, next)
100 {
101 list_remove(&functionCursor->next);
102 CryptMemFree(functionCursor);
103 }
104 setCursor->cs.DebugInfo->Spare[0] = 0;
105 DeleteCriticalSection(&setCursor->cs);
106 CryptMemFree(setCursor);
107 }
108 }
109
110 /* There is no free function associated with this; therefore, the sets are
111 * freed when crypt32.dll is unloaded.
112 */
113 HCRYPTOIDFUNCSET WINAPI CryptInitOIDFunctionSet(LPCSTR pszFuncName,
114 DWORD dwFlags)
115 {
116 struct OIDFunctionSet *cursor, *ret = NULL;
117
118 TRACE("(%s, %x)\n", debugstr_a(pszFuncName), dwFlags);
119
120 EnterCriticalSection(&funcSetCS);
121 LIST_FOR_EACH_ENTRY(cursor, &funcSets, struct OIDFunctionSet, next)
122 {
123 if (!strcasecmp(pszFuncName, cursor->name))
124 {
125 ret = (HCRYPTOIDFUNCSET)cursor;
126 break;
127 }
128 }
129 if (!ret)
130 {
131 ret = CryptMemAlloc(sizeof(struct OIDFunctionSet));
132 if (ret)
133 {
134 memset(ret, 0, sizeof(*ret));
135 ret->name = CryptMemAlloc(strlen(pszFuncName) + 1);
136 if (ret->name)
137 {
138 InitializeCriticalSection(&ret->cs);
139 ret->cs.DebugInfo->Spare[0] = (DWORD_PTR)(__FILE__ ": OIDFunctionSet.cs");
140 list_init(&ret->functions);
141 strcpy(ret->name, pszFuncName);
142 list_add_tail(&funcSets, &ret->next);
143 }
144 else
145 {
146 CryptMemFree(ret);
147 ret = NULL;
148 }
149 }
150 }
151 LeaveCriticalSection(&funcSetCS);
152
153 return (HCRYPTOIDFUNCSET)ret;
154 }
155
156 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
157 LPCSTR pszOID)
158 {
159 static const char szEncodingTypeFmt[] =
160 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %d\\%s\\%s";
161 UINT len;
162 char numericOID[7]; /* enough for "#65535" */
163 const char *oid;
164 LPSTR szKey;
165
166 /* MSDN says the encoding type is a mask, but it isn't treated that way.
167 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
168 * "EncodingType 2" would be expected if it were a mask. Instead native
169 * stores values in "EncodingType 3".
170 */
171 if (!HIWORD(pszOID))
172 {
173 snprintf(numericOID, sizeof(numericOID), "#%d", LOWORD(pszOID));
174 oid = numericOID;
175 }
176 else
177 oid = pszOID;
178
179 /* This is enough: the lengths of the two string parameters are explicitly
180 * counted, and we need up to five additional characters for the encoding
181 * type. These are covered by the "%d", "%s", and "%s" characters in the
182 * format specifier that are removed by sprintf.
183 */
184 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
185 szKey = CryptMemAlloc(len);
186 if (szKey)
187 sprintf(szKey, szEncodingTypeFmt,
188 GET_CERT_ENCODING_TYPE(dwEncodingType), pszFuncName, oid);
189 return szKey;
190 }
191
192 BOOL WINAPI CryptGetDefaultOIDDllList(HCRYPTOIDFUNCSET hFuncSet,
193 DWORD dwEncodingType, LPWSTR pwszDllList, DWORD *pcchDllList)
194 {
195 BOOL ret = TRUE;
196 struct OIDFunctionSet *set = (struct OIDFunctionSet *)hFuncSet;
197 char *keyName;
198 HKEY key;
199 long rc;
200
201 TRACE("(%p, %d, %p, %p)\n", hFuncSet, dwEncodingType, pwszDllList,
202 pcchDllList);
203
204 keyName = CRYPT_GetKeyName(dwEncodingType, set->name, "DEFAULT");
205 rc = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, NULL, 0,
206 KEY_READ, NULL, &key, NULL);
207 if (!rc)
208 {
209 DWORD size = *pcchDllList * sizeof(WCHAR);
210
211 rc = RegQueryValueExW(key, DllW, NULL, NULL, (LPBYTE)pwszDllList,
212 &size);
213 if (!rc)
214 *pcchDllList = size / sizeof(WCHAR);
215 else
216 {
217 /* No value, return an empty list */
218 if (pwszDllList && *pcchDllList)
219 *pwszDllList = '\0';
220 *pcchDllList = 1;
221 }
222 RegCloseKey(key);
223 }
224 else
225 {
226 /* No value, return an empty list */
227 if (pwszDllList && *pcchDllList)
228 *pwszDllList = '\0';
229 *pcchDllList = 1;
230 }
231 CryptMemFree(keyName);
232
233 return ret;
234 }
235
236 BOOL WINAPI CryptInstallOIDFunctionAddress(HMODULE hModule,
237 DWORD dwEncodingType, LPCSTR pszFuncName, DWORD cFuncEntry,
238 const CRYPT_OID_FUNC_ENTRY rgFuncEntry[], DWORD dwFlags)
239 {
240 BOOL ret = TRUE;
241 struct OIDFunctionSet *set;
242
243 TRACE("(%p, %d, %s, %d, %p, %08x)\n", hModule, dwEncodingType,
244 debugstr_a(pszFuncName), cFuncEntry, rgFuncEntry, dwFlags);
245
246 set = (struct OIDFunctionSet *)CryptInitOIDFunctionSet(pszFuncName, 0);
247 if (set)
248 {
249 DWORD i;
250
251 EnterCriticalSection(&set->cs);
252 for (i = 0; ret && i < cFuncEntry; i++)
253 {
254 struct OIDFunction *func;
255
256 if (HIWORD(rgFuncEntry[i].pszOID))
257 func = CryptMemAlloc(sizeof(struct OIDFunction)
258 + strlen(rgFuncEntry[i].pszOID) + 1);
259 else
260 func = CryptMemAlloc(sizeof(struct OIDFunction));
261 if (func)
262 {
263 func->encoding = GET_CERT_ENCODING_TYPE(dwEncodingType);
264 if (HIWORD(rgFuncEntry[i].pszOID))
265 {
266 LPSTR oid;
267
268 oid = (LPSTR)((LPBYTE)func + sizeof(*func));
269 strcpy(oid, rgFuncEntry[i].pszOID);
270 func->entry.pszOID = oid;
271 }
272 else
273 func->entry.pszOID = rgFuncEntry[i].pszOID;
274 func->entry.pvFuncAddr = rgFuncEntry[i].pvFuncAddr;
275 list_add_tail(&set->functions, &func->next);
276 }
277 else
278 ret = FALSE;
279 }
280 LeaveCriticalSection(&set->cs);
281 }
282 else
283 ret = FALSE;
284 return ret;
285 }
286
287 struct FuncAddr
288 {
289 HMODULE lib;
290 LPWSTR dllList;
291 LPWSTR currentDll;
292 };
293
294 static BOOL CRYPT_GetFuncFromReg(DWORD dwEncodingType, LPCSTR pszOID,
295 LPCSTR szFuncName, LPVOID *ppvFuncAddr, HCRYPTOIDFUNCADDR *phFuncAddr)
296 {
297 BOOL ret = FALSE;
298 char *keyName;
299 const char *funcName;
300 HKEY key;
301 long rc;
302
303 keyName = CRYPT_GetKeyName(dwEncodingType, szFuncName, pszOID);
304 rc = RegOpenKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, KEY_READ, &key);
305 if (!rc)
306 {
307 DWORD type, size = 0;
308
309 rc = RegQueryValueExA(key, "FuncName", NULL, &type, NULL, &size);
310 if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ)
311 {
312 funcName = CryptMemAlloc(size);
313 rc = RegQueryValueExA(key, "FuncName", NULL, &type,
314 (LPBYTE)funcName, &size);
315 }
316 else
317 funcName = szFuncName;
318 rc = RegQueryValueExW(key, DllW, NULL, &type, NULL, &size);
319 if ((!rc || rc == ERROR_MORE_DATA) && type == REG_SZ)
320 {
321 LPWSTR dllName = CryptMemAlloc(size);
322
323 if (dllName)
324 {
325 rc = RegQueryValueExW(key, DllW, NULL, NULL,
326 (LPBYTE)dllName, &size);
327 if (!rc)
328 {
329 HMODULE lib;
330
331 /* This is a bit of a hack; MSDN describes a more
332 * complicated unload routine than this will allow.
333 * Still, this seems to suffice for now.
334 */
335 lib = LoadLibraryW(dllName);
336 if (lib)
337 {
338 *ppvFuncAddr = GetProcAddress(lib, funcName);
339 if (*ppvFuncAddr)
340 {
341 struct FuncAddr *addr =
342 CryptMemAlloc(sizeof(struct FuncAddr));
343
344 if (addr)
345 {
346 addr->lib = lib;
347 addr->dllList = addr->currentDll = NULL;
348 *phFuncAddr = addr;
349 ret = TRUE;
350 }
351 else
352 {
353 *phFuncAddr = NULL;
354 FreeLibrary(lib);
355 }
356 }
357 else
358 {
359 /* Unload the library, the caller doesn't want
360 * to unload it when the return value is NULL.
361 */
362 FreeLibrary(lib);
363 }
364 }
365 }
366 else
367 SetLastError(rc);
368 CryptMemFree(dllName);
369 }
370 }
371 else
372 SetLastError(rc);
373 if (funcName != szFuncName)
374 CryptMemFree((char *)funcName);
375 RegCloseKey(key);
376 }
377 else
378 SetLastError(rc);
379 CryptMemFree(keyName);
380 return ret;
381 }
382
383 BOOL WINAPI CryptGetOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet,
384 DWORD dwEncodingType, LPCSTR pszOID, DWORD dwFlags, void **ppvFuncAddr,
385 HCRYPTOIDFUNCADDR *phFuncAddr)
386 {
387 BOOL ret = FALSE;
388 struct OIDFunctionSet *set = (struct OIDFunctionSet *)hFuncSet;
389
390 TRACE("(%p, %d, %s, %08x, %p, %p)\n", hFuncSet, dwEncodingType,
391 debugstr_a(pszOID), dwFlags, ppvFuncAddr, phFuncAddr);
392
393 *ppvFuncAddr = NULL;
394 if (!(dwFlags & CRYPT_GET_INSTALLED_OID_FUNC_FLAG))
395 {
396 struct OIDFunction *function;
397
398 EnterCriticalSection(&set->cs);
399 LIST_FOR_EACH_ENTRY(function, &set->functions, struct OIDFunction, next)
400 {
401 if (function->encoding == GET_CERT_ENCODING_TYPE(dwEncodingType))
402 {
403 if (HIWORD(pszOID))
404 {
405 if (HIWORD(function->entry.pszOID) &&
406 !strcasecmp(function->entry.pszOID, pszOID))
407 {
408 *ppvFuncAddr = function->entry.pvFuncAddr;
409 *phFuncAddr = NULL; /* FIXME: what should it be? */
410 ret = TRUE;
411 break;
412 }
413 }
414 else if (function->entry.pszOID == pszOID)
415 {
416 *ppvFuncAddr = function->entry.pvFuncAddr;
417 *phFuncAddr = NULL; /* FIXME: what should it be? */
418 ret = TRUE;
419 break;
420 }
421 }
422 }
423 LeaveCriticalSection(&set->cs);
424 }
425 if (!*ppvFuncAddr)
426 ret = CRYPT_GetFuncFromReg(dwEncodingType, pszOID, set->name,
427 ppvFuncAddr, phFuncAddr);
428 TRACE("returning %d\n", ret);
429 return ret;
430 }
431
432 BOOL WINAPI CryptFreeOIDFunctionAddress(HCRYPTOIDFUNCADDR hFuncAddr,
433 DWORD dwFlags)
434 {
435 TRACE("(%p, %08x)\n", hFuncAddr, dwFlags);
436
437 /* FIXME: as MSDN states, need to check for DllCanUnloadNow in the DLL,
438 * and only unload it if it can be unloaded. Also need to implement ref
439 * counting on the functions.
440 */
441 if (hFuncAddr)
442 {
443 struct FuncAddr *addr = (struct FuncAddr *)hFuncAddr;
444
445 CryptMemFree(addr->dllList);
446 FreeLibrary(addr->lib);
447 CryptMemFree(addr);
448 }
449 return TRUE;
450 }
451
452 static BOOL CRYPT_GetFuncFromDll(LPCWSTR dll, LPCSTR func, HMODULE *lib,
453 void **ppvFuncAddr)
454 {
455 BOOL ret = FALSE;
456
457 *lib = LoadLibraryW(dll);
458 if (*lib)
459 {
460 *ppvFuncAddr = GetProcAddress(*lib, func);
461 if (*ppvFuncAddr)
462 ret = TRUE;
463 else
464 {
465 FreeLibrary(*lib);
466 *lib = NULL;
467 }
468 }
469 return ret;
470 }
471
472 BOOL WINAPI CryptGetDefaultOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet,
473 DWORD dwEncodingType, LPCWSTR pwszDll, DWORD dwFlags, void **ppvFuncAddr,
474 HCRYPTOIDFUNCADDR *phFuncAddr)
475 {
476 struct OIDFunctionSet *set = (struct OIDFunctionSet *)hFuncSet;
477 BOOL ret = FALSE;
478
479 TRACE("(%p, %d, %s, %08x, %p, %p)\n", hFuncSet, dwEncodingType,
480 debugstr_w(pwszDll), dwFlags, ppvFuncAddr, phFuncAddr);
481
482 if (pwszDll)
483 {
484 HMODULE lib;
485
486 *phFuncAddr = NULL;
487 ret = CRYPT_GetFuncFromDll(pwszDll, set->name, &lib, ppvFuncAddr);
488 if (ret)
489 {
490 struct FuncAddr *addr = CryptMemAlloc(sizeof(struct FuncAddr));
491
492 if (addr)
493 {
494 addr->lib = lib;
495 addr->dllList = addr->currentDll = NULL;
496 *phFuncAddr = addr;
497 }
498 else
499 {
500 FreeLibrary(lib);
501 *ppvFuncAddr = NULL;
502 SetLastError(ERROR_OUTOFMEMORY);
503 ret = FALSE;
504 }
505 }
506 else
507 SetLastError(ERROR_FILE_NOT_FOUND);
508 }
509 else
510 {
511 struct FuncAddr *addr = (struct FuncAddr *)*phFuncAddr;
512
513 if (!addr)
514 {
515 DWORD size;
516
517 ret = CryptGetDefaultOIDDllList(hFuncSet, dwEncodingType, NULL,
518 &size);
519 if (ret)
520 {
521 LPWSTR dllList = CryptMemAlloc(size * sizeof(WCHAR));
522
523 if (dllList)
524 {
525 ret = CryptGetDefaultOIDDllList(hFuncSet, dwEncodingType,
526 dllList, &size);
527 if (ret)
528 {
529 addr = CryptMemAlloc(sizeof(struct FuncAddr));
530 if (addr)
531 {
532 addr->dllList = dllList;
533 addr->currentDll = dllList;
534 addr->lib = NULL;
535 *phFuncAddr = addr;
536 }
537 else
538 {
539 CryptMemFree(dllList);
540 SetLastError(ERROR_OUTOFMEMORY);
541 ret = FALSE;
542 }
543 }
544 }
545 else
546 {
547 SetLastError(ERROR_OUTOFMEMORY);
548 ret = FALSE;
549 }
550 }
551 }
552 if (addr)
553 {
554 if (!*addr->currentDll)
555 {
556 CryptFreeOIDFunctionAddress(*phFuncAddr, 0);
557 SetLastError(ERROR_FILE_NOT_FOUND);
558 *phFuncAddr = NULL;
559 ret = FALSE;
560 }
561 else
562 {
563 /* FIXME: as elsewhere, can't free until DllCanUnloadNow says
564 * it's possible, and should defer unloading for some time to
565 * avoid repeated LoadLibrary/FreeLibrary on the same dll.
566 */
567 FreeLibrary(addr->lib);
568 ret = CRYPT_GetFuncFromDll(addr->currentDll, set->name,
569 &addr->lib, ppvFuncAddr);
570 if (ret)
571 {
572 /* Move past the current DLL */
573 addr->currentDll += lstrlenW(addr->currentDll) + 1;
574 *phFuncAddr = addr;
575 }
576 else
577 {
578 CryptFreeOIDFunctionAddress(*phFuncAddr, 0);
579 SetLastError(ERROR_FILE_NOT_FOUND);
580 *phFuncAddr = NULL;
581 }
582 }
583 }
584 }
585 return ret;
586 }
587
588 /***********************************************************************
589 * CryptRegisterOIDFunction (CRYPT32.@)
590 *
591 * Register the DLL and the functions it uses to cover the combination
592 * of encoding type, functionname and OID.
593 *
594 * PARAMS
595 * dwEncodingType [I] Encoding type to be used.
596 * pszFuncName [I] Name of the function to be registered.
597 * pszOID [I] OID of the function (numeric or string).
598 * pwszDll [I] The DLL that is to be registered.
599 * pszOverrideFuncName [I] Name of the function in the DLL.
600 *
601 * RETURNS
602 * Success: TRUE.
603 * Failure: FALSE. (Look at GetLastError()).
604 *
605 * NOTES
606 * Registry errors are always reported via SetLastError().
607 */
608 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
609 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
610 {
611 LONG r;
612 HKEY hKey;
613 LPSTR szKey;
614
615 TRACE("(%x, %s, %s, %s, %s)\n", dwEncodingType, pszFuncName,
616 debugstr_a(pszOID), debugstr_w(pwszDll), pszOverrideFuncName);
617
618 /* Native does nothing pwszDll is NULL */
619 if (!pwszDll)
620 return TRUE;
621
622 /* I'm not matching MS bug for bug here, because I doubt any app depends on
623 * it: native "succeeds" if pszFuncName is NULL, but the nonsensical entry
624 * it creates would never be used.
625 */
626 if (!pszFuncName || !pszOID)
627 {
628 SetLastError(E_INVALIDARG);
629 return FALSE;
630 }
631
632 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
633 TRACE("Key name is %s\n", debugstr_a(szKey));
634
635 if (!szKey)
636 return FALSE;
637
638 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
639 CryptMemFree(szKey);
640
641 if (r != ERROR_SUCCESS) goto error_close_key;
642
643 /* write the values */
644 if (pszOverrideFuncName)
645 {
646 r = RegSetValueExA(hKey, "FuncName", 0, REG_SZ,
647 (const BYTE*)pszOverrideFuncName, lstrlenA(pszOverrideFuncName) + 1);
648 if (r != ERROR_SUCCESS) goto error_close_key;
649 }
650 r = RegSetValueExW(hKey, DllW, 0, REG_SZ, (const BYTE*) pwszDll,
651 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
652
653 error_close_key:
654
655 RegCloseKey(hKey);
656
657 if (r != ERROR_SUCCESS)
658 {
659 SetLastError(r);
660 return FALSE;
661 }
662
663 return TRUE;
664 }
665
666 /***********************************************************************
667 * CryptUnregisterOIDFunction (CRYPT32.@)
668 */
669 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
670 LPCSTR pszOID)
671 {
672 LPSTR szKey;
673 LONG rc;
674
675 TRACE("%x %s %s\n", dwEncodingType, debugstr_a(pszFuncName),
676 debugstr_a(pszOID));
677
678 if (!pszFuncName || !pszOID)
679 {
680 SetLastError(ERROR_INVALID_PARAMETER);
681 return FALSE;
682 }
683
684 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
685 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
686 CryptMemFree(szKey);
687 if (rc)
688 SetLastError(rc);
689 return rc ? FALSE : TRUE;
690 }
691
692 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
693 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
694 DWORD *pcbValueData)
695 {
696 LPSTR szKey;
697 LONG rc;
698 HKEY hKey;
699
700 TRACE("%x %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
701 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
702 pcbValueData);
703
704 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
705 return TRUE;
706
707 if (!pszFuncName || !pszOID || !pwszValueName)
708 {
709 SetLastError(ERROR_INVALID_PARAMETER);
710 return FALSE;
711 }
712
713 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
714 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
715 CryptMemFree(szKey);
716 if (rc)
717 SetLastError(rc);
718 else
719 {
720 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
721 pbValueData, pcbValueData);
722 if (rc)
723 SetLastError(rc);
724 RegCloseKey(hKey);
725 }
726 return rc ? FALSE : TRUE;
727 }
728
729 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
730 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
731 const BYTE *pbValueData, DWORD cbValueData)
732 {
733 LPSTR szKey;
734 LONG rc;
735 HKEY hKey;
736
737 TRACE("%x %s %s %s %d %p %d\n", dwEncodingType, debugstr_a(pszFuncName),
738 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
739 cbValueData);
740
741 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
742 return TRUE;
743
744 if (!pszFuncName || !pszOID || !pwszValueName)
745 {
746 SetLastError(ERROR_INVALID_PARAMETER);
747 return FALSE;
748 }
749
750 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
751 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
752 CryptMemFree(szKey);
753 if (rc)
754 SetLastError(rc);
755 else
756 {
757 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
758 cbValueData);
759 if (rc)
760 SetLastError(rc);
761 RegCloseKey(hKey);
762 }
763 return rc ? FALSE : TRUE;
764 }
765
766 static LPCWSTR CRYPT_FindStringInMultiString(LPCWSTR multi, LPCWSTR toFind)
767 {
768 LPCWSTR ret = NULL, ptr;
769
770 for (ptr = multi; ptr && *ptr && !ret; ptr += lstrlenW(ptr) + 1)
771 {
772 if (!lstrcmpiW(ptr, toFind))
773 ret = ptr;
774 }
775 return ret;
776 }
777
778 static DWORD CRYPT_GetMultiStringCharacterLen(LPCWSTR multi)
779 {
780 DWORD ret;
781
782 if (multi)
783 {
784 LPCWSTR ptr;
785
786 /* Count terminating empty string */
787 ret = 1;
788 for (ptr = multi; *ptr; ptr += lstrlenW(ptr) + 1)
789 ret += lstrlenW(ptr) + 1;
790 }
791 else
792 ret = 0;
793 return ret;
794 }
795
796 static LPWSTR CRYPT_AddStringToMultiString(LPWSTR multi, LPCWSTR toAdd,
797 DWORD index)
798 {
799 LPWSTR ret;
800
801 if (!multi)
802 {
803 /* FIXME: ignoring index, is that okay? */
804 ret = CryptMemAlloc((lstrlenW(toAdd) + 2) * sizeof(WCHAR));
805 if (ret)
806 {
807 /* copy string, including NULL terminator */
808 memcpy(ret, toAdd, (lstrlenW(toAdd) + 1) * sizeof(WCHAR));
809 /* add terminating empty string */
810 *(ret + lstrlenW(toAdd) + 1) = 0;
811 }
812 }
813 else
814 {
815 DWORD len = CRYPT_GetMultiStringCharacterLen(multi);
816
817 ret = CryptMemRealloc(multi, (len + lstrlenW(toAdd) + 1) *
818 sizeof(WCHAR));
819 if (ret)
820 {
821 LPWSTR spotToAdd;
822
823 if (index == CRYPT_REGISTER_LAST_INDEX)
824 spotToAdd = ret + len - 1;
825 else
826 {
827 DWORD i;
828
829 /* FIXME: if index is too large for the string, toAdd is
830 * added to the end. Is that okay?
831 */
832 for (i = 0, spotToAdd = ret; i < index && *spotToAdd;
833 spotToAdd += lstrlenW(spotToAdd) + 1)
834 ;
835 }
836 if (spotToAdd)
837 {
838 /* Copy existing string "right" */
839 memmove(spotToAdd + lstrlenW(toAdd) + 1, spotToAdd,
840 (len - (spotToAdd - ret)) * sizeof(WCHAR));
841 /* Copy new string */
842 memcpy(spotToAdd, toAdd, (lstrlenW(toAdd) + 1) * sizeof(WCHAR));
843 }
844 else
845 {
846 CryptMemFree(ret);
847 ret = NULL;
848 }
849 }
850 }
851 return ret;
852 }
853
854 static BOOL CRYPT_RemoveStringFromMultiString(LPWSTR multi, LPCWSTR toRemove)
855 {
856 LPWSTR spotToRemove = (LPWSTR)CRYPT_FindStringInMultiString(multi,
857 toRemove);
858 BOOL ret;
859
860 if (spotToRemove)
861 {
862 DWORD len = CRYPT_GetMultiStringCharacterLen(multi);
863
864 /* Copy remainder of string "left" */
865 memmove(spotToRemove, spotToRemove + lstrlenW(toRemove) + 1,
866 (len - (spotToRemove - multi)) * sizeof(WCHAR));
867 ret = TRUE;
868 }
869 else
870 {
871 SetLastError(ERROR_FILE_NOT_FOUND);
872 ret = FALSE;
873 }
874 return ret;
875 }
876
877 static BOOL CRYPT_GetDefaultOIDKey(DWORD dwEncodingType, LPCSTR pszFuncName,
878 PHKEY key)
879 {
880 LPSTR keyName;
881 LONG r;
882
883 keyName = CRYPT_GetKeyName(dwEncodingType, pszFuncName, "DEFAULT");
884 TRACE("Key name is %s\n", debugstr_a(keyName));
885
886 if (!keyName)
887 return FALSE;
888
889 r = RegCreateKeyExA(HKEY_LOCAL_MACHINE, keyName, 0, NULL, 0, KEY_ALL_ACCESS,
890 NULL, key, NULL);
891 CryptMemFree(keyName);
892 if (r != ERROR_SUCCESS)
893 {
894 SetLastError(r);
895 return FALSE;
896 }
897 return TRUE;
898 }
899
900 static LPWSTR CRYPT_GetDefaultOIDDlls(HKEY key)
901 {
902 LONG r;
903 DWORD type, size;
904 LPWSTR dlls;
905
906 r = RegQueryValueExW(key, DllW, NULL, &type, NULL, &size);
907 if (r == ERROR_SUCCESS && type == REG_MULTI_SZ)
908 {
909 dlls = CryptMemAlloc(size);
910 r = RegQueryValueExW(key, DllW, NULL, &type, (LPBYTE)dlls, &size);
911 if (r != ERROR_SUCCESS)
912 {
913 CryptMemFree(dlls);
914 dlls = NULL;
915 }
916 }
917 else
918 dlls = NULL;
919 return dlls;
920 }
921
922 static inline BOOL CRYPT_SetDefaultOIDDlls(HKEY key, LPCWSTR dlls)
923 {
924 DWORD len = CRYPT_GetMultiStringCharacterLen(dlls);
925 LONG r;
926
927 if ((r = RegSetValueExW(key, DllW, 0, REG_MULTI_SZ, (const BYTE *)dlls,
928 len * sizeof (WCHAR))))
929 SetLastError(r);
930 return r == ERROR_SUCCESS;
931 }
932
933 /***********************************************************************
934 * CryptRegisterDefaultOIDFunction (CRYPT32.@)
935 */
936 BOOL WINAPI CryptRegisterDefaultOIDFunction(DWORD dwEncodingType,
937 LPCSTR pszFuncName, DWORD dwIndex, LPCWSTR pwszDll)
938 {
939 HKEY key;
940 LPWSTR dlls;
941 BOOL ret = FALSE;
942
943 TRACE("(%x, %s, %d, %s)\n", dwEncodingType, debugstr_a(pszFuncName),
944 dwIndex, debugstr_w(pwszDll));
945
946 if (!pwszDll)
947 {
948 SetLastError(E_INVALIDARG);
949 return FALSE;
950 }
951
952 if (!CRYPT_GetDefaultOIDKey(dwEncodingType, pszFuncName, &key))
953 return FALSE;
954
955 dlls = CRYPT_GetDefaultOIDDlls(key);
956 if (CRYPT_FindStringInMultiString(dlls, pwszDll))
957 SetLastError(ERROR_FILE_EXISTS);
958 else
959 {
960 dlls = CRYPT_AddStringToMultiString(dlls, pwszDll, dwIndex);
961 if (dlls)
962 ret = CRYPT_SetDefaultOIDDlls(key, dlls);
963 }
964 CryptMemFree(dlls);
965 RegCloseKey(key);
966 return ret;
967 }
968
969 BOOL WINAPI CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType,
970 LPCSTR pszFuncName, LPCWSTR pwszDll)
971 {
972 HKEY key;
973 LPWSTR dlls;
974 BOOL ret;
975
976 TRACE("(%x, %s, %s)\n", dwEncodingType, debugstr_a(pszFuncName),
977 debugstr_w(pwszDll));
978
979 if (!pwszDll)
980 {
981 SetLastError(E_INVALIDARG);
982 return FALSE;
983 }
984
985 if (!CRYPT_GetDefaultOIDKey(dwEncodingType, pszFuncName, &key))
986 return FALSE;
987
988 dlls = CRYPT_GetDefaultOIDDlls(key);
989 if ((ret = CRYPT_RemoveStringFromMultiString(dlls, pwszDll)))
990 ret = CRYPT_SetDefaultOIDDlls(key, dlls);
991 CryptMemFree(dlls);
992 RegCloseKey(key);
993 return ret;
994 }
995
996 static void oid_init_localizednames(HINSTANCE hInstance)
997 {
998 int i;
999
1000 for(i = 0; i < sizeof(LocalizedKeys)/sizeof(LPCWSTR); i++)
1001 {
1002 LoadStringW(hInstance, IDS_LOCALIZEDNAME_ROOT+i, LocalizedNames[i], 256);
1003 }
1004 }
1005
1006 /********************************************************************
1007 * CryptFindLocalizedName (CRYPT32.@)
1008 */
1009 LPCWSTR WINAPI CryptFindLocalizedName(LPCWSTR pwszCryptName)
1010 {
1011 int i;
1012
1013 for(i = 0; i < sizeof(LocalizedKeys)/sizeof(LPCWSTR); i++)
1014 {
1015 if(!lstrcmpiW(LocalizedKeys[i], pwszCryptName))
1016 {
1017 return LocalizedNames[i];
1018 }
1019 }
1020
1021 FIXME("No name for: %s - stub\n",debugstr_w(pwszCryptName));
1022 return NULL;
1023 }
1024
1025 static CRITICAL_SECTION oidInfoCS;
1026 static CRITICAL_SECTION_DEBUG oidInfoCSDebug =
1027 {
1028 0, 0, &oidInfoCS,
1029 { &oidInfoCSDebug.ProcessLocksList, &oidInfoCSDebug.ProcessLocksList },
1030