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
26 #include "wine/debug.h"
28 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
30 static const WCHAR szDllName[] = { 'D','l','l',0 };
32 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
35 static const char szEncodingTypeFmt[] =
36 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
38 char numericOID[7]; /* enough for "#65535" */
42 /* MSDN says the encoding type is a mask, but it isn't treated that way.
43 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
44 * "EncodingType 2" would be expected if it were a mask. Instead native
45 * stores values in "EncodingType 3".
49 snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
55 /* This is enough: the lengths of the two string parameters are explicitly
56 * counted, and we need up to five additional characters for the encoding
57 * type. These are covered by the "%d", "%s", and "%s" characters in the
58 * format specifier that are removed by sprintf.
60 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
61 szKey = HeapAlloc(GetProcessHeap(), 0, len);
63 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
67 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
68 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
74 TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
75 debugstr_w(pwszDll), pszOverrideFuncName);
77 /* This only registers functions for encoding certs, not messages */
78 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
81 /* Native does nothing pwszDll is NULL */
85 /* I'm not matching MS bug for bug here, because I doubt any app depends on
87 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
88 * it creates would never be used
89 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
90 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
92 if (!pszFuncName || !pszOID)
94 SetLastError(ERROR_INVALID_PARAMETER);
98 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
99 TRACE("Key name is %s\n", debugstr_a(szKey));
104 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
105 HeapFree(GetProcessHeap(), 0, szKey);
106 if(r != ERROR_SUCCESS)
109 /* write the values */
110 if (pszOverrideFuncName)
111 RegSetValueExA(hKey, "FuncName", 0, REG_SZ, pszOverrideFuncName,
112 lstrlenA(pszOverrideFuncName) + 1);
113 RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
114 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
120 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
126 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
128 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
131 if (!pszFuncName || !pszOID)
133 SetLastError(ERROR_INVALID_PARAMETER);
137 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
138 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
139 HeapFree(GetProcessHeap(), 0, szKey);
142 return rc ? FALSE : TRUE;
145 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
146 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
153 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
154 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
157 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
160 if (!pszFuncName || !pszOID || !pwszValueName)
162 SetLastError(ERROR_INVALID_PARAMETER);
166 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
167 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
168 HeapFree(GetProcessHeap(), 0, szKey);
173 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
174 pbValueData, pcbValueData);
179 return rc ? FALSE : TRUE;
182 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
183 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
184 const BYTE *pbValueData, DWORD cbValueData)
190 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
191 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
194 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
197 if (!pszFuncName || !pszOID || !pwszValueName)
199 SetLastError(ERROR_INVALID_PARAMETER);
203 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
204 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
205 HeapFree(GetProcessHeap(), 0, szKey);
210 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
216 return rc ? FALSE : TRUE;
219 /* Gets the registered function named szFuncName for dwCertEncodingType and
220 * lpszStructType, or NULL if one could not be found. *lib will be set to the
221 * handle of the module it's in, or NULL if no module was loaded. If the
222 * return value is NULL, *lib will also be NULL, to simplify error handling.
224 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
225 LPCSTR szFuncName, HMODULE *lib)
228 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
230 const char *funcName;
233 DWORD type, size = 0;
236 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
237 HeapFree(GetProcessHeap(), 0, szKey);
238 if(r != ERROR_SUCCESS)
241 RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
242 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
244 funcName = HeapAlloc(GetProcessHeap(), 0, size);
245 RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
249 funcName = szFuncName;
250 RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
251 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
253 LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
255 RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
257 *lib = LoadLibraryW(dllName);
260 ret = GetProcAddress(*lib, funcName);
263 /* Unload the library, the caller doesn't want to unload it
264 * when the return value is NULL.
270 HeapFree(GetProcessHeap(), 0, dllName);
272 if (funcName != szFuncName)
273 HeapFree(GetProcessHeap(), 0, (char *)funcName);
277 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
280 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
281 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
285 CryptEncodeObjectFunc pCryptEncodeObject;
287 TRACE("(0x%08lx, %s, %p, %p, %p)\n",
288 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
289 "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
291 if (!pbEncoded && !pcbEncoded)
293 SetLastError(ERROR_INVALID_PARAMETER);
297 /* Try registered DLL first.. */
299 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
300 lpszStructType, "CryptEncodeObject", &lib);
301 if (pCryptEncodeObject)
303 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
304 pvStructInfo, pbEncoded, pcbEncoded);
309 /* If not, use CryptEncodeObjectEx */
310 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
311 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
316 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
317 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
318 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
321 BYTE significantBytes, padByte = 0, bytesNeeded;
322 BOOL neg = FALSE, pad = FALSE;
326 SetLastError(ERROR_INVALID_PARAMETER);
330 memcpy(&val, pvStructInfo, sizeof(val));
331 /* Count the number of significant bytes. Temporarily swap sign for
332 * negatives so I count the minimum number of bytes.
339 for (significantBytes = sizeof(val); !(val & 0xff000000);
340 val <<= 8, significantBytes--)
345 if ((val & 0xff000000) < 0x80000000)
351 else if ((val & 0xff000000) > 0x7f000000)
356 bytesNeeded = 2 + significantBytes;
359 if (!pbEncoded || bytesNeeded > *pcbEncoded)
361 *pcbEncoded = bytesNeeded;
362 SetLastError(ERROR_MORE_DATA);
367 SetLastError(ERROR_INVALID_PARAMETER);
370 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
372 if (pEncodePara && pEncodePara->pfnAlloc)
373 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
375 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
376 if (!*(BYTE **)pbEncoded)
378 pbEncoded = *(BYTE **)pbEncoded;
380 *pbEncoded++ = ASN_INTEGER;
383 *pbEncoded++ = significantBytes + 1;
384 *pbEncoded++ = padByte;
387 *pbEncoded++ = significantBytes;
388 for (i = 0; i < significantBytes; i++, val <<= 8)
389 *(pbEncoded + i) = (BYTE)((val & 0xff000000) >> 24);
393 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
394 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
396 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
397 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
398 BYTE *pbEncoded, DWORD *pcbEncoded)
402 CryptEncodeObjectExFunc encodeFunc = NULL;
404 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p): semi-stub\n",
405 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
406 "(integer value)", pvStructInfo, dwFlags, pEncodePara, pbEncoded,
409 if (!pbEncoded && !pcbEncoded)
411 SetLastError(ERROR_INVALID_PARAMETER);
415 if (!HIWORD(lpszStructType))
417 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) == X509_ASN_ENCODING
418 || (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) ==
421 switch (LOWORD(lpszStructType))
423 case (WORD)X509_INTEGER:
424 encodeFunc = CRYPT_AsnEncodeInt;
427 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
432 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
433 lpszStructType, "CryptEncodeObjectEx", &lib);
435 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
436 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
438 SetLastError(ERROR_FILE_NOT_FOUND);
444 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
445 DWORD, DWORD, void *, DWORD *);
447 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
448 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
449 DWORD *pcbStructInfo)
453 CryptDecodeObjectFunc pCryptDecodeObject;
455 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
456 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
457 "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
460 if (!pvStructInfo && !pcbStructInfo)
462 SetLastError(ERROR_INVALID_PARAMETER);
466 /* Try registered DLL first.. */
468 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
469 lpszStructType, "CryptDecodeObject", &lib);
470 if (pCryptDecodeObject)
472 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
473 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
478 /* If not, use CryptDecodeObjectEx */
479 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
480 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
485 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
486 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
487 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
492 if (!pbEncoded || !cbEncoded)
494 SetLastError(ERROR_INVALID_PARAMETER);
499 *pcbStructInfo = sizeof(int);
500 SetLastError(ERROR_MORE_DATA);
503 if (pbEncoded[0] != ASN_INTEGER)
505 SetLastError(CRYPT_E_ASN1_BADTAG);
508 if (pbEncoded[1] == 0)
510 SetLastError(CRYPT_E_ASN1_CORRUPT);
513 if (pbEncoded[1] > sizeof(int))
515 SetLastError(CRYPT_E_ASN1_LARGE);
518 if (pbEncoded[2] & 0x80)
520 /* initialize to a negative value to sign-extend */
525 for (i = 0; i < pbEncoded[1]; i++)
528 val |= pbEncoded[2 + i];
530 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
532 if (pDecodePara && pDecodePara->pfnAlloc)
533 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(sizeof(int));
535 *(BYTE **)pvStructInfo = LocalAlloc(0, sizeof(int));
536 if (!*(BYTE **)pvStructInfo)
538 memcpy(*(BYTE **)pvStructInfo, &val, sizeof(int));
541 else if (*pcbStructInfo < sizeof(int))
543 *pcbStructInfo = sizeof(int);
544 SetLastError(ERROR_MORE_DATA);
549 *pcbStructInfo = sizeof(int);
550 memcpy(pvStructInfo, &val, sizeof(int));
556 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
557 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
559 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
560 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
561 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
565 CryptDecodeObjectExFunc decodeFunc = NULL;
567 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p): semi-stub\n",
568 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
569 "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
570 pvStructInfo, pcbStructInfo);
572 if (!pvStructInfo && !pcbStructInfo)
574 SetLastError(ERROR_INVALID_PARAMETER);
578 if (!HIWORD(lpszStructType))
580 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) == X509_ASN_ENCODING
581 || (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) ==
584 switch (LOWORD(lpszStructType))
586 case (WORD)X509_INTEGER:
587 decodeFunc = CRYPT_AsnDecodeInt;
590 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
595 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
596 lpszStructType, "CryptDecodeObjectEx", &lib);
598 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
599 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
601 SetLastError(ERROR_FILE_NOT_FOUND);