Cryp{En|De}codeObjectEx should return success if the input buffer is
[wine/wine64.git] / dlls / crypt32 / encode.c
blob0c2f2c03afac9d2f3c950a6bdb38847fb0fdf9bd
1 /*
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
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"
28 /* a few asn.1 tags we need */
29 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
30 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
32 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
34 static const WCHAR szDllName[] = { 'D','l','l',0 };
36 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
37 LPCSTR pszOID)
39 static const char szEncodingTypeFmt[] =
40 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
41 UINT len;
42 char numericOID[7]; /* enough for "#65535" */
43 const char *oid;
44 LPSTR szKey;
46 /* MSDN says the encoding type is a mask, but it isn't treated that way.
47 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
48 * "EncodingType 2" would be expected if it were a mask. Instead native
49 * stores values in "EncodingType 3".
51 if (!HIWORD(pszOID))
53 snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
54 oid = numericOID;
56 else
57 oid = pszOID;
59 /* This is enough: the lengths of the two string parameters are explicitly
60 * counted, and we need up to five additional characters for the encoding
61 * type. These are covered by the "%d", "%s", and "%s" characters in the
62 * format specifier that are removed by sprintf.
64 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
65 szKey = HeapAlloc(GetProcessHeap(), 0, len);
66 if (szKey)
67 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
68 return szKey;
71 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
72 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
74 LONG r;
75 HKEY hKey;
76 LPSTR szKey;
78 TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
79 debugstr_w(pwszDll), pszOverrideFuncName);
81 /* This only registers functions for encoding certs, not messages */
82 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
83 return TRUE;
85 /* Native does nothing pwszDll is NULL */
86 if (!pwszDll)
87 return TRUE;
89 /* I'm not matching MS bug for bug here, because I doubt any app depends on
90 * it:
91 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
92 * it creates would never be used
93 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
94 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
96 if (!pszFuncName || !pszOID)
98 SetLastError(ERROR_INVALID_PARAMETER);
99 return FALSE;
102 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
103 TRACE("Key name is %s\n", debugstr_a(szKey));
105 if (!szKey)
106 return FALSE;
108 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
109 HeapFree(GetProcessHeap(), 0, szKey);
110 if(r != ERROR_SUCCESS)
111 return FALSE;
113 /* write the values */
114 if (pszOverrideFuncName)
115 RegSetValueExA(hKey, "FuncName", 0, REG_SZ, pszOverrideFuncName,
116 lstrlenA(pszOverrideFuncName) + 1);
117 RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
118 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
120 RegCloseKey(hKey);
121 return TRUE;
124 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
125 LPCSTR pszOID)
127 LPSTR szKey;
128 LONG rc;
130 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
132 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
133 return TRUE;
135 if (!pszFuncName || !pszOID)
137 SetLastError(ERROR_INVALID_PARAMETER);
138 return FALSE;
141 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
142 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
143 HeapFree(GetProcessHeap(), 0, szKey);
144 if (rc)
145 SetLastError(rc);
146 return rc ? FALSE : TRUE;
149 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
150 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
151 DWORD *pcbValueData)
153 LPSTR szKey;
154 LONG rc;
155 HKEY hKey;
157 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
158 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
159 pcbValueData);
161 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
162 return TRUE;
164 if (!pszFuncName || !pszOID || !pwszValueName)
166 SetLastError(ERROR_INVALID_PARAMETER);
167 return FALSE;
170 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
171 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
172 HeapFree(GetProcessHeap(), 0, szKey);
173 if (rc)
174 SetLastError(rc);
175 else
177 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
178 pbValueData, pcbValueData);
179 if (rc)
180 SetLastError(rc);
181 RegCloseKey(hKey);
183 return rc ? FALSE : TRUE;
186 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
187 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
188 const BYTE *pbValueData, DWORD cbValueData)
190 LPSTR szKey;
191 LONG rc;
192 HKEY hKey;
194 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
195 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
196 cbValueData);
198 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
199 return TRUE;
201 if (!pszFuncName || !pszOID || !pwszValueName)
203 SetLastError(ERROR_INVALID_PARAMETER);
204 return FALSE;
207 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
208 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
209 HeapFree(GetProcessHeap(), 0, szKey);
210 if (rc)
211 SetLastError(rc);
212 else
214 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
215 cbValueData);
216 if (rc)
217 SetLastError(rc);
218 RegCloseKey(hKey);
220 return rc ? FALSE : TRUE;
223 /* Gets the registered function named szFuncName for dwCertEncodingType and
224 * lpszStructType, or NULL if one could not be found. *lib will be set to the
225 * handle of the module it's in, or NULL if no module was loaded. If the
226 * return value is NULL, *lib will also be NULL, to simplify error handling.
228 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
229 LPCSTR szFuncName, HMODULE *lib)
231 void *ret = NULL;
232 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
233 lpszStructType);
234 const char *funcName;
235 long r;
236 HKEY hKey;
237 DWORD type, size = 0;
239 *lib = NULL;
240 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
241 HeapFree(GetProcessHeap(), 0, szKey);
242 if(r != ERROR_SUCCESS)
243 return NULL;
245 RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
246 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
248 funcName = HeapAlloc(GetProcessHeap(), 0, size);
249 RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
250 &size);
252 else
253 funcName = szFuncName;
254 RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
255 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
257 LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
259 RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
260 &size);
261 *lib = LoadLibraryW(dllName);
262 if (*lib)
264 ret = GetProcAddress(*lib, funcName);
265 if (!ret)
267 /* Unload the library, the caller doesn't want to unload it
268 * when the return value is NULL.
270 FreeLibrary(*lib);
271 *lib = NULL;
274 HeapFree(GetProcessHeap(), 0, dllName);
276 if (funcName != szFuncName)
277 HeapFree(GetProcessHeap(), 0, (char *)funcName);
278 return ret;
281 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
282 BYTE *, DWORD *);
284 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
285 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
287 BOOL ret = FALSE;
288 HMODULE lib;
289 CryptEncodeObjectFunc pCryptEncodeObject;
291 TRACE("(0x%08lx, %s, %p, %p, %p)\n",
292 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
293 "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
295 if (!pbEncoded && !pcbEncoded)
297 SetLastError(ERROR_INVALID_PARAMETER);
298 return FALSE;
301 /* Try registered DLL first.. */
302 pCryptEncodeObject =
303 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
304 lpszStructType, "CryptEncodeObject", &lib);
305 if (pCryptEncodeObject)
307 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
308 pvStructInfo, pbEncoded, pcbEncoded);
309 FreeLibrary(lib);
311 else
313 /* If not, use CryptEncodeObjectEx */
314 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
315 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
317 return ret;
320 /* Helper function to check *pcbEncoded, set it to the required size, and
321 * optionally to allocate memory. Assumes pbEncoded is not NULL.
322 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
323 * pointer to the newly allocated memory.
325 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
326 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
327 DWORD bytesNeeded)
329 BOOL ret = TRUE;
331 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
333 if (pEncodePara && pEncodePara->pfnAlloc)
334 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
335 else
336 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
337 if (!*(BYTE **)pbEncoded)
338 ret = FALSE;
340 else if (bytesNeeded > *pcbEncoded)
342 *pcbEncoded = bytesNeeded;
343 SetLastError(ERROR_MORE_DATA);
344 ret = FALSE;
346 return ret;
349 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
350 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
351 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
353 INT val, i;
354 BYTE significantBytes, padByte = 0, bytesNeeded;
355 BOOL neg = FALSE, pad = FALSE;
357 if (!pvStructInfo)
359 SetLastError(ERROR_INVALID_PARAMETER);
360 return FALSE;
363 memcpy(&val, pvStructInfo, sizeof(val));
364 /* Count the number of significant bytes. Temporarily swap sign for
365 * negatives so I count the minimum number of bytes.
367 if (val < 0)
369 neg = TRUE;
370 val = -val;
372 for (significantBytes = sizeof(val); !(val & 0xff000000);
373 val <<= 8, significantBytes--)
375 if (neg)
377 val = -val;
378 if ((val & 0xff000000) < 0x80000000)
380 padByte = 0xff;
381 pad = TRUE;
384 else if ((val & 0xff000000) > 0x7f000000)
386 padByte = 0;
387 pad = TRUE;
389 bytesNeeded = 2 + significantBytes;
390 if (pad)
391 bytesNeeded++;
392 if (!pbEncoded)
394 *pcbEncoded = bytesNeeded;
395 return TRUE;
397 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
398 bytesNeeded))
399 return FALSE;
400 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
401 pbEncoded = *(BYTE **)pbEncoded;
402 *pbEncoded++ = ASN_INTEGER;
403 if (pad)
405 *pbEncoded++ = significantBytes + 1;
406 *pbEncoded++ = padByte;
408 else
409 *pbEncoded++ = significantBytes;
410 for (i = 0; i < significantBytes; i++, val <<= 8)
411 *(pbEncoded + i) = (BYTE)((val & 0xff000000) >> 24);
412 return TRUE;
415 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
416 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
417 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
419 SYSTEMTIME sysTime;
420 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
421 * temporary buffer because the output buffer is not NULL-terminated.
423 char buf[16];
424 static const DWORD bytesNeeded = sizeof(buf) - 1;
426 if (!pvStructInfo)
428 SetLastError(ERROR_INVALID_PARAMETER);
429 return FALSE;
431 /* Sanity check the year, this is a two-digit year format */
432 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
433 return FALSE;
434 if (sysTime.wYear < 1950 || sysTime.wYear > 2050)
436 SetLastError(CRYPT_E_BAD_ENCODE);
437 return FALSE;
439 if (!pbEncoded)
441 *pcbEncoded = bytesNeeded;
442 return TRUE;
444 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
445 bytesNeeded))
446 return FALSE;
447 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
448 pbEncoded = *(BYTE **)pbEncoded;
449 buf[0] = ASN_UTCTIME;
450 buf[1] = bytesNeeded - 2;
451 snprintf(buf + 2, sizeof(buf) - 2, "%02d%02d%02d%02d%02d%02dZ",
452 sysTime.wYear >= 2000 ? sysTime.wYear - 2000 : sysTime.wYear - 1900,
453 sysTime.wDay, sysTime.wMonth, sysTime.wHour, sysTime.wMinute,
454 sysTime.wSecond);
455 memcpy(pbEncoded, buf, bytesNeeded);
456 return TRUE;
459 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
460 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
461 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
463 SYSTEMTIME sysTime;
464 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
465 * temporary buffer because the output buffer is not NULL-terminated.
467 char buf[18];
468 static const DWORD bytesNeeded = sizeof(buf) - 1;
470 if (!pvStructInfo)
472 SetLastError(ERROR_INVALID_PARAMETER);
473 return FALSE;
475 if (!pbEncoded)
477 *pcbEncoded = bytesNeeded;
478 return TRUE;
480 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
481 return FALSE;
482 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
483 bytesNeeded))
484 return FALSE;
485 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
486 pbEncoded = *(BYTE **)pbEncoded;
487 buf[0] = ASN_GENERALTIME;
488 buf[1] = bytesNeeded - 2;
489 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
490 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
491 sysTime.wMinute, sysTime.wSecond);
492 memcpy(pbEncoded, buf, bytesNeeded);
493 return TRUE;
496 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
497 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
498 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
500 SYSTEMTIME sysTime;
501 BOOL ret;
503 if (!pvStructInfo)
505 SetLastError(ERROR_INVALID_PARAMETER);
506 return FALSE;
508 /* Check the year, if it's in the UTCTime range call that encode func */
509 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
510 return FALSE;
511 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
512 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
513 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
514 else
515 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
516 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
517 pcbEncoded);
518 return ret;
521 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
522 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
524 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
525 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
526 BYTE *pbEncoded, DWORD *pcbEncoded)
528 BOOL ret = FALSE;
529 HMODULE lib = NULL;
530 CryptEncodeObjectExFunc encodeFunc = NULL;
532 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p): semi-stub\n",
533 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
534 "(integer value)", pvStructInfo, dwFlags, pEncodePara, pbEncoded,
535 pcbEncoded);
537 if (!pbEncoded && !pcbEncoded)
539 SetLastError(ERROR_INVALID_PARAMETER);
540 return FALSE;
542 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
543 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
545 SetLastError(ERROR_FILE_NOT_FOUND);
546 return FALSE;
549 SetLastError(NOERROR);
550 if (!HIWORD(lpszStructType))
552 switch (LOWORD(lpszStructType))
554 case (WORD)X509_INTEGER:
555 encodeFunc = CRYPT_AsnEncodeInt;
556 break;
557 case (WORD)X509_CHOICE_OF_TIME:
558 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
559 break;
560 case (WORD)PKCS_UTC_TIME:
561 encodeFunc = CRYPT_AsnEncodeUtcTime;
562 break;
563 default:
564 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
567 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
568 encodeFunc = CRYPT_AsnEncodeUtcTime;
569 if (!encodeFunc)
570 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
571 lpszStructType, "CryptEncodeObjectEx", &lib);
572 if (encodeFunc)
573 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
574 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
575 else
576 SetLastError(ERROR_FILE_NOT_FOUND);
577 if (lib)
578 FreeLibrary(lib);
579 return ret;
582 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
583 DWORD, DWORD, void *, DWORD *);
585 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
586 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
587 DWORD *pcbStructInfo)
589 BOOL ret = FALSE;
590 HMODULE lib;
591 CryptDecodeObjectFunc pCryptDecodeObject;
593 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
594 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
595 "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
596 pcbStructInfo);
598 if (!pvStructInfo && !pcbStructInfo)
600 SetLastError(ERROR_INVALID_PARAMETER);
601 return FALSE;
604 /* Try registered DLL first.. */
605 pCryptDecodeObject =
606 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
607 lpszStructType, "CryptDecodeObject", &lib);
608 if (pCryptDecodeObject)
610 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
611 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
612 FreeLibrary(lib);
614 else
616 /* If not, use CryptDecodeObjectEx */
617 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
618 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
620 return ret;
623 /* Helper function to check *pcbStructInfo, set it to the required size, and
624 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
625 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
626 * pointer to the newly allocated memory.
628 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
629 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
630 DWORD bytesNeeded)
632 BOOL ret = TRUE;
634 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
636 if (pDecodePara && pDecodePara->pfnAlloc)
637 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
638 else
639 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
640 if (!*(BYTE **)pvStructInfo)
641 ret = FALSE;
643 else if (*pcbStructInfo < bytesNeeded)
645 *pcbStructInfo = bytesNeeded;
646 SetLastError(ERROR_MORE_DATA);
647 ret = FALSE;
649 return ret;
652 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
653 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
654 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
656 int val, i;
658 if (!pbEncoded || !cbEncoded)
660 SetLastError(ERROR_INVALID_PARAMETER);
661 return FALSE;
663 if (!pvStructInfo)
665 *pcbStructInfo = sizeof(int);
666 return TRUE;
668 if (pbEncoded[0] != ASN_INTEGER)
670 SetLastError(CRYPT_E_ASN1_BADTAG);
671 return FALSE;
673 if (pbEncoded[1] == 0)
675 SetLastError(CRYPT_E_ASN1_CORRUPT);
676 return FALSE;
678 if (pbEncoded[1] > sizeof(int))
680 SetLastError(CRYPT_E_ASN1_LARGE);
681 return FALSE;
683 if (pbEncoded[2] & 0x80)
685 /* initialize to a negative value to sign-extend */
686 val = -1;
688 else
689 val = 0;
690 for (i = 0; i < pbEncoded[1]; i++)
692 val <<= 8;
693 val |= pbEncoded[2 + i];
695 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
696 pcbStructInfo, sizeof(int)))
697 return FALSE;
698 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
699 pvStructInfo = *(BYTE **)pvStructInfo;
700 *pcbStructInfo = sizeof(int);
701 memcpy(pvStructInfo, &val, sizeof(int));
702 return TRUE;
705 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
706 do { \
707 BYTE i; \
709 (word) = 0; \
710 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
712 if (!isdigit(*(pbEncoded))) \
714 SetLastError(CRYPT_E_ASN1_CORRUPT); \
715 return FALSE; \
717 (word) *= 10; \
718 (word) += *(pbEncoded)++ - '0'; \
720 } while (0)
722 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
723 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
724 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
726 SYSTEMTIME sysTime = { 0 };
727 BYTE len;
729 if (!pbEncoded || !cbEncoded)
731 SetLastError(ERROR_INVALID_PARAMETER);
732 return FALSE;
734 if (!pvStructInfo)
736 *pcbStructInfo = sizeof(FILETIME);
737 return TRUE;
739 if (pbEncoded[0] != ASN_UTCTIME)
741 SetLastError(CRYPT_E_ASN1_BADTAG);
742 return FALSE;
744 len = pbEncoded[1];
745 /* FIXME: magic # */
746 if (len < 10)
748 SetLastError(CRYPT_E_ASN1_CORRUPT);
749 return FALSE;
751 pbEncoded += 2;
752 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
753 if (sysTime.wYear >= 50)
754 sysTime.wYear += 1900;
755 else
756 sysTime.wYear += 2000;
757 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
758 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
759 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
760 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
761 if (len > 0)
763 if (len >= 2 && isdigit(*pbEncoded) && isdigit(*(pbEncoded + 1)))
764 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
765 else if (isdigit(*pbEncoded))
766 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, sysTime.wSecond);
767 if (len > 0)
769 /* FIXME: get timezone, for now assuming UTC (no adjustment) */
773 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
774 pcbStructInfo, sizeof(FILETIME)))
775 return FALSE;
776 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
777 pvStructInfo = *(BYTE **)pvStructInfo;
778 *pcbStructInfo = sizeof(FILETIME);
779 return SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
782 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
783 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
784 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
786 SYSTEMTIME sysTime = { 0 };
787 BYTE len;
789 if (!pbEncoded || !cbEncoded)
791 SetLastError(ERROR_INVALID_PARAMETER);
792 return FALSE;
794 if (!pvStructInfo)
796 *pcbStructInfo = sizeof(FILETIME);
797 return TRUE;
799 if (pbEncoded[0] != ASN_GENERALTIME)
801 SetLastError(CRYPT_E_ASN1_BADTAG);
802 return FALSE;
804 len = pbEncoded[1];
805 /* FIXME: magic # */
806 if (len < 10)
808 SetLastError(CRYPT_E_ASN1_CORRUPT);
809 return FALSE;
811 pbEncoded += 2;
812 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
813 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
814 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
815 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
816 if (len > 0)
818 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
819 if (len > 0)
820 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
821 if (len > 0 && (*pbEncoded == '.' || *pbEncoded == ','))
823 BYTE digits;
825 pbEncoded++;
826 len--;
827 digits = min(len, 3); /* workaround macro weirdness */
828 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
829 sysTime.wMilliseconds);
831 if (len >= 5 && (*pbEncoded == '+' || *pbEncoded == '-'))
833 WORD hours, minutes;
834 BYTE sign = *pbEncoded++;
836 len--;
837 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
838 if (hours >= 24)
839 return CRYPT_E_ASN1_CORRUPT;
840 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
841 if (minutes >= 60)
842 return CRYPT_E_ASN1_CORRUPT;
843 if (sign == '+')
845 sysTime.wHour += hours;
846 sysTime.wMinute += minutes;
848 else
850 if (hours > sysTime.wHour)
852 sysTime.wDay--;
853 sysTime.wHour = 24 - (hours - sysTime.wHour);
855 else
856 sysTime.wHour -= hours;
857 if (minutes > sysTime.wMinute)
859 sysTime.wHour--;
860 sysTime.wMinute = 60 - (minutes - sysTime.wMinute);
862 else
863 sysTime.wMinute -= minutes;
868 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
869 pcbStructInfo, sizeof(FILETIME)))
870 return FALSE;
871 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
872 pvStructInfo = *(BYTE **)pvStructInfo;
873 *pcbStructInfo = sizeof(FILETIME);
874 return SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
877 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
878 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
879 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
881 BOOL ret;
883 if (!pbEncoded || !cbEncoded)
885 SetLastError(ERROR_INVALID_PARAMETER);
886 return FALSE;
888 if (!pvStructInfo)
890 *pcbStructInfo = sizeof(FILETIME);
891 return TRUE;
894 if (pbEncoded[0] == ASN_UTCTIME)
895 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
896 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
897 pcbStructInfo);
898 else if (pbEncoded[0] == ASN_GENERALTIME)
899 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
900 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
901 pvStructInfo, pcbStructInfo);
902 else
904 SetLastError(CRYPT_E_ASN1_BADTAG);
905 ret = FALSE;
907 return ret;
910 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
911 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
913 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
914 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
915 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
917 BOOL ret = FALSE;
918 HMODULE lib = NULL;
919 CryptDecodeObjectExFunc decodeFunc = NULL;
921 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p): semi-stub\n",
922 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
923 "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
924 pvStructInfo, pcbStructInfo);
926 if (!pvStructInfo && !pcbStructInfo)
928 SetLastError(ERROR_INVALID_PARAMETER);
929 return FALSE;
931 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
932 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
934 SetLastError(ERROR_FILE_NOT_FOUND);
935 return FALSE;
938 SetLastError(NOERROR);
939 if (!HIWORD(lpszStructType))
941 switch (LOWORD(lpszStructType))
943 case (WORD)X509_INTEGER:
944 decodeFunc = CRYPT_AsnDecodeInt;
945 break;
946 case (WORD)X509_CHOICE_OF_TIME:
947 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
948 break;
949 case (WORD)PKCS_UTC_TIME:
950 decodeFunc = CRYPT_AsnDecodeUtcTime;
951 break;
952 default:
953 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
956 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
957 decodeFunc = CRYPT_AsnDecodeUtcTime;
958 if (!decodeFunc)
959 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
960 lpszStructType, "CryptDecodeObjectEx", &lib);
961 if (decodeFunc)
962 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
963 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
964 else
965 SetLastError(ERROR_FILE_NOT_FOUND);
966 if (lib)
967 FreeLibrary(lib);
968 return ret;