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 /* 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,
39 static const char szEncodingTypeFmt[] =
40 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
42 char numericOID[7]; /* enough for "#65535" */
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".
53 snprintf(numericOID, sizeof(numericOID), "#%d", (int)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);
67 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
71 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
72 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
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))
85 /* Native does nothing pwszDll is NULL */
89 /* I'm not matching MS bug for bug here, because I doubt any app depends on
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);
102 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
103 TRACE("Key name is %s\n", debugstr_a(szKey));
108 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
109 HeapFree(GetProcessHeap(), 0, szKey);
110 if(r != ERROR_SUCCESS)
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));
124 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
130 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
132 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
135 if (!pszFuncName || !pszOID)
137 SetLastError(ERROR_INVALID_PARAMETER);
141 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
142 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
143 HeapFree(GetProcessHeap(), 0, szKey);
146 return rc ? FALSE : TRUE;
149 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
150 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
157 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
158 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
161 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
164 if (!pszFuncName || !pszOID || !pwszValueName)
166 SetLastError(ERROR_INVALID_PARAMETER);
170 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
171 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
172 HeapFree(GetProcessHeap(), 0, szKey);
177 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
178 pbValueData, pcbValueData);
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)
194 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
195 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
198 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
201 if (!pszFuncName || !pszOID || !pwszValueName)
203 SetLastError(ERROR_INVALID_PARAMETER);
207 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
208 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
209 HeapFree(GetProcessHeap(), 0, szKey);
214 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
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)
232 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
234 const char *funcName;
237 DWORD type, size = 0;
240 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
241 HeapFree(GetProcessHeap(), 0, szKey);
242 if(r != ERROR_SUCCESS)
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,
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,
261 *lib = LoadLibraryW(dllName);
264 ret = GetProcAddress(*lib, funcName);
267 /* Unload the library, the caller doesn't want to unload it
268 * when the return value is NULL.
274 HeapFree(GetProcessHeap(), 0, dllName);
276 if (funcName != szFuncName)
277 HeapFree(GetProcessHeap(), 0, (char *)funcName);
281 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
284 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
285 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
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);
301 /* Try registered DLL first.. */
303 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
304 lpszStructType, "CryptEncodeObject", &lib);
305 if (pCryptEncodeObject)
307 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
308 pvStructInfo, pbEncoded, pcbEncoded);
313 /* If not, use CryptEncodeObjectEx */
314 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
315 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
320 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
321 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
324 if (!pbEncoded || (!(dwFlags & CRYPT_ENCODE_ALLOC_FLAG) &&
325 bytesNeeded > *pcbEncoded))
327 *pcbEncoded = bytesNeeded;
328 SetLastError(ERROR_MORE_DATA);
331 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
333 if (pEncodePara && pEncodePara->pfnAlloc)
334 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
336 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
337 if (!*(BYTE **)pbEncoded)
343 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
344 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
345 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
348 BYTE significantBytes, padByte = 0, bytesNeeded;
349 BOOL neg = FALSE, pad = FALSE;
353 SetLastError(ERROR_INVALID_PARAMETER);
357 memcpy(&val, pvStructInfo, sizeof(val));
358 /* Count the number of significant bytes. Temporarily swap sign for
359 * negatives so I count the minimum number of bytes.
366 for (significantBytes = sizeof(val); !(val & 0xff000000);
367 val <<= 8, significantBytes--)
372 if ((val & 0xff000000) < 0x80000000)
378 else if ((val & 0xff000000) > 0x7f000000)
383 bytesNeeded = 2 + significantBytes;
386 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
389 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
390 pbEncoded = *(BYTE **)pbEncoded;
391 *pbEncoded++ = ASN_INTEGER;
394 *pbEncoded++ = significantBytes + 1;
395 *pbEncoded++ = padByte;
398 *pbEncoded++ = significantBytes;
399 for (i = 0; i < significantBytes; i++, val <<= 8)
400 *(pbEncoded + i) = (BYTE)((val & 0xff000000) >> 24);
404 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
405 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
406 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
409 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
410 * temporary buffer because the output buffer is not NULL-terminated.
413 static const DWORD bytesNeeded = sizeof(buf) - 1;
417 SetLastError(ERROR_INVALID_PARAMETER);
420 /* Sanity check the year, this is a two-digit year format */
421 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
423 if (sysTime.wYear < 1950 || sysTime.wYear > 2050)
425 SetLastError(CRYPT_E_BAD_ENCODE);
428 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
431 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
432 pbEncoded = *(BYTE **)pbEncoded;
433 buf[0] = ASN_UTCTIME;
434 buf[1] = bytesNeeded - 2;
435 snprintf(buf + 2, sizeof(buf) - 2, "%02d%02d%02d%02d%02d%02dZ",
436 sysTime.wYear >= 2000 ? sysTime.wYear - 2000 : sysTime.wYear - 1900,
437 sysTime.wDay, sysTime.wMonth, sysTime.wHour, sysTime.wMinute,
439 memcpy(pbEncoded, buf, bytesNeeded);
443 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
444 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
445 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
448 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
449 * temporary buffer because the output buffer is not NULL-terminated.
452 static const DWORD bytesNeeded = sizeof(buf) - 1;
456 SetLastError(ERROR_INVALID_PARAMETER);
459 /* Check the year, if it's in the UTCTime range call that encode func */
460 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
462 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
463 return CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
464 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
465 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
468 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
469 pbEncoded = *(BYTE **)pbEncoded;
470 buf[0] = ASN_GENERALTIME;
471 buf[1] = bytesNeeded - 2;
472 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
473 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
474 sysTime.wMinute, sysTime.wSecond);
475 memcpy(pbEncoded, buf, bytesNeeded);
479 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
480 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
482 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
483 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
484 BYTE *pbEncoded, DWORD *pcbEncoded)
488 CryptEncodeObjectExFunc encodeFunc = NULL;
490 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p): semi-stub\n",
491 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
492 "(integer value)", pvStructInfo, dwFlags, pEncodePara, pbEncoded,
495 if (!pbEncoded && !pcbEncoded)
497 SetLastError(ERROR_INVALID_PARAMETER);
500 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
501 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
503 SetLastError(ERROR_FILE_NOT_FOUND);
507 if (!HIWORD(lpszStructType))
509 switch (LOWORD(lpszStructType))
511 case (WORD)X509_INTEGER:
512 encodeFunc = CRYPT_AsnEncodeInt;
514 case (WORD)X509_CHOICE_OF_TIME:
515 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
517 case (WORD)PKCS_UTC_TIME:
518 encodeFunc = CRYPT_AsnEncodeUtcTime;
521 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
524 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
525 encodeFunc = CRYPT_AsnEncodeUtcTime;
527 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
528 lpszStructType, "CryptEncodeObjectEx", &lib);
530 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
531 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
533 SetLastError(ERROR_FILE_NOT_FOUND);
539 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
540 DWORD, DWORD, void *, DWORD *);
542 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
543 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
544 DWORD *pcbStructInfo)
548 CryptDecodeObjectFunc pCryptDecodeObject;
550 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
551 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
552 "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
555 if (!pvStructInfo && !pcbStructInfo)
557 SetLastError(ERROR_INVALID_PARAMETER);
561 /* Try registered DLL first.. */
563 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
564 lpszStructType, "CryptDecodeObject", &lib);
565 if (pCryptDecodeObject)
567 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
568 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
573 /* If not, use CryptDecodeObjectEx */
574 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
575 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
580 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
581 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
584 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
586 if (pDecodePara && pDecodePara->pfnAlloc)
587 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
589 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
590 if (!*(BYTE **)pvStructInfo)
593 else if (*pcbStructInfo < bytesNeeded)
595 *pcbStructInfo = bytesNeeded;
596 SetLastError(ERROR_MORE_DATA);
602 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
603 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
604 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
608 if (!pbEncoded || !cbEncoded)
610 SetLastError(ERROR_INVALID_PARAMETER);
615 *pcbStructInfo = sizeof(int);
616 SetLastError(ERROR_MORE_DATA);
619 if (pbEncoded[0] != ASN_INTEGER)
621 SetLastError(CRYPT_E_ASN1_BADTAG);
624 if (pbEncoded[1] == 0)
626 SetLastError(CRYPT_E_ASN1_CORRUPT);
629 if (pbEncoded[1] > sizeof(int))
631 SetLastError(CRYPT_E_ASN1_LARGE);
634 if (pbEncoded[2] & 0x80)
636 /* initialize to a negative value to sign-extend */
641 for (i = 0; i < pbEncoded[1]; i++)
644 val |= pbEncoded[2 + i];
646 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
647 pcbStructInfo, sizeof(int)))
649 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
650 pvStructInfo = *(BYTE **)pvStructInfo;
651 *pcbStructInfo = sizeof(int);
652 memcpy(pvStructInfo, &val, sizeof(int));
656 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
661 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
663 if (!isdigit(*(pbEncoded))) \
665 SetLastError(CRYPT_E_ASN1_CORRUPT); \
669 (word) += *(pbEncoded)++ - '0'; \
673 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
674 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
675 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
677 SYSTEMTIME sysTime = { 0 };
680 if (!pbEncoded || !cbEncoded)
682 SetLastError(ERROR_INVALID_PARAMETER);
687 *pcbStructInfo = sizeof(FILETIME);
688 SetLastError(ERROR_MORE_DATA);
691 if (pbEncoded[0] != ASN_UTCTIME)
693 SetLastError(CRYPT_E_ASN1_BADTAG);
700 SetLastError(CRYPT_E_ASN1_CORRUPT);
704 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
705 if (sysTime.wYear >= 50)
706 sysTime.wYear += 1900;
708 sysTime.wYear += 2000;
709 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
710 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
711 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
712 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
715 if (len >= 2 && isdigit(*pbEncoded) && isdigit(*(pbEncoded + 1)))
716 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
717 else if (isdigit(*pbEncoded))
718 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, sysTime.wSecond);
721 /* FIXME: get timezone, for now assuming UTC (no adjustment) */
725 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
726 pcbStructInfo, sizeof(FILETIME)))
728 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
729 pvStructInfo = *(BYTE **)pvStructInfo;
730 *pcbStructInfo = sizeof(FILETIME);
731 return SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
734 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
735 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
736 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
738 SYSTEMTIME sysTime = { 0 };
741 if (!pbEncoded || !cbEncoded)
743 SetLastError(ERROR_INVALID_PARAMETER);
748 *pcbStructInfo = sizeof(FILETIME);
749 SetLastError(ERROR_MORE_DATA);
752 if (pbEncoded[0] == ASN_UTCTIME)
753 return CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
754 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
756 if (pbEncoded[0] != ASN_GENERALTIME)
758 SetLastError(CRYPT_E_ASN1_BADTAG);
765 SetLastError(CRYPT_E_ASN1_CORRUPT);
769 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
770 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
771 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
772 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
775 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
777 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
778 if (len > 0 && (*pbEncoded == '.' || *pbEncoded == ','))
784 digits = min(len, 3); /* workaround macro weirdness */
785 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
786 sysTime.wMilliseconds);
788 if (len >= 5 && (*pbEncoded == '+' || *pbEncoded == '-'))
791 BYTE sign = *pbEncoded++;
794 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
796 return CRYPT_E_ASN1_CORRUPT;
797 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
799 return CRYPT_E_ASN1_CORRUPT;
802 sysTime.wHour += hours;
803 sysTime.wMinute += minutes;
807 if (hours > sysTime.wHour)
810 sysTime.wHour = 24 - (hours - sysTime.wHour);
813 sysTime.wHour -= hours;
814 if (minutes > sysTime.wMinute)
817 sysTime.wMinute = 60 - (minutes - sysTime.wMinute);
820 sysTime.wMinute -= minutes;
825 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
826 pcbStructInfo, sizeof(FILETIME)))
828 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
829 pvStructInfo = *(BYTE **)pvStructInfo;
830 *pcbStructInfo = sizeof(FILETIME);
831 return SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
834 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
835 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
837 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
838 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
839 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
843 CryptDecodeObjectExFunc decodeFunc = NULL;
845 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p): semi-stub\n",
846 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
847 "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
848 pvStructInfo, pcbStructInfo);
850 if (!pvStructInfo && !pcbStructInfo)
852 SetLastError(ERROR_INVALID_PARAMETER);
855 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
856 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
858 SetLastError(ERROR_FILE_NOT_FOUND);
862 if (!HIWORD(lpszStructType))
864 switch (LOWORD(lpszStructType))
866 case (WORD)X509_INTEGER:
867 decodeFunc = CRYPT_AsnDecodeInt;
869 case (WORD)X509_CHOICE_OF_TIME:
870 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
872 case (WORD)PKCS_UTC_TIME:
873 decodeFunc = CRYPT_AsnDecodeUtcTime;
876 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
879 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
880 decodeFunc = CRYPT_AsnDecodeUtcTime;
882 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
883 lpszStructType, "CryptDecodeObjectEx", &lib);
885 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
886 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
888 SetLastError(ERROR_FILE_NOT_FOUND);