2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2005 Juan Lang
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.
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.
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
25 #include "wine/debug.h"
26 #include "wine/list.h"
27 #include "crypt32_private.h"
29 WINE_DEFAULT_DEBUG_CHANNEL(crypt
);
31 static const WCHAR DllW
[] = { 'D','l','l',0 };
32 CRITICAL_SECTION funcSetCS
;
38 CRITICAL_SECTION cs
; /* protects functions */
39 struct list functions
;
46 CRYPT_OID_FUNC_ENTRY entry
;
50 void CRYPT_InitFunctionSets(void)
52 InitializeCriticalSection(&funcSetCS
);
56 void CRYPT_FreeFunctionSets(void)
58 struct OIDFunctionSet
*setCursor
, *setNext
;
60 LIST_FOR_EACH_ENTRY_SAFE(setCursor
, setNext
, &funcSets
,
61 struct OIDFunctionSet
, next
)
63 struct OIDFunction
*functionCursor
, *funcNext
;
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
)
71 list_remove(&functionCursor
->next
);
72 CryptMemFree(functionCursor
);
74 DeleteCriticalSection(&setCursor
->cs
);
76 DeleteCriticalSection(&funcSetCS
);
79 /* There is no free function associated with this; therefore, the sets are
80 * freed when crypt32.dll is unloaded.
82 HCRYPTOIDFUNCSET WINAPI
CryptInitOIDFunctionSet(LPCSTR pszFuncName
,
85 struct OIDFunctionSet
*cursor
, *ret
= NULL
;
87 TRACE("(%s, %lx)\n", debugstr_a(pszFuncName
), dwFlags
);
89 EnterCriticalSection(&funcSetCS
);
90 LIST_FOR_EACH_ENTRY(cursor
, &funcSets
, struct OIDFunctionSet
, next
)
92 if (!strcasecmp(pszFuncName
, cursor
->name
))
94 ret
= (HCRYPTOIDFUNCSET
)cursor
;
100 ret
= CryptMemAlloc(sizeof(struct OIDFunctionSet
));
103 memset(ret
, 0, sizeof(*ret
));
104 ret
->name
= CryptMemAlloc(strlen(pszFuncName
) + 1);
107 InitializeCriticalSection(&ret
->cs
);
108 list_init(&ret
->functions
);
109 strcpy(ret
->name
, pszFuncName
);
110 list_add_tail(&funcSets
, &ret
->next
);
119 LeaveCriticalSection(&funcSetCS
);
121 return (HCRYPTOIDFUNCSET
)ret
;
124 static char *CRYPT_GetKeyName(DWORD dwEncodingType
, LPCSTR pszFuncName
,
127 static const char szEncodingTypeFmt
[] =
128 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
130 char numericOID
[7]; /* enough for "#65535" */
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".
141 snprintf(numericOID
, sizeof(numericOID
), "#%d", LOWORD(pszOID
));
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.
152 len
= sizeof(szEncodingTypeFmt
) + lstrlenA(pszFuncName
) + lstrlenA(oid
);
153 szKey
= CryptMemAlloc(len
);
155 sprintf(szKey
, szEncodingTypeFmt
, dwEncodingType
, pszFuncName
, oid
);
159 BOOL WINAPI
CryptGetDefaultOIDDllList(HCRYPTOIDFUNCSET hFuncSet
,
160 DWORD dwEncodingType
, LPWSTR pwszDllList
, DWORD
*pcchDllList
)
163 struct OIDFunctionSet
*set
= (struct OIDFunctionSet
*)hFuncSet
;
168 TRACE("(%p, %ld, %p, %p)\n", hFuncSet
, dwEncodingType
, pwszDllList
,
171 keyName
= CRYPT_GetKeyName(dwEncodingType
, set
->name
, "DEFAULT");
172 rc
= RegCreateKeyExA(HKEY_LOCAL_MACHINE
, keyName
, 0, NULL
, 0,
173 KEY_READ
, NULL
, &key
, NULL
);
176 DWORD size
= *pcchDllList
* sizeof(WCHAR
);
178 rc
= RegQueryValueExW(key
, DllW
, NULL
, NULL
, (LPBYTE
)pwszDllList
,
181 *pcchDllList
= size
/ sizeof(WCHAR
);
184 /* No value, return an empty list */
196 CryptMemFree(keyName
);
201 BOOL WINAPI
CryptInstallOIDFunctionAddress(HMODULE hModule
,
202 DWORD dwEncodingType
, LPCSTR pszFuncName
, DWORD cFuncEntry
,
203 const CRYPT_OID_FUNC_ENTRY rgFuncEntry
[], DWORD dwFlags
)
206 struct OIDFunctionSet
*set
;
208 TRACE("(%p, %ld, %s, %ld, %p, %08lx)\n", hModule
, dwEncodingType
,
209 debugstr_a(pszFuncName
), cFuncEntry
, rgFuncEntry
, dwFlags
);
211 set
= (struct OIDFunctionSet
*)CryptInitOIDFunctionSet(pszFuncName
, 0);
216 EnterCriticalSection(&set
->cs
);
217 for (i
= 0; ret
&& i
< cFuncEntry
; i
++)
219 struct OIDFunction
*func
;
221 if (HIWORD(rgFuncEntry
[i
].pszOID
))
222 func
= CryptMemAlloc(sizeof(struct OIDFunction
)
223 + strlen(rgFuncEntry
[i
].pszOID
) + 1);
225 func
= CryptMemAlloc(sizeof(struct OIDFunction
));
228 func
->encoding
= dwEncodingType
;
229 if (HIWORD(rgFuncEntry
[i
].pszOID
))
231 func
->entry
.pszOID
= (LPSTR
)((LPBYTE
)func
+ sizeof(*func
));
232 strcpy((LPSTR
)func
->entry
.pszOID
, rgFuncEntry
[i
].pszOID
);
235 func
->entry
.pszOID
= rgFuncEntry
[i
].pszOID
;
236 func
->entry
.pvFuncAddr
= rgFuncEntry
[i
].pvFuncAddr
;
237 list_add_tail(&set
->functions
, &func
->next
);
242 LeaveCriticalSection(&set
->cs
);
249 static BOOL
CRYPT_GetFuncFromReg(DWORD dwEncodingType
, LPCSTR pszOID
,
250 LPCSTR szFuncName
, LPVOID
*ppvFuncAddr
, HCRYPTOIDFUNCADDR
*phFuncAddr
)
254 const char *funcName
;
258 keyName
= CRYPT_GetKeyName(dwEncodingType
, szFuncName
, pszOID
);
259 rc
= RegOpenKeyExA(HKEY_LOCAL_MACHINE
, keyName
, 0, KEY_READ
, &key
);
262 DWORD type
, size
= 0;
264 rc
= RegQueryValueExA(key
, "FuncName", NULL
, &type
, NULL
, &size
);
265 if (rc
== ERROR_MORE_DATA
&& type
== REG_SZ
)
267 funcName
= CryptMemAlloc(size
);
268 rc
= RegQueryValueExA(key
, "FuncName", NULL
, &type
,
269 (LPBYTE
)funcName
, &size
);
272 funcName
= szFuncName
;
273 rc
= RegQueryValueExW(key
, DllW
, NULL
, &type
, NULL
, &size
);
274 if (rc
== ERROR_MORE_DATA
&& type
== REG_SZ
)
276 LPWSTR dllName
= CryptMemAlloc(size
);
280 rc
= RegQueryValueExW(key
, DllW
, NULL
, NULL
,
281 (LPBYTE
)dllName
, &size
);
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.
290 lib
= LoadLibraryW(dllName
);
293 *ppvFuncAddr
= GetProcAddress(lib
, szFuncName
);
296 *phFuncAddr
= (HCRYPTOIDFUNCADDR
)lib
;
301 /* Unload the library, the caller doesn't want
302 * to unload it when the return value is NULL.
310 CryptMemFree(dllName
);
315 if (funcName
!= szFuncName
)
316 CryptMemFree((char *)funcName
);
321 CryptMemFree(keyName
);
325 BOOL WINAPI
CryptGetOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet
,
326 DWORD dwEncodingType
, LPCSTR pszOID
, DWORD dwFlags
, void **ppvFuncAddr
,
327 HCRYPTOIDFUNCADDR
*phFuncAddr
)
330 struct OIDFunctionSet
*set
= (struct OIDFunctionSet
*)hFuncSet
;
332 TRACE("(%p, %ld, %s, %08lx, %p, %p)\n", hFuncSet
, dwEncodingType
,
333 debugstr_a(pszOID
), dwFlags
, ppvFuncAddr
, phFuncAddr
);
336 if (!(dwFlags
& CRYPT_GET_INSTALLED_OID_FUNC_FLAG
))
338 struct OIDFunction
*function
;
340 EnterCriticalSection(&set
->cs
);
341 LIST_FOR_EACH_ENTRY(function
, &set
->functions
, struct OIDFunction
, next
)
343 if (function
->encoding
== dwEncodingType
)
347 if (HIWORD(function
->entry
.pszOID
&&
348 !strcasecmp(function
->entry
.pszOID
, pszOID
)))
350 *ppvFuncAddr
= function
->entry
.pvFuncAddr
;
351 *phFuncAddr
= NULL
; /* FIXME: what should it be? */
356 else if (function
->entry
.pszOID
== pszOID
)
358 *ppvFuncAddr
= function
->entry
.pvFuncAddr
;
359 *phFuncAddr
= NULL
; /* FIXME: what should it be? */
365 LeaveCriticalSection(&set
->cs
);
368 ret
= CRYPT_GetFuncFromReg(dwEncodingType
, pszOID
, set
->name
,
369 ppvFuncAddr
, phFuncAddr
);
373 BOOL WINAPI
CryptFreeOIDFunctionAddress(HCRYPTOIDFUNCADDR hFuncAddr
,
376 TRACE("(%p, %08lx)\n", hFuncAddr
, dwFlags
);
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.
382 FreeLibrary((HMODULE
)hFuncAddr
);
386 BOOL WINAPI
CryptRegisterDefaultOIDFunction(DWORD dwEncodingType
,
387 LPCSTR pszFuncName
, DWORD dwIndex
, LPCWSTR pwszDll
)
389 FIXME("(%lx,%s,%lx,%s) stub!\n", dwEncodingType
, pszFuncName
, dwIndex
,
390 debugstr_w(pwszDll
));
394 BOOL WINAPI
CryptUnregisterDefaultOIDFunction(DWORD dwEncodingType
,
395 LPCSTR pszFuncName
, LPCWSTR pwszDll
)
397 FIXME("(%lx %s %s): stub\n", dwEncodingType
, debugstr_a(pszFuncName
),
398 debugstr_w(pwszDll
));
402 BOOL WINAPI
CryptGetDefaultOIDFunctionAddress(HCRYPTOIDFUNCSET hFuncSet
,
403 DWORD dwEncodingType
, LPCWSTR pwszDll
, DWORD dwFlags
, void *ppvFuncAddr
,
404 HCRYPTOIDFUNCADDR
*phFuncAddr
)
406 FIXME("(%p, %ld, %s, %08lx, %p, %p): stub\n", hFuncSet
, dwEncodingType
,
407 debugstr_w(pwszDll
), dwFlags
, ppvFuncAddr
, phFuncAddr
);
411 BOOL WINAPI
CryptRegisterOIDFunction(DWORD dwEncodingType
, LPCSTR pszFuncName
,
412 LPCSTR pszOID
, LPCWSTR pwszDll
, LPCSTR pszOverrideFuncName
)
418 TRACE("(%lx, %s, %s, %s, %s)\n", dwEncodingType
, pszFuncName
, pszOID
,
419 debugstr_w(pwszDll
), pszOverrideFuncName
);
421 /* This only registers functions for encoding certs, not messages */
422 if (!GET_CERT_ENCODING_TYPE(dwEncodingType
))
425 /* Native does nothing pwszDll is NULL */
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.
433 if (!pszFuncName
|| !pszOID
)
435 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER
));
439 szKey
= CRYPT_GetKeyName(dwEncodingType
, pszFuncName
, pszOID
);
440 TRACE("Key name is %s\n", debugstr_a(szKey
));
445 r
= RegCreateKeyA(HKEY_LOCAL_MACHINE
, szKey
, &hKey
);
447 if(r
!= ERROR_SUCCESS
)
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
));
461 BOOL WINAPI
CryptUnregisterOIDFunction(DWORD dwEncodingType
, LPCSTR pszFuncName
,
467 TRACE("%lx %s %s\n", dwEncodingType
, pszFuncName
, pszOID
);
469 if (!GET_CERT_ENCODING_TYPE(dwEncodingType
))
472 if (!pszFuncName
|| !pszOID
)
474 SetLastError(ERROR_INVALID_PARAMETER
);
478 szKey
= CRYPT_GetKeyName(dwEncodingType
, pszFuncName
, pszOID
);
479 rc
= RegDeleteKeyA(HKEY_LOCAL_MACHINE
, szKey
);
483 return rc
? FALSE
: TRUE
;
486 BOOL WINAPI
CryptGetOIDFunctionValue(DWORD dwEncodingType
, LPCSTR pszFuncName
,
487 LPCSTR pszOID
, LPCWSTR pwszValueName
, DWORD
*pdwValueType
, BYTE
*pbValueData
,
494 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType
, debugstr_a(pszFuncName
),
495 debugstr_a(pszOID
), debugstr_w(pwszValueName
), pdwValueType
, pbValueData
,
498 if (!GET_CERT_ENCODING_TYPE(dwEncodingType
))
501 if (!pszFuncName
|| !pszOID
|| !pwszValueName
)
503 SetLastError(ERROR_INVALID_PARAMETER
);
507 szKey
= CRYPT_GetKeyName(dwEncodingType
, pszFuncName
, pszOID
);
508 rc
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, szKey
, &hKey
);
514 rc
= RegQueryValueExW(hKey
, pwszValueName
, NULL
, pdwValueType
,
515 pbValueData
, pcbValueData
);
520 return rc
? FALSE
: TRUE
;
523 BOOL WINAPI
CryptSetOIDFunctionValue(DWORD dwEncodingType
, LPCSTR pszFuncName
,
524 LPCSTR pszOID
, LPCWSTR pwszValueName
, DWORD dwValueType
,
525 const BYTE
*pbValueData
, DWORD cbValueData
)
531 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType
, debugstr_a(pszFuncName
),
532 debugstr_a(pszOID
), debugstr_w(pwszValueName
), dwValueType
, pbValueData
,
535 if (!GET_CERT_ENCODING_TYPE(dwEncodingType
))
538 if (!pszFuncName
|| !pszOID
|| !pwszValueName
)
540 SetLastError(ERROR_INVALID_PARAMETER
);
544 szKey
= CRYPT_GetKeyName(dwEncodingType
, pszFuncName
, pszOID
);
545 rc
= RegOpenKeyA(HKEY_LOCAL_MACHINE
, szKey
, &hKey
);
551 rc
= RegSetValueExW(hKey
, pwszValueName
, 0, dwValueType
, pbValueData
,
557 return rc
? FALSE
: TRUE
;