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_AsnEncodeInteger(DWORD dwCertEncodingType,
775 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
776 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
778 DWORD significantBytes;
779 BYTE padByte = 0, bytesNeeded;
781 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
785 SetLastError(STATUS_ACCESS_VIOLATION);
789 /* FIXME: use exception handling to protect against bogus pointers */
790 significantBytes = blob->cbData;
791 if (significantBytes)
793 if (blob->pbData[significantBytes - 1] & 0x80)
795 /* negative, lop off leading (little-endian) 0xffs */
796 for (; significantBytes > 0 &&
797 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
799 if (blob->pbData[significantBytes - 1] < 0x80)
807 /* positive, lop off leading (little-endian) zeroes */
808 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
811 if (blob->pbData[significantBytes - 1] > 0x7f)
818 bytesNeeded = 2 + significantBytes;
823 *pcbEncoded = bytesNeeded;
826 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
829 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
830 pbEncoded = *(BYTE **)pbEncoded;
831 *pbEncoded++ = ASN_INTEGER;
834 *pbEncoded++ = significantBytes + 1;
835 *pbEncoded++ = padByte;
838 *pbEncoded++ = significantBytes;
839 for (; significantBytes > 0; significantBytes--)
840 *(pbEncoded++) = blob->pbData[significantBytes - 1];
844 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
845 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
846 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
849 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
850 * temporary buffer because the output buffer is not NULL-terminated.
853 static const DWORD bytesNeeded = sizeof(buf) - 1;
857 SetLastError(STATUS_ACCESS_VIOLATION);
860 /* Sanity check the year, this is a two-digit year format */
861 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
863 if (sysTime.wYear < 1950 || sysTime.wYear > 2050)
865 SetLastError(CRYPT_E_BAD_ENCODE);
870 *pcbEncoded = bytesNeeded;
873 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
876 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
877 pbEncoded = *(BYTE **)pbEncoded;
878 buf[0] = ASN_UTCTIME;
879 buf[1] = bytesNeeded - 2;
880 snprintf(buf + 2, sizeof(buf) - 2, "%02d%02d%02d%02d%02d%02dZ",
881 sysTime.wYear >= 2000 ? sysTime.wYear - 2000 : sysTime.wYear - 1900,
882 sysTime.wDay, sysTime.wMonth, sysTime.wHour, sysTime.wMinute,
884 memcpy(pbEncoded, buf, bytesNeeded);
888 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
889 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
890 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
893 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
894 * temporary buffer because the output buffer is not NULL-terminated.
897 static const DWORD bytesNeeded = sizeof(buf) - 1;
901 SetLastError(STATUS_ACCESS_VIOLATION);
906 *pcbEncoded = bytesNeeded;
909 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
911 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
914 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
915 pbEncoded = *(BYTE **)pbEncoded;
916 buf[0] = ASN_GENERALTIME;
917 buf[1] = bytesNeeded - 2;
918 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
919 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
920 sysTime.wMinute, sysTime.wSecond);
921 memcpy(pbEncoded, buf, bytesNeeded);
925 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
926 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
927 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
934 SetLastError(STATUS_ACCESS_VIOLATION);
937 /* Check the year, if it's in the UTCTime range call that encode func */
938 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
940 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
941 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
942 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
944 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
945 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
950 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
951 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
953 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
954 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
955 BYTE *pbEncoded, DWORD *pcbEncoded)
959 CryptEncodeObjectExFunc encodeFunc = NULL;
961 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p): semi-stub\n",
962 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
963 "(integer value)", pvStructInfo, dwFlags, pEncodePara, pbEncoded,
966 if (!pbEncoded && !pcbEncoded)
968 SetLastError(ERROR_INVALID_PARAMETER);
971 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
972 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
974 SetLastError(ERROR_FILE_NOT_FOUND);
978 SetLastError(NOERROR);
979 if (!HIWORD(lpszStructType))
981 switch (LOWORD(lpszStructType))
983 case (WORD)X509_NAME:
984 encodeFunc = CRYPT_AsnEncodeName;
986 case (WORD)X509_INTEGER:
987 encodeFunc = CRYPT_AsnEncodeInt;
989 case (WORD)X509_MULTI_BYTE_INTEGER:
990 encodeFunc = CRYPT_AsnEncodeInteger;
992 case (WORD)X509_CHOICE_OF_TIME:
993 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
995 case (WORD)PKCS_UTC_TIME:
996 encodeFunc = CRYPT_AsnEncodeUtcTime;
999 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1002 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1003 encodeFunc = CRYPT_AsnEncodeUtcTime;
1005 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1006 lpszStructType, "CryptEncodeObjectEx", &lib);
1008 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
1009 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1011 SetLastError(ERROR_FILE_NOT_FOUND);
1017 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1018 DWORD, DWORD, void *, DWORD *);
1020 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1021 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
1022 DWORD *pcbStructInfo)
1026 CryptDecodeObjectFunc pCryptDecodeObject;
1028 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
1029 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1030 "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1033 if (!pvStructInfo && !pcbStructInfo)
1035 SetLastError(ERROR_INVALID_PARAMETER);
1039 /* Try registered DLL first.. */
1040 pCryptDecodeObject =
1041 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
1042 lpszStructType, "CryptDecodeObject", &lib);
1043 if (pCryptDecodeObject)
1045 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
1046 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1051 /* If not, use CryptDecodeObjectEx */
1052 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
1053 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
1058 /* Helper function to check *pcbStructInfo, set it to the required size, and
1059 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
1060 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
1061 * pointer to the newly allocated memory.
1063 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
1064 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
1069 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1071 if (pDecodePara && pDecodePara->pfnAlloc)
1072 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
1074 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
1075 if (!*(BYTE **)pvStructInfo)
1078 *pcbStructInfo = bytesNeeded;
1080 else if (*pcbStructInfo < bytesNeeded)
1082 *pcbStructInfo = bytesNeeded;
1083 SetLastError(ERROR_MORE_DATA);
1089 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_FLAG. */
1090 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1091 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, LPSTR pszObjId,
1097 /* cbEncoded is an upper bound on the number of bytes, not the actual
1098 * count: check the count for sanity.
1100 if (cbEncoded <= 1 || pbEncoded[1] > cbEncoded - 2)
1102 SetLastError(CRYPT_E_ASN1_EOD);
1105 if (pbEncoded[0] != ASN_OBJECTIDENTIFIER)
1107 SetLastError(CRYPT_E_ASN1_BADTAG);
1112 /* The largest possible string for the first two components is 2.175
1113 * (= 2 * 40 + 175 = 255), so this is big enough.
1118 snprintf(firstTwo, sizeof(firstTwo), "%d.%d", pbEncoded[2] / 40,
1119 pbEncoded[2] - (pbEncoded[2] / 40) * 40);
1120 bytesNeeded = strlen(firstTwo) + 1;
1121 for (ptr = pbEncoded + 3; ret && ptr - pbEncoded - 2 < pbEncoded[1]; )
1123 /* large enough for ".4000000" */
1127 while (ptr - pbEncoded - 2 < pbEncoded[1] && (*ptr & 0x80))
1133 if (ptr - pbEncoded - 2 >= pbEncoded[1] || (*ptr & 0x80))
1135 SetLastError(CRYPT_E_ASN1_CORRUPT);
1142 snprintf(str, sizeof(str), ".%d", val);
1143 bytesNeeded += strlen(str);
1147 *pcbObjId = bytesNeeded;
1148 else if (*pcbObjId < bytesNeeded)
1150 *pcbObjId = bytesNeeded;
1151 SetLastError(ERROR_MORE_DATA);
1156 sprintf(pszObjId, "%d.%d", pbEncoded[2] / 40,
1157 pbEncoded[2] - (pbEncoded[2] / 40) * 40);
1158 pszObjId += strlen(pszObjId);
1159 for (ptr = pbEncoded + 3; ret && ptr - pbEncoded - 2 < pbEncoded[1];
1164 while (ptr - pbEncoded - 2 < pbEncoded[1] && (*ptr & 0x80))
1172 sprintf(pszObjId, ".%d", val);
1173 pszObjId += strlen(pszObjId);
1179 *pcbObjId = bytesNeeded;
1183 /* Warning: this assumes the address of value->Value.pbData is already set, in
1184 * order to avoid overwriting memory. (In some cases, it may change it, if it
1185 * doesn't copy anything to memory.) Be sure to set it correctly!
1187 static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
1188 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value,
1194 /* cbEncoded is an upper bound on the number of bytes, not the actual
1195 * count: check the count for sanity.
1197 if (cbEncoded <= 1 || pbEncoded[1] > cbEncoded - 2)
1199 SetLastError(CRYPT_E_ASN1_EOD);
1202 switch (pbEncoded[0])
1204 case ASN_NUMERICSTRING:
1205 case ASN_PRINTABLESTRING:
1209 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
1210 SetLastError(OSS_UNIMPLEMENTED);
1213 bytesNeeded = sizeof(CERT_NAME_VALUE);
1216 switch (pbEncoded[0])
1218 case ASN_NUMERICSTRING:
1219 case ASN_PRINTABLESTRING:
1221 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1222 bytesNeeded += pbEncoded[1];
1228 *pcbValue = bytesNeeded;
1231 if (*pcbValue < bytesNeeded)
1233 *pcbValue = bytesNeeded;
1234 SetLastError(ERROR_MORE_DATA);
1237 *pcbValue = bytesNeeded;
1238 switch (pbEncoded[0])
1240 case ASN_NUMERICSTRING:
1241 value->dwValueType = CERT_RDN_NUMERIC_STRING;
1243 case ASN_PRINTABLESTRING:
1244 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
1247 value->dwValueType = CERT_RDN_IA5_STRING;
1252 switch (pbEncoded[0])
1254 case ASN_NUMERICSTRING:
1255 case ASN_PRINTABLESTRING:
1257 value->Value.cbData = pbEncoded[1];
1258 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1259 value->Value.pbData = (BYTE *)pbEncoded + 2;
1262 if (!value->Value.pbData)
1264 SetLastError(CRYPT_E_ASN1_INTERNAL);
1268 memcpy(value->Value.pbData, pbEncoded + 2, pbEncoded[1]);
1275 value->Value.cbData = 0;
1276 value->Value.pbData = NULL;
1281 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
1282 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr,
1286 DWORD bytesNeeded, size;
1288 /* cbEncoded is an upper bound on the number of bytes, not the actual
1289 * count: check the count for sanity. It must be at least 6, two for the
1290 * tag and length for the RDN_ATTR, two for the OID, and two for the string.
1292 if (cbEncoded < 6 || pbEncoded[1] < 4 || pbEncoded[1] > cbEncoded - 2)
1294 SetLastError(CRYPT_E_ASN1_EOD);
1297 if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCE))
1299 SetLastError(CRYPT_E_ASN1_BADTAG);
1302 bytesNeeded = sizeof(CERT_RDN_ATTR);
1303 ret = CRYPT_AsnDecodeOid(dwCertEncodingType, pbEncoded + 2,
1304 cbEncoded - 2, dwFlags, NULL, &size);
1307 /* ugly: need to know the size of the next element of the sequence,
1308 * so get it directly
1310 BYTE objIdLen = pbEncoded[3];
1312 bytesNeeded += size;
1313 /* hack: like encoding, this takes advantage of the fact that the rest
1314 * of the structure is identical to a CERT_NAME_VALUE.
1316 ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType, pbEncoded + 4 +
1317 objIdLen, cbEncoded - 4 - objIdLen, dwFlags, NULL, &size);
1320 bytesNeeded += size;
1322 *pcbAttr = bytesNeeded;
1323 else if (*pcbAttr < bytesNeeded)
1325 *pcbAttr = bytesNeeded;
1326 SetLastError(ERROR_MORE_DATA);
1331 BYTE *originalData = attr->Value.pbData;
1333 *pcbAttr = bytesNeeded;
1334 /* strange: decode the value first, because it has a counted
1335 * size, and we can store the OID after it. Keep track of the
1336 * original data pointer, we'll need to know whether it was
1340 ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType,
1341 pbEncoded + 4 + objIdLen, cbEncoded - 4 - objIdLen,
1342 dwFlags, (CERT_NAME_VALUE *)&attr->dwValueType, &size);
1347 /* if the data were copied to the original location,
1348 * the OID goes after. Otherwise it goes in the
1349 * spot originally reserved for the data.
1351 if (attr->Value.pbData == originalData)
1352 attr->pszObjId = (LPSTR)(attr->Value.pbData +
1353 attr->Value.cbData);
1355 attr->pszObjId = originalData;
1356 size = bytesNeeded - size;
1357 ret = CRYPT_AsnDecodeOid(dwCertEncodingType,
1358 pbEncoded + 2, cbEncoded - 2, dwFlags, attr->pszObjId,
1362 attr->pszObjId = NULL;
1370 static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
1371 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN *rdn,
1375 DWORD bytesNeeded, cRDNAttr = 0;
1377 /* cbEncoded is an upper bound on the number of bytes, not the actual
1378 * count: check the count for sanity.
1380 if (cbEncoded <= 1 || pbEncoded[1] > cbEncoded - 2)
1382 SetLastError(CRYPT_E_ASN1_EOD);
1385 if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SETOF))
1387 SetLastError(CRYPT_E_ASN1_BADTAG);
1390 bytesNeeded = sizeof(CERT_RDN);
1396 for (ptr = pbEncoded + 2; ret && ptr - pbEncoded - 2 < pbEncoded[1]; )
1398 ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1399 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1403 bytesNeeded += size;
1412 *pcbRdn = bytesNeeded;
1415 if (*pcbRdn < bytesNeeded)
1417 *pcbRdn = bytesNeeded;
1418 SetLastError(ERROR_MORE_DATA);
1421 *pcbRdn = bytesNeeded;
1422 rdn->cRDNAttr = cRDNAttr;
1423 if (rdn->cRDNAttr == 0)
1424 rdn->rgRDNAttr = NULL;
1431 rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn + sizeof(CERT_RDN));
1432 nextData = (BYTE *)rdn->rgRDNAttr +
1433 rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
1434 for (i = 0, ptr = pbEncoded + 2; ret && i < cRDNAttr &&
1435 ptr - pbEncoded - 2 < pbEncoded[1]; i++)
1437 rdn->rgRDNAttr[i].Value.pbData = nextData;
1439 ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1440 cbEncoded - (ptr - pbEncoded), dwFlags, &rdn->rgRDNAttr[i],
1444 bytesNeeded -= size;
1445 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the data may not
1448 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
1449 nextData += rdn->rgRDNAttr[i].Value.cbData;
1450 /* Ugly: the OID, if copied, is stored in memory after the
1451 * value, so increment by its string length if it's set and
1454 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId == nextData)
1455 nextData += strlen(rdn->rgRDNAttr[i].pszObjId) + 1;
1464 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
1465 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1466 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1469 DWORD bytesNeeded, cRDN = 0;
1471 if (!pbEncoded || !cbEncoded)
1473 SetLastError(ERROR_INVALID_PARAMETER);
1476 if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
1478 SetLastError(CRYPT_E_ASN1_BADTAG);
1483 SetLastError(CRYPT_E_ASN1_EOD);
1486 bytesNeeded = sizeof(CERT_NAME_INFO);
1492 for (ptr = pbEncoded + 2; ret && ptr - pbEncoded - 2 < pbEncoded[1]; )
1494 ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1495 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1499 bytesNeeded += size;
1506 CERT_NAME_INFO *info;
1510 *pcbStructInfo = bytesNeeded;
1513 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1514 pcbStructInfo, bytesNeeded))
1516 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1517 pvStructInfo = *(BYTE **)pvStructInfo;
1518 info = (CERT_NAME_INFO *)pvStructInfo;
1520 if (info->cRDN == 0)
1528 info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
1529 sizeof(CERT_NAME_INFO));
1530 nextData = (BYTE *)info->rgRDN + info->cRDN * sizeof(CERT_RDN);
1531 for (i = 0, ptr = pbEncoded + 2; ret && i < cRDN &&
1532 ptr - pbEncoded - 2 < pbEncoded[1]; i++)
1534 info->rgRDN[i].rgRDNAttr = (CERT_RDN_ATTR *)nextData;
1536 ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1537 cbEncoded - (ptr - pbEncoded), dwFlags, &info->rgRDN[i],
1542 bytesNeeded -= size;
1551 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
1552 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1553 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1557 if (!pbEncoded || !cbEncoded)
1559 SetLastError(CRYPT_E_ASN1_EOD);
1564 *pcbStructInfo = sizeof(int);
1567 if (pbEncoded[0] != ASN_INTEGER)
1569 SetLastError(CRYPT_E_ASN1_BADTAG);
1574 SetLastError(CRYPT_E_ASN1_EOD);
1577 if (pbEncoded[1] == 0)
1579 SetLastError(CRYPT_E_ASN1_CORRUPT);
1582 if (pbEncoded[1] > sizeof(int))
1584 SetLastError(CRYPT_E_ASN1_LARGE);
1587 if (pbEncoded[2] & 0x80)
1589 /* initialize to a negative value to sign-extend */
1594 for (i = 0; i < pbEncoded[1]; i++)
1597 val |= pbEncoded[2 + i];
1599 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1600 pcbStructInfo, sizeof(int)))
1602 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1603 pvStructInfo = *(BYTE **)pvStructInfo;
1604 memcpy(pvStructInfo, &val, sizeof(int));
1608 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
1609 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1610 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1613 CRYPT_INTEGER_BLOB *blob;
1615 if (!pbEncoded || !cbEncoded)
1617 SetLastError(CRYPT_E_ASN1_EOD);
1620 if (pbEncoded[0] != ASN_INTEGER)
1622 SetLastError(CRYPT_E_ASN1_BADTAG);
1627 SetLastError(CRYPT_E_ASN1_EOD);
1630 if (pbEncoded[1] > cbEncoded)
1632 SetLastError(CRYPT_E_ASN1_EOD);
1635 bytesNeeded = pbEncoded[1] + sizeof(CRYPT_INTEGER_BLOB);
1638 *pcbStructInfo = bytesNeeded;
1641 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1642 pcbStructInfo, bytesNeeded))
1644 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1645 pvStructInfo = *(BYTE **)pvStructInfo;
1646 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
1647 blob->cbData = pbEncoded[1];
1648 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_INTEGER_BLOB);
1653 for (i = 0; i < blob->cbData; i++)
1654 blob->pbData[i] = *(pbEncoded + 2 + pbEncoded[1] - i - 1);
1659 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
1664 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
1666 if (!isdigit(*(pbEncoded))) \
1668 SetLastError(CRYPT_E_ASN1_CORRUPT); \
1672 (word) += *(pbEncoded)++ - '0'; \
1676 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
1677 SYSTEMTIME *sysTime)
1681 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
1683 WORD hours, minutes = 0;
1684 BYTE sign = *pbEncoded++;
1687 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
1690 SetLastError(CRYPT_E_ASN1_CORRUPT);
1696 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
1699 SetLastError(CRYPT_E_ASN1_CORRUPT);
1706 sysTime->wHour += hours;
1707 sysTime->wMinute += minutes;
1711 if (hours > sysTime->wHour)
1714 sysTime->wHour = 24 - (hours - sysTime->wHour);
1717 sysTime->wHour -= hours;
1718 if (minutes > sysTime->wMinute)
1721 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
1724 sysTime->wMinute -= minutes;
1731 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
1732 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1733 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1735 SYSTEMTIME sysTime = { 0 };
1739 if (!pbEncoded || !cbEncoded)
1741 SetLastError(ERROR_INVALID_PARAMETER);
1746 *pcbStructInfo = sizeof(FILETIME);
1749 if (pbEncoded[0] != ASN_UTCTIME)
1751 SetLastError(CRYPT_E_ASN1_BADTAG);
1756 SetLastError(CRYPT_E_ASN1_EOD);
1760 /* FIXME: magic # */
1763 SetLastError(CRYPT_E_ASN1_CORRUPT);
1767 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
1768 if (sysTime.wYear >= 50)
1769 sysTime.wYear += 1900;
1771 sysTime.wYear += 2000;
1772 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
1773 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
1774 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
1775 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
1778 if (len >= 2 && isdigit(*pbEncoded) && isdigit(*(pbEncoded + 1)))
1779 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
1780 else if (isdigit(*pbEncoded))
1781 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, sysTime.wSecond);
1782 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
1786 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1787 pcbStructInfo, sizeof(FILETIME)))
1791 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1792 pvStructInfo = *(BYTE **)pvStructInfo;
1793 ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
1799 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
1800 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1801 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1803 SYSTEMTIME sysTime = { 0 };
1807 if (!pbEncoded || !cbEncoded)
1809 SetLastError(ERROR_INVALID_PARAMETER);
1814 *pcbStructInfo = sizeof(FILETIME);
1817 if (pbEncoded[0] != ASN_GENERALTIME)
1819 SetLastError(CRYPT_E_ASN1_BADTAG);
1824 SetLastError(CRYPT_E_ASN1_EOD);
1828 /* FIXME: magic # */
1831 SetLastError(CRYPT_E_ASN1_CORRUPT);
1835 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
1836 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
1837 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
1838 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
1841 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
1843 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
1844 if (len > 0 && (*pbEncoded == '.' || *pbEncoded == ','))
1850 digits = min(len, 3); /* workaround macro weirdness */
1851 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
1852 sysTime.wMilliseconds);
1854 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
1858 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1859 pcbStructInfo, sizeof(FILETIME)))
1863 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1864 pvStructInfo = *(BYTE **)pvStructInfo;
1865 ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
1871 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
1872 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1873 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1877 if (!pbEncoded || !cbEncoded)
1879 SetLastError(ERROR_INVALID_PARAMETER);
1884 *pcbStructInfo = sizeof(FILETIME);
1888 if (pbEncoded[0] == ASN_UTCTIME)
1889 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
1890 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
1892 else if (pbEncoded[0] == ASN_GENERALTIME)
1893 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
1894 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
1895 pvStructInfo, pcbStructInfo);
1898 SetLastError(CRYPT_E_ASN1_BADTAG);
1904 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
1905 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
1907 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1908 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1909 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1913 CryptDecodeObjectExFunc decodeFunc = NULL;
1915 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p): semi-stub\n",
1916 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1917 "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
1918 pvStructInfo, pcbStructInfo);
1920 if (!pvStructInfo && !pcbStructInfo)
1922 SetLastError(ERROR_INVALID_PARAMETER);
1925 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
1926 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
1928 SetLastError(ERROR_FILE_NOT_FOUND);
1932 SetLastError(NOERROR);
1933 if (!HIWORD(lpszStructType))
1935 switch (LOWORD(lpszStructType))
1937 case (WORD)X509_NAME:
1938 decodeFunc = CRYPT_AsnDecodeName;
1940 case (WORD)X509_INTEGER:
1941 decodeFunc = CRYPT_AsnDecodeInt;
1943 case (WORD)X509_MULTI_BYTE_INTEGER:
1944 decodeFunc = CRYPT_AsnDecodeInteger;
1946 case (WORD)X509_CHOICE_OF_TIME:
1947 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
1949 case (WORD)PKCS_UTC_TIME:
1950 decodeFunc = CRYPT_AsnDecodeUtcTime;
1953 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1956 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1957 decodeFunc = CRYPT_AsnDecodeUtcTime;
1959 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1960 lpszStructType, "CryptDecodeObjectEx", &lib);
1962 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
1963 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
1965 SetLastError(ERROR_FILE_NOT_FOUND);