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
27 #include "wine/debug.h"
29 /* a few asn.1 tags we need */
30 #define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
31 #define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
32 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
33 #define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
34 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
35 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
37 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
39 static const WCHAR szDllName[] = { 'D','l','l',0 };
41 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
44 static const char szEncodingTypeFmt[] =
45 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
47 char numericOID[7]; /* enough for "#65535" */
51 /* MSDN says the encoding type is a mask, but it isn't treated that way.
52 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
53 * "EncodingType 2" would be expected if it were a mask. Instead native
54 * stores values in "EncodingType 3".
58 snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
64 /* This is enough: the lengths of the two string parameters are explicitly
65 * counted, and we need up to five additional characters for the encoding
66 * type. These are covered by the "%d", "%s", and "%s" characters in the
67 * format specifier that are removed by sprintf.
69 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
70 szKey = HeapAlloc(GetProcessHeap(), 0, len);
72 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
76 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
77 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
83 TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
84 debugstr_w(pwszDll), pszOverrideFuncName);
86 /* This only registers functions for encoding certs, not messages */
87 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
90 /* Native does nothing pwszDll is NULL */
94 /* I'm not matching MS bug for bug here, because I doubt any app depends on
96 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
97 * it creates would never be used
98 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
99 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
101 if (!pszFuncName || !pszOID)
103 SetLastError(ERROR_INVALID_PARAMETER);
107 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
108 TRACE("Key name is %s\n", debugstr_a(szKey));
113 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
114 HeapFree(GetProcessHeap(), 0, szKey);
115 if(r != ERROR_SUCCESS)
118 /* write the values */
119 if (pszOverrideFuncName)
120 RegSetValueExA(hKey, "FuncName", 0, REG_SZ, pszOverrideFuncName,
121 lstrlenA(pszOverrideFuncName) + 1);
122 RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
123 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
129 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
135 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
137 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
140 if (!pszFuncName || !pszOID)
142 SetLastError(ERROR_INVALID_PARAMETER);
146 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
147 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
148 HeapFree(GetProcessHeap(), 0, szKey);
151 return rc ? FALSE : TRUE;
154 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
155 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
162 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
163 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
166 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
169 if (!pszFuncName || !pszOID || !pwszValueName)
171 SetLastError(ERROR_INVALID_PARAMETER);
175 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
176 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
177 HeapFree(GetProcessHeap(), 0, szKey);
182 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
183 pbValueData, pcbValueData);
188 return rc ? FALSE : TRUE;
191 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
192 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
193 const BYTE *pbValueData, DWORD cbValueData)
199 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
200 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
203 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
206 if (!pszFuncName || !pszOID || !pwszValueName)
208 SetLastError(ERROR_INVALID_PARAMETER);
212 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
213 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
214 HeapFree(GetProcessHeap(), 0, szKey);
219 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
225 return rc ? FALSE : TRUE;
228 /* Gets the registered function named szFuncName for dwCertEncodingType and
229 * lpszStructType, or NULL if one could not be found. *lib will be set to the
230 * handle of the module it's in, or NULL if no module was loaded. If the
231 * return value is NULL, *lib will also be NULL, to simplify error handling.
233 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
234 LPCSTR szFuncName, HMODULE *lib)
237 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
239 const char *funcName;
242 DWORD type, size = 0;
245 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
246 HeapFree(GetProcessHeap(), 0, szKey);
247 if(r != ERROR_SUCCESS)
250 RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
251 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
253 funcName = HeapAlloc(GetProcessHeap(), 0, size);
254 RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
258 funcName = szFuncName;
259 RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
260 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
262 LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
264 RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
266 *lib = LoadLibraryW(dllName);
269 ret = GetProcAddress(*lib, funcName);
272 /* Unload the library, the caller doesn't want to unload it
273 * when the return value is NULL.
279 HeapFree(GetProcessHeap(), 0, dllName);
281 if (funcName != szFuncName)
282 HeapFree(GetProcessHeap(), 0, (char *)funcName);
286 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
289 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
290 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
294 CryptEncodeObjectFunc pCryptEncodeObject;
296 TRACE("(0x%08lx, %s, %p, %p, %p)\n",
297 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
298 "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
300 if (!pbEncoded && !pcbEncoded)
302 SetLastError(ERROR_INVALID_PARAMETER);
306 /* Try registered DLL first.. */
308 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
309 lpszStructType, "CryptEncodeObject", &lib);
310 if (pCryptEncodeObject)
312 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
313 pvStructInfo, pbEncoded, pcbEncoded);
318 /* If not, use CryptEncodeObjectEx */
319 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
320 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
325 /* Helper function to check *pcbEncoded, set it to the required size, and
326 * optionally to allocate memory. Assumes pbEncoded is not NULL.
327 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
328 * pointer to the newly allocated memory.
330 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
331 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
336 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
338 if (pEncodePara && pEncodePara->pfnAlloc)
339 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
341 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
342 if (!*(BYTE **)pbEncoded)
345 *pcbEncoded = bytesNeeded;
347 else if (bytesNeeded > *pcbEncoded)
349 *pcbEncoded = bytesNeeded;
350 SetLastError(ERROR_MORE_DATA);
356 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
357 LPCSTR pszObjId, BYTE *pbEncoded, DWORD *pcbEncoded)
359 DWORD bytesNeeded = 2;
369 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
371 SetLastError(CRYPT_E_ASN1_ERROR);
375 firstByte = val1 * 40 + val2;
376 ptr = pszObjId + firstPos;
381 /* note I assume each component is at most 32-bits long in base 2 */
382 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
384 if (val1 >= 0x10000000)
386 else if (val1 >= 0x200000)
388 else if (val1 >= 0x4000)
390 else if (val1 >= 0x80)
400 SetLastError(CRYPT_E_ASN1_ERROR);
407 if (*pbEncoded < bytesNeeded)
409 SetLastError(ERROR_MORE_DATA);
414 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
415 *pbEncoded++ = bytesNeeded - 2;
421 *pbEncoded++ = firstByte;
422 ptr = pszObjId + firstPos;
425 sscanf(ptr, "%d%n", &val, &pos);
427 unsigned char outBytes[5];
430 if (val >= 0x10000000)
432 else if (val >= 0x200000)
434 else if (val >= 0x4000)
436 else if (val >= 0x80)
440 for (i = numBytes; i > 0; i--)
442 outBytes[i - 1] = val & 0x7f;
445 for (i = 0; i < numBytes - 1; i++)
446 *pbEncoded++ = outBytes[i] | 0x80;
447 *pbEncoded++ = outBytes[i];
456 *pcbEncoded = bytesNeeded;
460 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
461 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
467 switch (value->dwValueType)
469 case CERT_RDN_NUMERIC_STRING:
470 tag = ASN_NUMERICSTRING;
471 bytesNeeded = 2 + value->Value.cbData;
473 case CERT_RDN_PRINTABLE_STRING:
474 tag = ASN_PRINTABLESTRING;
475 bytesNeeded = 2 + value->Value.cbData;
477 case CERT_RDN_IA5_STRING:
479 bytesNeeded = 2 + value->Value.cbData;
481 case CERT_RDN_ANY_TYPE:
482 /* explicitly disallowed */
483 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
486 FIXME("String type %ld unimplemented\n", value->dwValueType);
491 if (*pcbEncoded < bytesNeeded)
493 SetLastError(ERROR_MORE_DATA);
499 *pbEncoded++ = bytesNeeded - 2;
500 switch (value->dwValueType)
502 case CERT_RDN_NUMERIC_STRING:
503 case CERT_RDN_PRINTABLE_STRING:
504 case CERT_RDN_IA5_STRING:
505 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
509 *pcbEncoded = bytesNeeded;
513 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
514 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
516 DWORD bytesNeeded, size;
519 bytesNeeded = 2; /* tag and len */
520 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, attr->pszObjId, NULL, &size);
524 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
525 * with dwValueType, so "cast" it to get its encoded size
527 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
528 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
534 if (*pcbEncoded < bytesNeeded)
536 SetLastError(ERROR_MORE_DATA);
541 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
542 *pbEncoded++ = bytesNeeded - 2;
543 size = bytesNeeded - 2;
544 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, attr->pszObjId,
549 size = bytesNeeded - 2 - size;
550 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
551 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
556 *pcbEncoded = bytesNeeded;
562 static int BLOBComp(const void *l, const void *r)
564 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
567 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
568 ret = a->cbData - b->cbData;
572 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
574 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
575 BYTE *pbEncoded, DWORD *pcbEncoded)
577 DWORD bytesNeeded, i;
579 CRYPT_DER_BLOB *blobs = NULL;
586 SetLastError(STATUS_ACCESS_VIOLATION);
591 blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
592 rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
597 bytesNeeded = 2; /* tag and len */
598 for (i = 0; ret && i < rdn->cRDNAttr; i++)
600 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
601 NULL, &blobs[i].cbData);
603 bytesNeeded += blobs[i].cbData;
609 if (*pcbEncoded < bytesNeeded)
611 SetLastError(ERROR_MORE_DATA);
616 for (i = 0; ret && i < rdn->cRDNAttr; i++)
618 blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
620 if (!blobs[i].pbData)
623 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
624 &rdn->rgRDNAttr[i], blobs[i].pbData, &blobs[i].cbData);
628 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
630 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
631 *pbEncoded++ = (BYTE)bytesNeeded - 2;
632 for (i = 0; ret && i < rdn->cRDNAttr; i++)
634 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
635 pbEncoded += blobs[i].cbData;
640 *pcbEncoded = bytesNeeded;
644 for (i = 0; i < rdn->cRDNAttr; i++)
645 HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
646 HeapFree(GetProcessHeap(), 0, blobs);
651 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
652 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
653 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
655 CERT_NAME_INFO *info = (CERT_NAME_INFO *)pvStructInfo;
656 DWORD bytesNeeded, size, i;
661 SetLastError(STATUS_ACCESS_VIOLATION);
664 if (info->cRDN && !info->rgRDN)
666 SetLastError(STATUS_ACCESS_VIOLATION);
669 TRACE("encoding name with %ld RDNs\n", info->cRDN);
670 bytesNeeded = 2; /* tag and len */
672 for (i = 0; ret && i < info->cRDN; i++)
674 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
683 *pcbEncoded = bytesNeeded;
686 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
687 pcbEncoded, bytesNeeded))
689 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
690 pbEncoded = *(BYTE **)pbEncoded;
691 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
692 *pbEncoded++ = (BYTE)bytesNeeded - 2;
693 for (i = 0; ret && i < info->cRDN; i++)
696 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
708 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
709 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
710 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
713 BYTE significantBytes, padByte = 0, bytesNeeded;
714 BOOL neg = FALSE, pad = FALSE;
718 SetLastError(STATUS_ACCESS_VIOLATION);
722 memcpy(&val, pvStructInfo, sizeof(val));
723 /* Count the number of significant bytes. Temporarily swap sign for
724 * negatives so I count the minimum number of bytes.
731 for (significantBytes = sizeof(val); !(val & 0xff000000);
732 val <<= 8, significantBytes--)
737 if ((val & 0xff000000) < 0x80000000)
743 else if ((val & 0xff000000) > 0x7f000000)
748 bytesNeeded = 2 + significantBytes;
753 *pcbEncoded = bytesNeeded;
756 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
759 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
760 pbEncoded = *(BYTE **)pbEncoded;
761 *pbEncoded++ = ASN_INTEGER;
764 *pbEncoded++ = significantBytes + 1;
765 *pbEncoded++ = padByte;
768 *pbEncoded++ = significantBytes;
769 for (i = 0; i < significantBytes; i++, val <<= 8)
770 *(pbEncoded + i) = (BYTE)((val & 0xff000000) >> 24);
774 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
775 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
776 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
779 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
780 * temporary buffer because the output buffer is not NULL-terminated.
783 static const DWORD bytesNeeded = sizeof(buf) - 1;
787 SetLastError(STATUS_ACCESS_VIOLATION);
790 /* Sanity check the year, this is a two-digit year format */
791 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
793 if (sysTime.wYear < 1950 || sysTime.wYear > 2050)
795 SetLastError(CRYPT_E_BAD_ENCODE);
800 *pcbEncoded = bytesNeeded;
803 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
806 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
807 pbEncoded = *(BYTE **)pbEncoded;
808 buf[0] = ASN_UTCTIME;
809 buf[1] = bytesNeeded - 2;
810 snprintf(buf + 2, sizeof(buf) - 2, "%02d%02d%02d%02d%02d%02dZ",
811 sysTime.wYear >= 2000 ? sysTime.wYear - 2000 : sysTime.wYear - 1900,
812 sysTime.wDay, sysTime.wMonth, sysTime.wHour, sysTime.wMinute,
814 memcpy(pbEncoded, buf, bytesNeeded);
818 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
819 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
820 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
823 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
824 * temporary buffer because the output buffer is not NULL-terminated.
827 static const DWORD bytesNeeded = sizeof(buf) - 1;
831 SetLastError(STATUS_ACCESS_VIOLATION);
836 *pcbEncoded = bytesNeeded;
839 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
841 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
844 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
845 pbEncoded = *(BYTE **)pbEncoded;
846 buf[0] = ASN_GENERALTIME;
847 buf[1] = bytesNeeded - 2;
848 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
849 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
850 sysTime.wMinute, sysTime.wSecond);
851 memcpy(pbEncoded, buf, bytesNeeded);
855 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
856 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
857 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
864 SetLastError(STATUS_ACCESS_VIOLATION);
867 /* Check the year, if it's in the UTCTime range call that encode func */
868 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
870 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
871 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
872 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
874 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
875 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
880 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
881 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
883 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
884 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
885 BYTE *pbEncoded, DWORD *pcbEncoded)
889 CryptEncodeObjectExFunc encodeFunc = NULL;
891 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p): semi-stub\n",
892 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
893 "(integer value)", pvStructInfo, dwFlags, pEncodePara, pbEncoded,
896 if (!pbEncoded && !pcbEncoded)
898 SetLastError(ERROR_INVALID_PARAMETER);
901 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
902 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
904 SetLastError(ERROR_FILE_NOT_FOUND);
908 SetLastError(NOERROR);
909 if (!HIWORD(lpszStructType))
911 switch (LOWORD(lpszStructType))
913 case (WORD)X509_NAME:
914 encodeFunc = CRYPT_AsnEncodeName;
916 case (WORD)X509_INTEGER:
917 encodeFunc = CRYPT_AsnEncodeInt;
919 case (WORD)X509_CHOICE_OF_TIME:
920 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
922 case (WORD)PKCS_UTC_TIME:
923 encodeFunc = CRYPT_AsnEncodeUtcTime;
926 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
929 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
930 encodeFunc = CRYPT_AsnEncodeUtcTime;
932 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
933 lpszStructType, "CryptEncodeObjectEx", &lib);
935 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
936 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
938 SetLastError(ERROR_FILE_NOT_FOUND);
944 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
945 DWORD, DWORD, void *, DWORD *);
947 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
948 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
949 DWORD *pcbStructInfo)
953 CryptDecodeObjectFunc pCryptDecodeObject;
955 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
956 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
957 "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
960 if (!pvStructInfo && !pcbStructInfo)
962 SetLastError(ERROR_INVALID_PARAMETER);
966 /* Try registered DLL first.. */
968 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
969 lpszStructType, "CryptDecodeObject", &lib);
970 if (pCryptDecodeObject)
972 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
973 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
978 /* If not, use CryptDecodeObjectEx */
979 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
980 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
985 /* Helper function to check *pcbStructInfo, set it to the required size, and
986 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
987 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
988 * pointer to the newly allocated memory.
990 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
991 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
996 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
998 if (pDecodePara && pDecodePara->pfnAlloc)
999 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
1001 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
1002 if (!*(BYTE **)pvStructInfo)
1005 *pcbStructInfo = bytesNeeded;
1007 else if (*pcbStructInfo < bytesNeeded)
1009 *pcbStructInfo = bytesNeeded;
1010 SetLastError(ERROR_MORE_DATA);
1016 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_FLAG. */
1017 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1018 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, LPSTR pszObjId,
1024 /* cbEncoded is an upper bound on the number of bytes, not the actual
1025 * count: check the count for sanity.
1027 if (cbEncoded <= 1 || pbEncoded[1] > cbEncoded - 2)
1029 SetLastError(CRYPT_E_ASN1_EOD);
1032 if (pbEncoded[0] != ASN_OBJECTIDENTIFIER)
1034 SetLastError(CRYPT_E_ASN1_BADTAG);
1039 /* The largest possible string for the first two components is 2.175
1040 * (= 2 * 40 + 175 = 255), so this is big enough.
1045 snprintf(firstTwo, sizeof(firstTwo), "%d.%d", pbEncoded[2] / 40,
1046 pbEncoded[2] - (pbEncoded[2] / 40) * 40);
1047 bytesNeeded = strlen(firstTwo) + 1;
1048 for (ptr = pbEncoded + 3; ret && ptr - pbEncoded - 2 < pbEncoded[1]; )
1050 /* large enough for ".4000000" */
1054 while (ptr - pbEncoded - 2 < pbEncoded[1] && (*ptr & 0x80))
1060 if (ptr - pbEncoded - 2 >= pbEncoded[1] || (*ptr & 0x80))
1062 SetLastError(CRYPT_E_ASN1_CORRUPT);
1069 snprintf(str, sizeof(str), ".%d", val);
1070 bytesNeeded += strlen(str);
1074 *pcbObjId = bytesNeeded;
1075 else if (*pcbObjId < bytesNeeded)
1077 *pcbObjId = bytesNeeded;
1078 SetLastError(ERROR_MORE_DATA);
1083 sprintf(pszObjId, "%d.%d", pbEncoded[2] / 40,
1084 pbEncoded[2] - (pbEncoded[2] / 40) * 40);
1085 pszObjId += strlen(pszObjId);
1086 for (ptr = pbEncoded + 3; ret && ptr - pbEncoded - 2 < pbEncoded[1];
1091 while (ptr - pbEncoded - 2 < pbEncoded[1] && (*ptr & 0x80))
1099 sprintf(pszObjId, ".%d", val);
1100 pszObjId += strlen(pszObjId);
1106 *pcbObjId = bytesNeeded;
1110 /* Warning: this assumes the address of value->Value.pbData is already set, in
1111 * order to avoid overwriting memory. (In some cases, it may change it, if it
1112 * doesn't copy anything to memory.) Be sure to set it correctly!
1114 static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
1115 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value,
1121 /* cbEncoded is an upper bound on the number of bytes, not the actual
1122 * count: check the count for sanity.
1124 if (cbEncoded <= 1 || pbEncoded[1] > cbEncoded - 2)
1126 SetLastError(CRYPT_E_ASN1_EOD);
1129 switch (pbEncoded[0])
1131 case ASN_NUMERICSTRING:
1132 case ASN_PRINTABLESTRING:
1136 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
1137 SetLastError(OSS_UNIMPLEMENTED);
1140 bytesNeeded = sizeof(CERT_NAME_VALUE);
1143 switch (pbEncoded[0])
1145 case ASN_NUMERICSTRING:
1146 case ASN_PRINTABLESTRING:
1148 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1149 bytesNeeded += pbEncoded[1];
1155 *pcbValue = bytesNeeded;
1158 if (*pcbValue < bytesNeeded)
1160 *pcbValue = bytesNeeded;
1161 SetLastError(ERROR_MORE_DATA);
1164 *pcbValue = bytesNeeded;
1165 switch (pbEncoded[0])
1167 case ASN_NUMERICSTRING:
1168 value->dwValueType = CERT_RDN_NUMERIC_STRING;
1170 case ASN_PRINTABLESTRING:
1171 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
1174 value->dwValueType = CERT_RDN_IA5_STRING;
1179 switch (pbEncoded[0])
1181 case ASN_NUMERICSTRING:
1182 case ASN_PRINTABLESTRING:
1184 value->Value.cbData = pbEncoded[1];
1185 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1186 value->Value.pbData = (BYTE *)pbEncoded + 2;
1189 if (!value->Value.pbData)
1191 SetLastError(CRYPT_E_ASN1_INTERNAL);
1195 memcpy(value->Value.pbData, pbEncoded + 2, pbEncoded[1]);
1202 value->Value.cbData = 0;
1203 value->Value.pbData = NULL;
1208 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
1209 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr,
1213 DWORD bytesNeeded, size;
1215 /* cbEncoded is an upper bound on the number of bytes, not the actual
1216 * count: check the count for sanity. It must be at least 6, two for the
1217 * tag and length for the RDN_ATTR, two for the OID, and two for the string.
1219 if (cbEncoded < 6 || pbEncoded[1] < 4 || pbEncoded[1] > cbEncoded - 2)
1221 SetLastError(CRYPT_E_ASN1_EOD);
1224 if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCE))
1226 SetLastError(CRYPT_E_ASN1_BADTAG);
1229 bytesNeeded = sizeof(CERT_RDN_ATTR);
1230 ret = CRYPT_AsnDecodeOid(dwCertEncodingType, pbEncoded + 2,
1231 cbEncoded - 2, dwFlags, NULL, &size);
1234 /* ugly: need to know the size of the next element of the sequence,
1235 * so get it directly
1237 BYTE objIdLen = pbEncoded[3];
1239 bytesNeeded += size;
1240 /* hack: like encoding, this takes advantage of the fact that the rest
1241 * of the structure is identical to a CERT_NAME_VALUE.
1243 ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType, pbEncoded + 4 +
1244 objIdLen, cbEncoded - 4 - objIdLen, dwFlags, NULL, &size);
1247 bytesNeeded += size;
1249 *pcbAttr = bytesNeeded;
1250 else if (*pcbAttr < bytesNeeded)
1252 *pcbAttr = bytesNeeded;
1253 SetLastError(ERROR_MORE_DATA);
1258 BYTE *originalData = attr->Value.pbData;
1260 *pcbAttr = bytesNeeded;
1261 /* strange: decode the value first, because it has a counted
1262 * size, and we can store the OID after it. Keep track of the
1263 * original data pointer, we'll need to know whether it was
1267 ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType,
1268 pbEncoded + 4 + objIdLen, cbEncoded - 4 - objIdLen,
1269 dwFlags, (CERT_NAME_VALUE *)&attr->dwValueType, &size);
1274 /* if the data were copied to the original location,
1275 * the OID goes after. Otherwise it goes in the
1276 * spot originally reserved for the data.
1278 if (attr->Value.pbData == originalData)
1279 attr->pszObjId = (LPSTR)(attr->Value.pbData +
1280 attr->Value.cbData);
1282 attr->pszObjId = originalData;
1283 size = bytesNeeded - size;
1284 ret = CRYPT_AsnDecodeOid(dwCertEncodingType,
1285 pbEncoded + 2, cbEncoded - 2, dwFlags, attr->pszObjId,
1289 attr->pszObjId = NULL;
1297 static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
1298 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN *rdn,
1302 DWORD bytesNeeded, cRDNAttr = 0;
1304 /* cbEncoded is an upper bound on the number of bytes, not the actual
1305 * count: check the count for sanity.
1307 if (cbEncoded <= 1 || pbEncoded[1] > cbEncoded - 2)
1309 SetLastError(CRYPT_E_ASN1_EOD);
1312 if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SETOF))
1314 SetLastError(CRYPT_E_ASN1_BADTAG);
1317 bytesNeeded = sizeof(CERT_RDN);
1323 for (ptr = pbEncoded + 2; ret && ptr - pbEncoded - 2 < pbEncoded[1]; )
1325 ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1326 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1330 bytesNeeded += size;
1339 *pcbRdn = bytesNeeded;
1342 if (*pcbRdn < bytesNeeded)
1344 *pcbRdn = bytesNeeded;
1345 SetLastError(ERROR_MORE_DATA);
1348 *pcbRdn = bytesNeeded;
1349 rdn->cRDNAttr = cRDNAttr;
1350 if (rdn->cRDNAttr == 0)
1351 rdn->rgRDNAttr = NULL;
1358 rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn + sizeof(CERT_RDN));
1359 nextData = (BYTE *)rdn->rgRDNAttr +
1360 rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
1361 for (i = 0, ptr = pbEncoded + 2; ret && i < cRDNAttr &&
1362 ptr - pbEncoded - 2 < pbEncoded[1]; i++)
1364 rdn->rgRDNAttr[i].Value.pbData = nextData;
1366 ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1367 cbEncoded - (ptr - pbEncoded), dwFlags, &rdn->rgRDNAttr[i],
1371 bytesNeeded -= size;
1372 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the data may not
1375 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
1376 nextData += rdn->rgRDNAttr[i].Value.cbData;
1377 /* Ugly: the OID, if copied, is stored in memory after the
1378 * value, so increment by its string length if it's set and
1381 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId == nextData)
1382 nextData += strlen(rdn->rgRDNAttr[i].pszObjId) + 1;
1391 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
1392 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1393 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1396 DWORD bytesNeeded, cRDN = 0;
1398 if (!pbEncoded || !cbEncoded)
1400 SetLastError(ERROR_INVALID_PARAMETER);
1403 if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
1405 SetLastError(CRYPT_E_ASN1_BADTAG);
1410 SetLastError(CRYPT_E_ASN1_EOD);
1413 bytesNeeded = sizeof(CERT_NAME_INFO);
1419 for (ptr = pbEncoded + 2; ret && ptr - pbEncoded - 2 < pbEncoded[1]; )
1421 ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1422 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1426 bytesNeeded += size;
1433 CERT_NAME_INFO *info;
1437 *pcbStructInfo = bytesNeeded;
1440 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1441 pcbStructInfo, bytesNeeded))
1443 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1444 pvStructInfo = *(BYTE **)pvStructInfo;
1445 info = (CERT_NAME_INFO *)pvStructInfo;
1447 if (info->cRDN == 0)
1455 info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
1456 sizeof(CERT_NAME_INFO));
1457 nextData = (BYTE *)info->rgRDN + info->cRDN * sizeof(CERT_RDN);
1458 for (i = 0, ptr = pbEncoded + 2; ret && i < cRDN &&
1459 ptr - pbEncoded - 2 < pbEncoded[1]; i++)
1461 info->rgRDN[i].rgRDNAttr = (CERT_RDN_ATTR *)nextData;
1463 ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1464 cbEncoded - (ptr - pbEncoded), dwFlags, &info->rgRDN[i],
1469 bytesNeeded -= size;
1478 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
1479 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1480 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1484 if (!pbEncoded || !cbEncoded)
1486 SetLastError(CRYPT_E_ASN1_EOD);
1491 *pcbStructInfo = sizeof(int);
1494 if (pbEncoded[0] != ASN_INTEGER)
1496 SetLastError(CRYPT_E_ASN1_BADTAG);
1501 SetLastError(CRYPT_E_ASN1_EOD);
1504 if (pbEncoded[1] == 0)
1506 SetLastError(CRYPT_E_ASN1_CORRUPT);
1509 if (pbEncoded[1] > sizeof(int))
1511 SetLastError(CRYPT_E_ASN1_LARGE);
1514 if (pbEncoded[2] & 0x80)
1516 /* initialize to a negative value to sign-extend */
1521 for (i = 0; i < pbEncoded[1]; i++)
1524 val |= pbEncoded[2 + i];
1526 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1527 pcbStructInfo, sizeof(int)))
1529 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1530 pvStructInfo = *(BYTE **)pvStructInfo;
1531 *pcbStructInfo = sizeof(int);
1532 memcpy(pvStructInfo, &val, sizeof(int));
1536 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
1541 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
1543 if (!isdigit(*(pbEncoded))) \
1545 SetLastError(CRYPT_E_ASN1_CORRUPT); \
1549 (word) += *(pbEncoded)++ - '0'; \
1553 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
1554 SYSTEMTIME *sysTime)
1558 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
1560 WORD hours, minutes = 0;
1561 BYTE sign = *pbEncoded++;
1564 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
1567 SetLastError(CRYPT_E_ASN1_CORRUPT);
1573 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
1576 SetLastError(CRYPT_E_ASN1_CORRUPT);
1583 sysTime->wHour += hours;
1584 sysTime->wMinute += minutes;
1588 if (hours > sysTime->wHour)
1591 sysTime->wHour = 24 - (hours - sysTime->wHour);
1594 sysTime->wHour -= hours;
1595 if (minutes > sysTime->wMinute)
1598 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
1601 sysTime->wMinute -= minutes;
1608 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
1609 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1610 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1612 SYSTEMTIME sysTime = { 0 };
1616 if (!pbEncoded || !cbEncoded)
1618 SetLastError(ERROR_INVALID_PARAMETER);
1623 *pcbStructInfo = sizeof(FILETIME);
1626 if (pbEncoded[0] != ASN_UTCTIME)
1628 SetLastError(CRYPT_E_ASN1_BADTAG);
1633 SetLastError(CRYPT_E_ASN1_EOD);
1637 /* FIXME: magic # */
1640 SetLastError(CRYPT_E_ASN1_CORRUPT);
1644 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
1645 if (sysTime.wYear >= 50)
1646 sysTime.wYear += 1900;
1648 sysTime.wYear += 2000;
1649 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
1650 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
1651 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
1652 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
1655 if (len >= 2 && isdigit(*pbEncoded) && isdigit(*(pbEncoded + 1)))
1656 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
1657 else if (isdigit(*pbEncoded))
1658 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, sysTime.wSecond);
1659 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
1663 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1664 pcbStructInfo, sizeof(FILETIME)))
1668 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1669 pvStructInfo = *(BYTE **)pvStructInfo;
1670 *pcbStructInfo = sizeof(FILETIME);
1671 ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
1677 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
1678 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1679 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1681 SYSTEMTIME sysTime = { 0 };
1685 if (!pbEncoded || !cbEncoded)
1687 SetLastError(ERROR_INVALID_PARAMETER);
1692 *pcbStructInfo = sizeof(FILETIME);
1695 if (pbEncoded[0] != ASN_GENERALTIME)
1697 SetLastError(CRYPT_E_ASN1_BADTAG);
1702 SetLastError(CRYPT_E_ASN1_EOD);
1706 /* FIXME: magic # */
1709 SetLastError(CRYPT_E_ASN1_CORRUPT);
1713 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
1714 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
1715 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
1716 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
1719 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
1721 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
1722 if (len > 0 && (*pbEncoded == '.' || *pbEncoded == ','))
1728 digits = min(len, 3); /* workaround macro weirdness */
1729 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
1730 sysTime.wMilliseconds);
1732 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
1736 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1737 pcbStructInfo, sizeof(FILETIME)))
1741 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1742 pvStructInfo = *(BYTE **)pvStructInfo;
1743 *pcbStructInfo = sizeof(FILETIME);
1744 ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
1750 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
1751 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1752 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1756 if (!pbEncoded || !cbEncoded)
1758 SetLastError(ERROR_INVALID_PARAMETER);
1763 *pcbStructInfo = sizeof(FILETIME);
1767 if (pbEncoded[0] == ASN_UTCTIME)
1768 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
1769 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
1771 else if (pbEncoded[0] == ASN_GENERALTIME)
1772 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
1773 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
1774 pvStructInfo, pcbStructInfo);
1777 SetLastError(CRYPT_E_ASN1_BADTAG);
1783 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
1784 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
1786 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1787 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1788 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1792 CryptDecodeObjectExFunc decodeFunc = NULL;
1794 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p): semi-stub\n",
1795 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1796 "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
1797 pvStructInfo, pcbStructInfo);
1799 if (!pvStructInfo && !pcbStructInfo)
1801 SetLastError(ERROR_INVALID_PARAMETER);
1804 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
1805 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
1807 SetLastError(ERROR_FILE_NOT_FOUND);
1811 SetLastError(NOERROR);
1812 if (!HIWORD(lpszStructType))
1814 switch (LOWORD(lpszStructType))
1816 case (WORD)X509_NAME:
1817 decodeFunc = CRYPT_AsnDecodeName;
1819 case (WORD)X509_INTEGER:
1820 decodeFunc = CRYPT_AsnDecodeInt;
1822 case (WORD)X509_CHOICE_OF_TIME:
1823 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
1825 case (WORD)PKCS_UTC_TIME:
1826 decodeFunc = CRYPT_AsnDecodeUtcTime;
1829 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1832 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1833 decodeFunc = CRYPT_AsnDecodeUtcTime;
1835 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1836 lpszStructType, "CryptDecodeObjectEx", &lib);
1838 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
1839 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
1841 SetLastError(ERROR_FILE_NOT_FOUND);