Temp hack to clean up .def files and hopefully avoid more bug
[wine] / dlls / crypt32 / encode.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 <stdarg.h>
20 #include <stdio.h>
21 #include "windef.h"
22 #include "winbase.h"
23 #include "wincrypt.h"
24 #include "winreg.h"
25 #include "snmp.h"
26 #include "wine/debug.h"
27
28 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
29
30 static const WCHAR szDllName[] = { 'D','l','l',0 };
31
32 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
33  LPCSTR pszOID)
34 {
35     static const char szEncodingTypeFmt[] =
36      "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
37     UINT len;
38     char numericOID[7]; /* enough for "#65535" */
39     const char *oid;
40     LPSTR szKey;
41
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".
46      */
47     if (!HIWORD(pszOID))
48     {
49         snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
50         oid = numericOID;
51     }
52     else
53         oid = pszOID;
54
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.
59      */
60     len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
61     szKey = HeapAlloc(GetProcessHeap(), 0, len);
62     if (szKey)
63         sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
64     return szKey;
65 }
66
67 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
68                   LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
69 {
70     LONG r;
71     HKEY hKey;
72     LPSTR szKey;
73
74     TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
75           debugstr_w(pwszDll), pszOverrideFuncName);
76
77     /* This only registers functions for encoding certs, not messages */
78     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
79         return TRUE;
80
81     /* Native does nothing pwszDll is NULL */
82     if (!pwszDll)
83         return TRUE;
84
85     /* I'm not matching MS bug for bug here, because I doubt any app depends on
86      * it:
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.
91      */
92     if (!pszFuncName || !pszOID)
93     {
94         SetLastError(ERROR_INVALID_PARAMETER);
95         return FALSE;
96     }
97
98     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
99     TRACE("Key name is %s\n", debugstr_a(szKey));
100
101     if (!szKey)
102         return FALSE;
103
104     r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
105     HeapFree(GetProcessHeap(), 0, szKey);
106     if(r != ERROR_SUCCESS)
107         return FALSE;
108
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));
115
116     RegCloseKey(hKey);
117     return TRUE;
118 }
119
120 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
121  LPCSTR pszOID)
122 {
123     LPSTR szKey;
124     LONG rc;
125
126     TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
127
128     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
129         return TRUE;
130
131     if (!pszFuncName || !pszOID)
132     {
133         SetLastError(ERROR_INVALID_PARAMETER);
134         return FALSE;
135     }
136
137     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
138     rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
139     HeapFree(GetProcessHeap(), 0, szKey);
140     if (rc)
141         SetLastError(rc);
142     return rc ? FALSE : TRUE;
143 }
144
145 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
146  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
147  DWORD *pcbValueData)
148 {
149     LPSTR szKey;
150     LONG rc;
151     HKEY hKey;
152
153     TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
154      debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
155      pcbValueData);
156
157     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
158         return TRUE;
159
160     if (!pszFuncName || !pszOID || !pwszValueName)
161     {
162         SetLastError(ERROR_INVALID_PARAMETER);
163         return FALSE;
164     }
165
166     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
167     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
168     HeapFree(GetProcessHeap(), 0, szKey);
169     if (rc)
170         SetLastError(rc);
171     else
172     {
173         rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
174          pbValueData, pcbValueData);
175         if (rc)
176             SetLastError(rc);
177         RegCloseKey(hKey);
178     }
179     return rc ? FALSE : TRUE;
180 }
181
182 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
183  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
184  const BYTE *pbValueData, DWORD cbValueData)
185 {
186     LPSTR szKey;
187     LONG rc;
188     HKEY hKey;
189
190     TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
191      debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
192      cbValueData);
193
194     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
195         return TRUE;
196
197     if (!pszFuncName || !pszOID || !pwszValueName)
198     {
199         SetLastError(ERROR_INVALID_PARAMETER);
200         return FALSE;
201     }
202
203     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
204     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
205     HeapFree(GetProcessHeap(), 0, szKey);
206     if (rc)
207         SetLastError(rc);
208     else
209     {
210         rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
211          cbValueData);
212         if (rc)
213             SetLastError(rc);
214         RegCloseKey(hKey);
215     }
216     return rc ? FALSE : TRUE;
217 }
218
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.
223  */
224 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
225  LPCSTR szFuncName, HMODULE *lib)
226 {
227     void *ret = NULL;
228     char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
229      lpszStructType);
230     const char *funcName;
231     long r;
232     HKEY hKey;
233     DWORD type, size = 0;
234
235     *lib = NULL;
236     r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
237     HeapFree(GetProcessHeap(), 0, szKey);
238     if(r != ERROR_SUCCESS)
239         return NULL;
240
241     RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
242     if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
243     {
244         funcName = HeapAlloc(GetProcessHeap(), 0, size);
245         RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
246          &size);
247     }
248     else
249         funcName = szFuncName;
250     RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
251     if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
252     {
253         LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
254
255         RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
256          &size);
257         *lib = LoadLibraryW(dllName);
258         if (*lib)
259         {
260              ret = GetProcAddress(*lib, funcName);
261              if (!ret)
262              {
263                  /* Unload the library, the caller doesn't want to unload it
264                   * when the return value is NULL.
265                   */
266                  FreeLibrary(*lib);
267                  *lib = NULL;
268              }
269         }
270         HeapFree(GetProcessHeap(), 0, dllName);
271     }
272     if (funcName != szFuncName)
273         HeapFree(GetProcessHeap(), 0, (char *)funcName);
274     return ret;
275 }
276
277 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
278  BYTE *, DWORD *);
279
280 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
281  const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
282 {
283     BOOL ret = FALSE;
284     HMODULE lib;
285     CryptEncodeObjectFunc pCryptEncodeObject;
286
287     TRACE("(0x%08lx, %s, %p, %p, %p)\n",
288      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
289      "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
290
291     if (!pbEncoded && !pcbEncoded)
292     {
293         SetLastError(ERROR_INVALID_PARAMETER);
294         return FALSE;
295     }
296
297     /* Try registered DLL first.. */
298     pCryptEncodeObject =
299      (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
300      lpszStructType, "CryptEncodeObject", &lib);
301     if (pCryptEncodeObject)
302     {
303         ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
304          pvStructInfo, pbEncoded, pcbEncoded);
305         FreeLibrary(lib);
306     }
307     else
308     {
309         /* If not, use CryptEncodeObjectEx */
310         ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
311          pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
312     }
313     return ret;
314 }
315
316 static BOOL CRYPT_EncodeInt(DWORD dwCertEncodingType, const void *pvStructInfo,
317  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
318  DWORD *pcbEncoded)
319 {
320     INT val, i;
321     BYTE significantBytes, padByte = 0, bytesNeeded;
322     BOOL neg = FALSE, pad = FALSE;
323
324     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING &&
325      (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
326     {
327         SetLastError(ERROR_FILE_NOT_FOUND);
328         return FALSE;
329     }
330     if (!pvStructInfo)
331     {
332         SetLastError(ERROR_INVALID_PARAMETER);
333         return FALSE;
334     }
335
336     memcpy(&val, pvStructInfo, sizeof(val));
337     /* Count the number of significant bytes.  Temporarily swap sign for
338      * negatives so I count the minimum number of bytes.
339      */
340     if (val < 0)
341     {
342         neg = TRUE;
343         val = -val;
344     }
345     for (significantBytes = sizeof(val); !(val & 0xff000000);
346      val <<= 8, significantBytes--)
347         ;
348     if (neg)
349     {
350         val = -val;
351         if ((val & 0xff000000) < 0x80000000)
352         {
353             padByte = 0xff;
354             pad = TRUE;
355         }
356     }
357     else if ((val & 0xff000000) > 0x7f000000)
358     {
359         padByte = 0;
360         pad = TRUE;
361     }
362     bytesNeeded = 2 + significantBytes;
363     if (pad)
364         bytesNeeded++;
365     if (!pbEncoded || bytesNeeded > *pcbEncoded)
366     {
367         *pcbEncoded = bytesNeeded;
368         SetLastError(ERROR_MORE_DATA);
369         return FALSE;
370     }
371     if (!pbEncoded)
372     {
373         SetLastError(ERROR_INVALID_PARAMETER);
374         return FALSE;
375     }
376     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
377     {
378         if (pEncodePara && pEncodePara->pfnAlloc)
379             *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
380         else
381             *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
382         if (!*(BYTE **)pbEncoded)
383             return FALSE;
384         pbEncoded = *(BYTE **)pbEncoded;
385     }
386     *pbEncoded++ = ASN_INTEGER;
387     if (pad)
388     {
389         *pbEncoded++ = significantBytes + 1;
390         *pbEncoded++ = padByte;
391     }
392     else
393         *pbEncoded++ = significantBytes;
394     for (i = 0; i < significantBytes; i++, val <<= 8)
395         *(pbEncoded + i) = (BYTE)((val & 0xff000000) >> 24);
396     return TRUE;
397 }
398
399 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
400  DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
401
402 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
403  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
404  BYTE *pbEncoded, DWORD *pcbEncoded)
405 {
406     BOOL ret = FALSE, encoded = FALSE;
407
408     TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p): semi-stub\n",
409      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
410      "(integer value)", pvStructInfo, dwFlags, pEncodePara, pbEncoded,
411      pcbEncoded);
412
413     if (!pbEncoded && !pcbEncoded)
414     {
415         SetLastError(ERROR_INVALID_PARAMETER);
416         return FALSE;
417     }
418
419     if (!HIWORD(lpszStructType))
420     {
421         switch (LOWORD(lpszStructType))
422         {
423         case (WORD)X509_INTEGER:
424             ret = CRYPT_EncodeInt(dwCertEncodingType, pvStructInfo, dwFlags,
425              pEncodePara, pbEncoded, pcbEncoded);
426             break;
427         default:
428             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
429         }
430     }
431     if (!encoded)
432     {
433         HMODULE lib;
434         CryptEncodeObjectExFunc pCryptEncodeObjectEx =
435          (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
436          lpszStructType, "CryptEncodeObjectEx", &lib);
437
438         if (pCryptEncodeObjectEx)
439         {
440             ret = pCryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
441              pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
442             FreeLibrary(lib);
443         }
444     }
445     return ret;
446 }
447
448 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
449  DWORD, DWORD, void *, DWORD *);
450
451 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
452  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
453  DWORD *pcbStructInfo)
454 {
455     BOOL ret = FALSE;
456     HMODULE lib;
457     CryptDecodeObjectFunc pCryptDecodeObject;
458
459     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
460      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
461      "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
462      pcbStructInfo);
463
464     if (!pvStructInfo && !pcbStructInfo)
465     {
466         SetLastError(ERROR_INVALID_PARAMETER);
467         return FALSE;
468     }
469
470     /* Try registered DLL first.. */
471     pCryptDecodeObject =
472      (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
473      lpszStructType, "CryptDecodeObject", &lib);
474     if (pCryptDecodeObject)
475     {
476         ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
477          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
478         FreeLibrary(lib);
479     }
480     else
481     {
482         /* If not, use CryptDecodeObjectEx */
483         ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
484          cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
485     }
486     return ret;
487 }
488
489 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
490  DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
491
492 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
493  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
494  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
495 {
496     BOOL ret = FALSE, decoded = FALSE;
497
498     FIXME("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p): stub\n",
499      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
500      "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
501      pvStructInfo, pcbStructInfo);
502
503     if (!pvStructInfo && !pcbStructInfo)
504     {
505         SetLastError(ERROR_INVALID_PARAMETER);
506         return FALSE;
507     }
508
509     if (!HIWORD(lpszStructType))
510     {
511         switch (LOWORD(lpszStructType))
512         {
513         default:
514             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
515         }
516     }
517     if (!decoded)
518     {
519         HMODULE lib;
520         CryptDecodeObjectExFunc pCryptDecodeObjectEx =
521          (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
522          lpszStructType, "CryptDecodeObjectEx", &lib);
523
524         if (pCryptDecodeObjectEx)
525         {
526             ret = pCryptDecodeObjectEx(dwCertEncodingType, lpszStructType,
527              pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
528              pcbStructInfo);
529             FreeLibrary(lib);
530         }
531     }
532     return ret;
533 }