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_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
31 #define ASN_OCTETSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
32 #define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
33 #define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
34 #define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
35 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
36 #define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
37 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
38 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
40 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
42 static const WCHAR szDllName[] = { 'D','l','l',0 };
44 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
47 static const char szEncodingTypeFmt[] =
48 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
50 char numericOID[7]; /* enough for "#65535" */
54 /* MSDN says the encoding type is a mask, but it isn't treated that way.
55 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
56 * "EncodingType 2" would be expected if it were a mask. Instead native
57 * stores values in "EncodingType 3".
61 snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
67 /* This is enough: the lengths of the two string parameters are explicitly
68 * counted, and we need up to five additional characters for the encoding
69 * type. These are covered by the "%d", "%s", and "%s" characters in the
70 * format specifier that are removed by sprintf.
72 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
73 szKey = HeapAlloc(GetProcessHeap(), 0, len);
75 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
79 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
80 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
86 TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
87 debugstr_w(pwszDll), pszOverrideFuncName);
89 /* This only registers functions for encoding certs, not messages */
90 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
93 /* Native does nothing pwszDll is NULL */
97 /* I'm not matching MS bug for bug here, because I doubt any app depends on
99 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
100 * it creates would never be used
101 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
102 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
104 if (!pszFuncName || !pszOID)
106 SetLastError(ERROR_INVALID_PARAMETER);
110 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
111 TRACE("Key name is %s\n", debugstr_a(szKey));
116 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
117 HeapFree(GetProcessHeap(), 0, szKey);
118 if(r != ERROR_SUCCESS)
121 /* write the values */
122 if (pszOverrideFuncName)
123 RegSetValueExA(hKey, "FuncName", 0, REG_SZ, pszOverrideFuncName,
124 lstrlenA(pszOverrideFuncName) + 1);
125 RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
126 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
132 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
138 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
140 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
143 if (!pszFuncName || !pszOID)
145 SetLastError(ERROR_INVALID_PARAMETER);
149 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
150 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
151 HeapFree(GetProcessHeap(), 0, szKey);
154 return rc ? FALSE : TRUE;
157 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
158 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
165 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
166 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
169 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
172 if (!pszFuncName || !pszOID || !pwszValueName)
174 SetLastError(ERROR_INVALID_PARAMETER);
178 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
179 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
180 HeapFree(GetProcessHeap(), 0, szKey);
185 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
186 pbValueData, pcbValueData);
191 return rc ? FALSE : TRUE;
194 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
195 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
196 const BYTE *pbValueData, DWORD cbValueData)
202 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
203 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
206 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
209 if (!pszFuncName || !pszOID || !pwszValueName)
211 SetLastError(ERROR_INVALID_PARAMETER);
215 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
216 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
217 HeapFree(GetProcessHeap(), 0, szKey);
222 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
228 return rc ? FALSE : TRUE;
231 /* Gets the registered function named szFuncName for dwCertEncodingType and
232 * lpszStructType, or NULL if one could not be found. *lib will be set to the
233 * handle of the module it's in, or NULL if no module was loaded. If the
234 * return value is NULL, *lib will also be NULL, to simplify error handling.
236 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
237 LPCSTR szFuncName, HMODULE *lib)
240 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
242 const char *funcName;
245 DWORD type, size = 0;
248 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
249 HeapFree(GetProcessHeap(), 0, szKey);
250 if(r != ERROR_SUCCESS)
253 RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
254 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
256 funcName = HeapAlloc(GetProcessHeap(), 0, size);
257 RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
261 funcName = szFuncName;
262 RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
263 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
265 LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
267 RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
269 *lib = LoadLibraryW(dllName);
272 ret = GetProcAddress(*lib, funcName);
275 /* Unload the library, the caller doesn't want to unload it
276 * when the return value is NULL.
282 HeapFree(GetProcessHeap(), 0, dllName);
284 if (funcName != szFuncName)
285 HeapFree(GetProcessHeap(), 0, (char *)funcName);
289 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
292 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
293 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
297 CryptEncodeObjectFunc pCryptEncodeObject;
299 TRACE("(0x%08lx, %s, %p, %p, %p)\n",
300 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
301 "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
303 if (!pbEncoded && !pcbEncoded)
305 SetLastError(ERROR_INVALID_PARAMETER);
309 /* Try registered DLL first.. */
311 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
312 lpszStructType, "CryptEncodeObject", &lib);
313 if (pCryptEncodeObject)
315 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
316 pvStructInfo, pbEncoded, pcbEncoded);
321 /* If not, use CryptEncodeObjectEx */
322 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
323 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
328 /* Helper function to check *pcbEncoded, set it to the required size, and
329 * optionally to allocate memory. Assumes pbEncoded is not NULL.
330 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
331 * pointer to the newly allocated memory.
333 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
334 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
339 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
341 if (pEncodePara && pEncodePara->pfnAlloc)
342 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
344 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
345 if (!*(BYTE **)pbEncoded)
348 *pcbEncoded = bytesNeeded;
350 else if (bytesNeeded > *pcbEncoded)
352 *pcbEncoded = bytesNeeded;
353 SetLastError(ERROR_MORE_DATA);
359 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
361 DWORD bytesNeeded, significantBytes = 0;
369 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
370 temp <<= 8, significantBytes--)
372 bytesNeeded = significantBytes + 1;
376 *pcbEncoded = bytesNeeded;
379 if (*pcbEncoded < bytesNeeded)
381 SetLastError(ERROR_MORE_DATA);
385 *pbEncoded = (BYTE)len;
390 *pbEncoded++ = significantBytes | 0x80;
391 for (i = 0; i < significantBytes; i++)
393 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
397 *pcbEncoded = bytesNeeded;
401 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
402 LPCSTR pszObjId, BYTE *pbEncoded, DWORD *pcbEncoded)
404 DWORD bytesNeeded = 0, lenBytes;
414 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
416 SetLastError(CRYPT_E_ASN1_ERROR);
420 firstByte = val1 * 40 + val2;
421 ptr = pszObjId + firstPos;
426 /* note I assume each component is at most 32-bits long in base 2 */
427 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
429 if (val1 >= 0x10000000)
431 else if (val1 >= 0x200000)
433 else if (val1 >= 0x4000)
435 else if (val1 >= 0x80)
445 SetLastError(CRYPT_E_ASN1_ERROR);
449 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
453 bytesNeeded += 1 + lenBytes;
456 if (*pbEncoded < bytesNeeded)
458 SetLastError(ERROR_MORE_DATA);
463 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
464 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
465 pbEncoded += lenBytes;
471 *pbEncoded++ = firstByte;
472 ptr = pszObjId + firstPos;
475 sscanf(ptr, "%d%n", &val, &pos);
477 unsigned char outBytes[5];
480 if (val >= 0x10000000)
482 else if (val >= 0x200000)
484 else if (val >= 0x4000)
486 else if (val >= 0x80)
490 for (i = numBytes; i > 0; i--)
492 outBytes[i - 1] = val & 0x7f;
495 for (i = 0; i < numBytes - 1; i++)
496 *pbEncoded++ = outBytes[i] | 0x80;
497 *pbEncoded++ = outBytes[i];
506 *pcbEncoded = bytesNeeded;
510 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
511 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
514 DWORD bytesNeeded, lenBytes, encodedLen;
517 switch (value->dwValueType)
519 case CERT_RDN_NUMERIC_STRING:
520 tag = ASN_NUMERICSTRING;
521 encodedLen = value->Value.cbData;
523 case CERT_RDN_PRINTABLE_STRING:
524 tag = ASN_PRINTABLESTRING;
525 encodedLen = value->Value.cbData;
527 case CERT_RDN_IA5_STRING:
529 encodedLen = value->Value.cbData;
531 case CERT_RDN_ANY_TYPE:
532 /* explicitly disallowed */
533 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
536 FIXME("String type %ld unimplemented\n", value->dwValueType);
539 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
540 bytesNeeded = 1 + lenBytes + encodedLen;
543 if (*pcbEncoded < bytesNeeded)
545 SetLastError(ERROR_MORE_DATA);
551 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
552 pbEncoded += lenBytes;
553 switch (value->dwValueType)
555 case CERT_RDN_NUMERIC_STRING:
556 case CERT_RDN_PRINTABLE_STRING:
557 case CERT_RDN_IA5_STRING:
558 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
562 *pcbEncoded = bytesNeeded;
566 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
567 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
569 DWORD bytesNeeded = 0, lenBytes, size;
572 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, attr->pszObjId, NULL, &size);
576 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
577 * with dwValueType, so "cast" it to get its encoded size
579 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
580 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
584 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
585 bytesNeeded += 1 + lenBytes;
588 if (*pcbEncoded < bytesNeeded)
590 SetLastError(ERROR_MORE_DATA);
595 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
596 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
598 pbEncoded += lenBytes;
599 size = bytesNeeded - 1 - lenBytes;
600 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, attr->pszObjId,
605 size = bytesNeeded - 1 - lenBytes - size;
606 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
607 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
612 *pcbEncoded = bytesNeeded;
618 static int BLOBComp(const void *l, const void *r)
620 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
623 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
624 ret = a->cbData - b->cbData;
628 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
630 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
631 BYTE *pbEncoded, DWORD *pcbEncoded)
633 DWORD bytesNeeded = 0, lenBytes, i;
635 CRYPT_DER_BLOB *blobs = NULL;
642 SetLastError(STATUS_ACCESS_VIOLATION);
647 blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
648 rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
653 for (i = 0; ret && i < rdn->cRDNAttr; i++)
655 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
656 NULL, &blobs[i].cbData);
658 bytesNeeded += blobs[i].cbData;
660 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
661 bytesNeeded += 1 + lenBytes;
666 if (*pcbEncoded < bytesNeeded)
668 SetLastError(ERROR_MORE_DATA);
673 for (i = 0; ret && i < rdn->cRDNAttr; i++)
675 blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
677 if (!blobs[i].pbData)
680 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
681 &rdn->rgRDNAttr[i], blobs[i].pbData, &blobs[i].cbData);
685 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
687 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
688 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
690 pbEncoded += lenBytes;
691 for (i = 0; ret && i < rdn->cRDNAttr; i++)
693 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
694 pbEncoded += blobs[i].cbData;
699 *pcbEncoded = bytesNeeded;
703 for (i = 0; i < rdn->cRDNAttr; i++)
704 HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
705 HeapFree(GetProcessHeap(), 0, blobs);
710 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
711 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
712 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
714 CERT_NAME_INFO *info = (CERT_NAME_INFO *)pvStructInfo;
715 DWORD bytesNeeded = 0, lenBytes, size, i;
720 SetLastError(STATUS_ACCESS_VIOLATION);
723 if (info->cRDN && !info->rgRDN)
725 SetLastError(STATUS_ACCESS_VIOLATION);
728 TRACE("encoding name with %ld RDNs\n", info->cRDN);
730 for (i = 0; ret && i < info->cRDN; i++)
732 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
737 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
738 bytesNeeded += 1 + lenBytes;
743 *pcbEncoded = bytesNeeded;
746 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
747 pcbEncoded, bytesNeeded))
749 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
750 pbEncoded = *(BYTE **)pbEncoded;
751 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
752 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, &size);
754 for (i = 0; ret && i < info->cRDN; i++)
757 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
769 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
770 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
771 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
773 CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)pvStructInfo;
774 DWORD bytesNeeded, lenBytes;
778 SetLastError(STATUS_ACCESS_VIOLATION);
781 /* FIXME: use exception handling to catch bogus pointers */
782 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
783 bytesNeeded = 1 + lenBytes + blob->cbData;
786 *pcbEncoded = bytesNeeded;
789 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
792 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
793 pbEncoded = *(BYTE **)pbEncoded;
794 *pbEncoded++ = ASN_OCTETSTRING;
795 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
796 pbEncoded += lenBytes;
798 memcpy(pbEncoded, blob->pbData, blob->cbData);
802 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
803 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
804 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
806 CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
807 DWORD bytesNeeded, lenBytes, dataBytes;
812 SetLastError(STATUS_ACCESS_VIOLATION);
815 /* FIXME: use exception handling to catch bogus pointers */
816 /* yep, MS allows cUnusedBits to be >= 8 */
817 if (blob->cbData * 8 > blob->cUnusedBits)
819 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
820 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
828 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
829 bytesNeeded = 1 + lenBytes + dataBytes + 1;
832 *pcbEncoded = bytesNeeded;
835 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
838 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
839 pbEncoded = *(BYTE **)pbEncoded;
840 *pbEncoded++ = ASN_BITSTRING;
841 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
842 pbEncoded += lenBytes;
843 *pbEncoded++ = unusedBits;
846 BYTE mask = 0xff << unusedBits;
850 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
851 pbEncoded += dataBytes - 1;
853 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
858 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
859 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
860 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
863 BYTE significantBytes, padByte = 0, bytesNeeded;
864 BOOL neg = FALSE, pad = FALSE;
868 SetLastError(STATUS_ACCESS_VIOLATION);
872 memcpy(&val, pvStructInfo, sizeof(val));
873 /* Count the number of significant bytes. Temporarily swap sign for
874 * negatives so I count the minimum number of bytes.
881 for (significantBytes = sizeof(val); !(val & 0xff000000);
882 val <<= 8, significantBytes--)
887 if ((val & 0xff000000) < 0x80000000)
893 else if ((val & 0xff000000) > 0x7f000000)
898 bytesNeeded = 2 + significantBytes;
903 *pcbEncoded = bytesNeeded;
906 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
909 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
910 pbEncoded = *(BYTE **)pbEncoded;
911 *pbEncoded++ = ASN_INTEGER;
914 *pbEncoded++ = significantBytes + 1;
915 *pbEncoded++ = padByte;
918 *pbEncoded++ = significantBytes;
919 for (i = 0; i < significantBytes; i++, val <<= 8)
920 *(pbEncoded + i) = (BYTE)((val & 0xff000000) >> 24);
924 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
925 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
926 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
928 DWORD significantBytes, lenBytes;
929 BYTE padByte = 0, bytesNeeded;
931 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
935 SetLastError(STATUS_ACCESS_VIOLATION);
939 /* FIXME: use exception handling to protect against bogus pointers */
940 significantBytes = blob->cbData;
941 if (significantBytes)
943 if (blob->pbData[significantBytes - 1] & 0x80)
945 /* negative, lop off leading (little-endian) 0xffs */
946 for (; significantBytes > 0 &&
947 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
949 if (blob->pbData[significantBytes - 1] < 0x80)
957 /* positive, lop off leading (little-endian) zeroes */
958 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
961 if (blob->pbData[significantBytes - 1] > 0x7f)
969 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
971 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
972 bytesNeeded = 1 + lenBytes + significantBytes;
977 *pcbEncoded = bytesNeeded;
980 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
983 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
984 pbEncoded = *(BYTE **)pbEncoded;
985 *pbEncoded++ = ASN_INTEGER;
988 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
989 pbEncoded += lenBytes;
990 *pbEncoded++ = padByte;
994 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
995 pbEncoded += lenBytes;
997 for (; significantBytes > 0; significantBytes--)
998 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1002 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1003 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1004 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1006 DWORD significantBytes, lenBytes;
1009 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
1013 SetLastError(STATUS_ACCESS_VIOLATION);
1017 /* FIXME: use exception handling to protect against bogus pointers */
1018 significantBytes = blob->cbData;
1019 if (significantBytes)
1021 /* positive, lop off leading (little-endian) zeroes */
1022 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1025 if (blob->pbData[significantBytes - 1] > 0x7f)
1029 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1031 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1032 bytesNeeded = 1 + lenBytes + significantBytes;
1037 *pcbEncoded = bytesNeeded;
1040 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
1043 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1044 pbEncoded = *(BYTE **)pbEncoded;
1045 *pbEncoded++ = ASN_INTEGER;
1048 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1049 pbEncoded += lenBytes;
1054 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1055 pbEncoded += lenBytes;
1057 for (; significantBytes > 0; significantBytes--)
1058 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1062 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
1063 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1064 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1066 CRYPT_INTEGER_BLOB blob;
1069 /* Encode as an unsigned integer, then change the tag to enumerated */
1070 blob.cbData = sizeof(DWORD);
1071 blob.pbData = (BYTE *)pvStructInfo;
1072 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
1073 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1074 if (ret && pbEncoded)
1076 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1077 pbEncoded = *(BYTE **)pbEncoded;
1078 pbEncoded[0] = ASN_ENUMERATED;
1083 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
1084 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1085 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1088 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
1089 * temporary buffer because the output buffer is not NULL-terminated.
1092 static const DWORD bytesNeeded = sizeof(buf) - 1;
1096 SetLastError(STATUS_ACCESS_VIOLATION);
1099 /* Sanity check the year, this is a two-digit year format */
1100 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1102 if (sysTime.wYear < 1950 || sysTime.wYear > 2050)
1104 SetLastError(CRYPT_E_BAD_ENCODE);
1109 *pcbEncoded = bytesNeeded;
1112 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
1115 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1116 pbEncoded = *(BYTE **)pbEncoded;
1117 buf[0] = ASN_UTCTIME;
1118 buf[1] = bytesNeeded - 2;
1119 snprintf(buf + 2, sizeof(buf) - 2, "%02d%02d%02d%02d%02d%02dZ",
1120 sysTime.wYear >= 2000 ? sysTime.wYear - 2000 : sysTime.wYear - 1900,
1121 sysTime.wDay, sysTime.wMonth, sysTime.wHour, sysTime.wMinute,
1123 memcpy(pbEncoded, buf, bytesNeeded);
1127 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
1128 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1129 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1132 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
1133 * temporary buffer because the output buffer is not NULL-terminated.
1136 static const DWORD bytesNeeded = sizeof(buf) - 1;
1140 SetLastError(STATUS_ACCESS_VIOLATION);
1145 *pcbEncoded = bytesNeeded;
1148 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1150 if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
1153 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1154 pbEncoded = *(BYTE **)pbEncoded;
1155 buf[0] = ASN_GENERALTIME;
1156 buf[1] = bytesNeeded - 2;
1157 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
1158 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1159 sysTime.wMinute, sysTime.wSecond);
1160 memcpy(pbEncoded, buf, bytesNeeded);
1164 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
1165 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1166 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1173 SetLastError(STATUS_ACCESS_VIOLATION);
1176 /* Check the year, if it's in the UTCTime range call that encode func */
1177 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1179 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
1180 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
1181 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1183 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
1184 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1189 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
1190 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
1192 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1193 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
1194 BYTE *pbEncoded, DWORD *pcbEncoded)
1198 CryptEncodeObjectExFunc encodeFunc = NULL;
1200 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n",
1201 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1202 "(integer value)", pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1205 if (!pbEncoded && !pcbEncoded)
1207 SetLastError(ERROR_INVALID_PARAMETER);
1210 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
1211 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
1213 SetLastError(ERROR_FILE_NOT_FOUND);
1217 SetLastError(NOERROR);
1218 if (!HIWORD(lpszStructType))
1220 switch (LOWORD(lpszStructType))
1222 case (WORD)X509_NAME:
1223 encodeFunc = CRYPT_AsnEncodeName;
1225 case (WORD)X509_OCTET_STRING:
1226 encodeFunc = CRYPT_AsnEncodeOctets;
1228 case (WORD)X509_BITS:
1229 case (WORD)X509_KEY_USAGE:
1230 encodeFunc = CRYPT_AsnEncodeBits;
1232 case (WORD)X509_INTEGER:
1233 encodeFunc = CRYPT_AsnEncodeInt;
1235 case (WORD)X509_MULTI_BYTE_INTEGER:
1236 encodeFunc = CRYPT_AsnEncodeInteger;
1238 case (WORD)X509_MULTI_BYTE_UINT:
1239 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
1241 case (WORD)X509_ENUMERATED:
1242 encodeFunc = CRYPT_AsnEncodeEnumerated;
1244 case (WORD)X509_CHOICE_OF_TIME:
1245 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
1247 case (WORD)PKCS_UTC_TIME:
1248 encodeFunc = CRYPT_AsnEncodeUtcTime;
1251 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1254 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1255 encodeFunc = CRYPT_AsnEncodeUtcTime;
1256 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
1257 encodeFunc = CRYPT_AsnEncodeEnumerated;
1258 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
1259 encodeFunc = CRYPT_AsnEncodeBits;
1260 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
1261 encodeFunc = CRYPT_AsnEncodeOctets;
1263 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1264 lpszStructType, "CryptEncodeObjectEx", &lib);
1266 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
1267 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1269 SetLastError(ERROR_FILE_NOT_FOUND);
1275 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1276 DWORD, DWORD, void *, DWORD *);
1278 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1279 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
1280 DWORD *pcbStructInfo)
1284 CryptDecodeObjectFunc pCryptDecodeObject;
1286 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
1287 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1288 "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1291 if (!pvStructInfo && !pcbStructInfo)
1293 SetLastError(ERROR_INVALID_PARAMETER);
1297 /* Try registered DLL first.. */
1298 pCryptDecodeObject =
1299 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
1300 lpszStructType, "CryptDecodeObject", &lib);
1301 if (pCryptDecodeObject)
1303 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
1304 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1309 /* If not, use CryptDecodeObjectEx */
1310 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
1311 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
1316 /* Gets the number of length bytes from the given (leading) length byte */
1317 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
1319 /* Helper function to get the encoded length of the data starting at pbEncoded,
1320 * where pbEncoded[0] is the tag. If the data are too short to contain a
1321 * length or if the length is too large for cbEncoded, sets an appropriate
1322 * error code and returns FALSE.
1324 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
1331 SetLastError(CRYPT_E_ASN1_EOD);
1334 else if (pbEncoded[1] <= 0x7f)
1336 *len = pbEncoded[1];
1341 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
1343 if (lenLen > sizeof(DWORD))
1345 SetLastError(CRYPT_E_ASN1_LARGE);
1348 else if (lenLen + 2 > cbEncoded)
1350 SetLastError(CRYPT_E_ASN1_CORRUPT);
1361 out |= *pbEncoded++;
1363 if (out + lenLen + 1 > cbEncoded)
1365 SetLastError(CRYPT_E_ASN1_EOD);
1378 /* Helper function to check *pcbStructInfo, set it to the required size, and
1379 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
1380 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
1381 * pointer to the newly allocated memory.
1383 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
1384 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
1389 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1391 if (pDecodePara && pDecodePara->pfnAlloc)
1392 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
1394 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
1395 if (!*(BYTE **)pvStructInfo)
1398 *pcbStructInfo = bytesNeeded;
1400 else if (*pcbStructInfo < bytesNeeded)
1402 *pcbStructInfo = bytesNeeded;
1403 SetLastError(ERROR_MORE_DATA);
1409 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_FLAG. */
1410 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1411 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, LPSTR pszObjId,
1415 DWORD bytesNeeded, dataLen;
1418 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1420 if (pbEncoded[0] != ASN_OBJECTIDENTIFIER)
1422 SetLastError(CRYPT_E_ASN1_BADTAG);
1425 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1428 /* The largest possible string for the first two components is 2.175
1429 * (= 2 * 40 + 175 = 255), so this is big enough.
1434 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1435 pbEncoded[1 + lenBytes] / 40,
1436 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40) * 40);
1437 bytesNeeded = strlen(firstTwo) + 1;
1438 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1439 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1441 /* large enough for ".4000000" */
1445 while (ptr - pbEncoded - 1 - lenBytes < dataLen && (*ptr & 0x80))
1451 if (ptr - pbEncoded - 1 - lenBytes >= dataLen || (*ptr & 0x80))
1453 SetLastError(CRYPT_E_ASN1_CORRUPT);
1460 snprintf(str, sizeof(str), ".%d", val);
1461 bytesNeeded += strlen(str);
1465 *pcbObjId = bytesNeeded;
1466 else if (*pcbObjId < bytesNeeded)
1468 *pcbObjId = bytesNeeded;
1469 SetLastError(ERROR_MORE_DATA);
1474 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1475 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40) * 40);
1476 pszObjId += strlen(pszObjId);
1477 for (ptr = pbEncoded + 2 + lenBytes; ret &&
1478 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1482 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1491 sprintf(pszObjId, ".%d", val);
1492 pszObjId += strlen(pszObjId);
1498 *pcbObjId = bytesNeeded;
1502 /* Warning: this assumes the address of value->Value.pbData is already set, in
1503 * order to avoid overwriting memory. (In some cases, it may change it, if it
1504 * doesn't copy anything to memory.) Be sure to set it correctly!
1506 static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
1507 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value,
1510 DWORD bytesNeeded, dataLen;
1514 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1516 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1517 switch (pbEncoded[0])
1519 case ASN_NUMERICSTRING:
1520 case ASN_PRINTABLESTRING:
1524 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
1525 SetLastError(OSS_UNIMPLEMENTED);
1528 bytesNeeded = sizeof(CERT_NAME_VALUE);
1531 switch (pbEncoded[0])
1533 case ASN_NUMERICSTRING:
1534 case ASN_PRINTABLESTRING:
1536 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1537 bytesNeeded += dataLen;
1543 *pcbValue = bytesNeeded;
1546 if (*pcbValue < bytesNeeded)
1548 *pcbValue = bytesNeeded;
1549 SetLastError(ERROR_MORE_DATA);
1552 *pcbValue = bytesNeeded;
1553 switch (pbEncoded[0])
1555 case ASN_NUMERICSTRING:
1556 value->dwValueType = CERT_RDN_NUMERIC_STRING;
1558 case ASN_PRINTABLESTRING:
1559 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
1562 value->dwValueType = CERT_RDN_IA5_STRING;
1567 switch (pbEncoded[0])
1569 case ASN_NUMERICSTRING:
1570 case ASN_PRINTABLESTRING:
1572 value->Value.cbData = dataLen;
1573 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1574 value->Value.pbData = (BYTE *)pbEncoded + 1 + lenBytes;
1577 if (!value->Value.pbData)
1579 SetLastError(CRYPT_E_ASN1_INTERNAL);
1583 memcpy(value->Value.pbData, pbEncoded + 1 + lenBytes,
1591 value->Value.cbData = 0;
1592 value->Value.pbData = NULL;
1597 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
1598 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr,
1602 DWORD bytesNeeded, dataLen, size;
1605 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1607 /* The data length must be at least 4, two for the tag and length for the
1608 * OID, and two for the string (assuming both have short-form lengths.)
1612 SetLastError(CRYPT_E_ASN1_EOD);
1615 if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCE))
1617 SetLastError(CRYPT_E_ASN1_BADTAG);
1620 bytesNeeded = sizeof(CERT_RDN_ATTR);
1621 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1622 ret = CRYPT_AsnDecodeOid(dwCertEncodingType, pbEncoded + 1 + lenBytes,
1623 cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
1626 /* ugly: need to know the size of the next element of the sequence,
1627 * so get it directly
1629 DWORD objIdOfset = 1 + lenBytes, objIdLen, nameValueOffset = 0;
1631 ret = CRYPT_GetLen(pbEncoded + objIdOfset, cbEncoded - objIdOfset,
1633 bytesNeeded += size;
1634 /* hack: like encoding, this takes advantage of the fact that the rest
1635 * of the structure is identical to a CERT_NAME_VALUE.
1639 nameValueOffset = objIdOfset + objIdLen + 1 +
1640 GET_LEN_BYTES(pbEncoded[objIdOfset]);
1641 ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType,
1642 pbEncoded + nameValueOffset, cbEncoded - nameValueOffset, dwFlags,
1647 bytesNeeded += size;
1649 *pcbAttr = bytesNeeded;
1650 else if (*pcbAttr < bytesNeeded)
1652 *pcbAttr = bytesNeeded;
1653 SetLastError(ERROR_MORE_DATA);
1658 BYTE *originalData = attr->Value.pbData;
1660 *pcbAttr = bytesNeeded;
1661 /* strange: decode the value first, because it has a counted
1662 * size, and we can store the OID after it. Keep track of the
1663 * original data pointer, we'll need to know whether it was
1667 ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType,
1668 pbEncoded + nameValueOffset, cbEncoded - nameValueOffset,
1669 dwFlags, (CERT_NAME_VALUE *)&attr->dwValueType, &size);
1674 /* if the data were copied to the original location,
1675 * the OID goes after. Otherwise it goes in the
1676 * spot originally reserved for the data.
1678 if (attr->Value.pbData == originalData)
1679 attr->pszObjId = (LPSTR)(attr->Value.pbData +
1680 attr->Value.cbData);
1682 attr->pszObjId = originalData;
1683 size = bytesNeeded - size;
1684 ret = CRYPT_AsnDecodeOid(dwCertEncodingType,
1685 pbEncoded + objIdOfset, cbEncoded - objIdOfset,
1686 dwFlags, attr->pszObjId, &size);
1689 attr->pszObjId = NULL;
1697 static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
1698 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN *rdn,
1702 DWORD bytesNeeded, dataLen, cRDNAttr = 0;
1705 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1707 if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SETOF))
1709 SetLastError(CRYPT_E_ASN1_BADTAG);
1712 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1713 bytesNeeded = sizeof(CERT_RDN);
1719 for (ptr = pbEncoded + 1 + lenBytes; ret &&
1720 ptr - pbEncoded - 1 - lenBytes < dataLen; )
1722 ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1723 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1729 bytesNeeded += size;
1730 ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1733 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1741 *pcbRdn = bytesNeeded;
1744 if (*pcbRdn < bytesNeeded)
1746 *pcbRdn = bytesNeeded;
1747 SetLastError(ERROR_MORE_DATA);
1750 *pcbRdn = bytesNeeded;
1751 rdn->cRDNAttr = cRDNAttr;
1752 if (rdn->cRDNAttr == 0)
1753 rdn->rgRDNAttr = NULL;
1760 rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn + sizeof(CERT_RDN));
1761 nextData = (BYTE *)rdn->rgRDNAttr +
1762 rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
1763 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret && i < cRDNAttr &&
1764 ptr - pbEncoded - 1 - lenBytes < dataLen; i++)
1766 rdn->rgRDNAttr[i].Value.pbData = nextData;
1768 ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1769 cbEncoded - (ptr - pbEncoded), dwFlags, &rdn->rgRDNAttr[i],
1775 bytesNeeded -= size;
1776 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the data may not
1779 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
1780 nextData += rdn->rgRDNAttr[i].Value.cbData;
1781 /* Ugly: the OID, if copied, is stored in memory after the
1782 * value, so increment by its string length if it's set and
1785 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId == nextData)
1786 nextData += strlen(rdn->rgRDNAttr[i].pszObjId) + 1;
1787 ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1790 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1798 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
1799 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1800 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1803 DWORD bytesNeeded, dataLen, cRDN = 0;
1808 SetLastError(CRYPT_E_ASN1_EOD);
1811 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1813 if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
1815 SetLastError(CRYPT_E_ASN1_BADTAG);
1818 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1819 bytesNeeded = sizeof(CERT_NAME_INFO);
1825 for (ptr = pbEncoded + 1 + lenBytes; ret && ptr - pbEncoded - 1 -
1826 lenBytes < dataLen; )
1828 ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1829 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1835 bytesNeeded += size;
1836 ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1839 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1845 CERT_NAME_INFO *info;
1849 *pcbStructInfo = bytesNeeded;
1852 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1853 pcbStructInfo, bytesNeeded))
1855 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1856 pvStructInfo = *(BYTE **)pvStructInfo;
1857 info = (CERT_NAME_INFO *)pvStructInfo;
1859 if (info->cRDN == 0)
1867 info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
1868 sizeof(CERT_NAME_INFO));
1869 nextData = (BYTE *)info->rgRDN + info->cRDN * sizeof(CERT_RDN);
1870 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret && i < cRDN &&
1871 ptr - pbEncoded - 1 - lenBytes < dataLen; i++)
1873 info->rgRDN[i].rgRDNAttr = (CERT_RDN_ATTR *)nextData;
1875 ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1876 cbEncoded - (ptr - pbEncoded), dwFlags, &info->rgRDN[i],
1883 bytesNeeded -= size;
1884 ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1887 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1895 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
1896 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1897 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1899 CRYPT_DATA_BLOB *blob;
1900 DWORD bytesNeeded, dataLen;
1904 SetLastError(CRYPT_E_ASN1_EOD);
1907 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1909 if (pbEncoded[0] != ASN_OCTETSTRING)
1911 SetLastError(CRYPT_E_ASN1_BADTAG);
1914 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1915 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
1917 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
1920 *pcbStructInfo = bytesNeeded;
1923 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1924 pcbStructInfo, bytesNeeded))
1926 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1927 pvStructInfo = *(BYTE **)pvStructInfo;
1928 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
1929 blob->cbData = dataLen;
1930 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1931 blob->pbData = (BYTE *)pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]);
1934 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB);
1936 memcpy(blob->pbData, pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]),
1942 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
1943 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1944 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1946 CRYPT_BIT_BLOB *blob;
1947 DWORD bytesNeeded, dataLen;
1951 SetLastError(CRYPT_E_ASN1_EOD);
1954 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1956 if (pbEncoded[0] != ASN_BITSTRING)
1958 SetLastError(CRYPT_E_ASN1_BADTAG);
1961 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1962 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1964 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
1967 *pcbStructInfo = bytesNeeded;
1970 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1971 pcbStructInfo, bytesNeeded))
1973 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1974 pvStructInfo = *(BYTE **)pvStructInfo;
1975 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1976 blob->cbData = dataLen - 1;
1977 blob->cUnusedBits = *(pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]));
1978 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1979 blob->pbData = (BYTE *)pbEncoded + 2 + GET_LEN_BYTES(pbEncoded[1]);
1982 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
1985 BYTE mask = 0xff << blob->cUnusedBits;
1987 memcpy(blob->pbData, pbEncoded + 2 + GET_LEN_BYTES(pbEncoded[1]),
1989 blob->pbData[blob->cbData - 1] &= mask;
1995 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
1996 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1997 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2001 if (!pbEncoded || !cbEncoded)
2003 SetLastError(CRYPT_E_ASN1_EOD);
2008 *pcbStructInfo = sizeof(int);
2011 if (pbEncoded[0] != ASN_INTEGER)
2013 SetLastError(CRYPT_E_ASN1_BADTAG);
2018 SetLastError(CRYPT_E_ASN1_EOD);
2021 if (pbEncoded[1] == 0)
2023 SetLastError(CRYPT_E_ASN1_CORRUPT);
2026 if (pbEncoded[1] > sizeof(int))
2028 SetLastError(CRYPT_E_ASN1_LARGE);
2031 if (pbEncoded[2] & 0x80)
2033 /* initialize to a negative value to sign-extend */
2038 for (i = 0; i < pbEncoded[1]; i++)
2041 val |= pbEncoded[2 + i];
2043 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2044 pcbStructInfo, sizeof(int)))
2046 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2047 pvStructInfo = *(BYTE **)pvStructInfo;
2048 memcpy(pvStructInfo, &val, sizeof(int));
2052 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
2053 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2054 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2056 DWORD bytesNeeded, dataLen;
2058 CRYPT_INTEGER_BLOB *blob;
2062 SetLastError(CRYPT_E_ASN1_EOD);
2065 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
2067 if (pbEncoded[0] != ASN_INTEGER)
2069 SetLastError(CRYPT_E_ASN1_BADTAG);
2072 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2073 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2076 *pcbStructInfo = bytesNeeded;
2079 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2080 pcbStructInfo, bytesNeeded))
2082 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2083 pvStructInfo = *(BYTE **)pvStructInfo;
2084 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2085 blob->cbData = dataLen;
2086 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_INTEGER_BLOB);
2091 for (i = 0; i < blob->cbData; i++)
2092 blob->pbData[i] = *(pbEncoded + 1 + lenBytes + dataLen - i - 1);
2097 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
2098 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2099 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2101 DWORD bytesNeeded, dataLen;
2103 CRYPT_INTEGER_BLOB *blob;
2107 SetLastError(CRYPT_E_ASN1_EOD);
2110 if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
2112 if (pbEncoded[0] != ASN_INTEGER)
2114 SetLastError(CRYPT_E_ASN1_BADTAG);
2117 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2118 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2121 *pcbStructInfo = bytesNeeded;
2124 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2125 pcbStructInfo, bytesNeeded))
2127 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2128 pvStructInfo = *(BYTE **)pvStructInfo;
2129 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2130 blob->cbData = dataLen;
2131 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_INTEGER_BLOB);
2132 /* remove leading zero byte if it exists */
2133 if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
2142 for (i = 0; i < blob->cbData; i++)
2143 blob->pbData[i] = *(pbEncoded + 1 + lenBytes + pbEncoded[1] - i -
2149 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
2150 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2151 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2153 unsigned int val = 0, i;
2155 /* Based on CRYPT_AsnDecodeInt, but interprets as unsigned */
2156 if (!pbEncoded || !cbEncoded)
2158 SetLastError(CRYPT_E_ASN1_EOD);
2163 *pcbStructInfo = sizeof(int);
2166 if (pbEncoded[0] != ASN_ENUMERATED)
2168 SetLastError(CRYPT_E_ASN1_BADTAG);
2173 SetLastError(CRYPT_E_ASN1_EOD);
2176 if (pbEncoded[1] == 0)
2178 SetLastError(CRYPT_E_ASN1_CORRUPT);
2181 /* A little strange looking, but we have to accept a sign byte: 0xffffffff
2182 * gets encoded as 0a 05 00 ff ff ff ff. Also, assuming a small length is
2183 * okay here, it has to be in short form.
2185 if (pbEncoded[1] > sizeof(unsigned int) + 1)
2187 SetLastError(CRYPT_E_ASN1_LARGE);
2190 for (i = 0; i < pbEncoded[1]; i++)
2193 val |= pbEncoded[2 + i];
2195 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2196 pcbStructInfo, sizeof(unsigned int)))
2198 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2199 pvStructInfo = *(BYTE **)pvStructInfo;
2200 memcpy(pvStructInfo, &val, sizeof(unsigned int));
2204 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
2209 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
2211 if (!isdigit(*(pbEncoded))) \
2213 SetLastError(CRYPT_E_ASN1_CORRUPT); \
2217 (word) += *(pbEncoded)++ - '0'; \
2221 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
2222 SYSTEMTIME *sysTime)
2226 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
2228 WORD hours, minutes = 0;
2229 BYTE sign = *pbEncoded++;
2232 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
2235 SetLastError(CRYPT_E_ASN1_CORRUPT);
2241 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
2244 SetLastError(CRYPT_E_ASN1_CORRUPT);
2251 sysTime->wHour += hours;
2252 sysTime->wMinute += minutes;
2256 if (hours > sysTime->wHour)
2259 sysTime->wHour = 24 - (hours - sysTime->wHour);
2262 sysTime->wHour -= hours;
2263 if (minutes > sysTime->wMinute)
2266 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
2269 sysTime->wMinute -= minutes;
2276 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
2277 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2278 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2280 SYSTEMTIME sysTime = { 0 };
2284 if (!pbEncoded || !cbEncoded)
2286 SetLastError(CRYPT_E_ASN1_EOD);
2291 *pcbStructInfo = sizeof(FILETIME);
2294 if (pbEncoded[0] != ASN_UTCTIME)
2296 SetLastError(CRYPT_E_ASN1_BADTAG);
2301 SetLastError(CRYPT_E_ASN1_EOD);
2304 if (pbEncoded[1] > 0x7f)
2306 /* long-form date strings really can't be valid */
2307 SetLastError(CRYPT_E_ASN1_CORRUPT);
2311 /* FIXME: magic # */
2314 SetLastError(CRYPT_E_ASN1_CORRUPT);
2318 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
2319 if (sysTime.wYear >= 50)
2320 sysTime.wYear += 1900;
2322 sysTime.wYear += 2000;
2323 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
2324 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
2325 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
2326 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
2329 if (len >= 2 && isdigit(*pbEncoded) && isdigit(*(pbEncoded + 1)))
2330 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
2331 else if (isdigit(*pbEncoded))
2332 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, sysTime.wSecond);
2333 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
2337 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2338 pcbStructInfo, sizeof(FILETIME)))
2342 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2343 pvStructInfo = *(BYTE **)pvStructInfo;
2344 ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
2350 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
2351 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2352 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2354 SYSTEMTIME sysTime = { 0 };
2358 if (!pbEncoded || !cbEncoded)
2360 SetLastError(CRYPT_E_ASN1_EOD);
2365 *pcbStructInfo = sizeof(FILETIME);
2368 if (pbEncoded[0] != ASN_GENERALTIME)
2370 SetLastError(CRYPT_E_ASN1_BADTAG);
2375 SetLastError(CRYPT_E_ASN1_EOD);
2378 if (pbEncoded[1] > 0x7f)
2380 /* long-form date strings really can't be valid */
2381 SetLastError(CRYPT_E_ASN1_CORRUPT);
2385 /* FIXME: magic # */
2388 SetLastError(CRYPT_E_ASN1_CORRUPT);
2392 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
2393 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
2394 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
2395 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
2398 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
2400 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
2401 if (len > 0 && (*pbEncoded == '.' || *pbEncoded == ','))
2407 digits = min(len, 3); /* workaround macro weirdness */
2408 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
2409 sysTime.wMilliseconds);
2411 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
2415 if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2416 pcbStructInfo, sizeof(FILETIME)))
2420 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2421 pvStructInfo = *(BYTE **)pvStructInfo;
2422 ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
2428 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
2429 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2430 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2434 if (!pbEncoded || !cbEncoded)
2436 SetLastError(CRYPT_E_ASN1_EOD);
2441 *pcbStructInfo = sizeof(FILETIME);
2445 if (pbEncoded[0] == ASN_UTCTIME)
2446 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
2447 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
2449 else if (pbEncoded[0] == ASN_GENERALTIME)
2450 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
2451 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
2452 pvStructInfo, pcbStructInfo);
2455 SetLastError(CRYPT_E_ASN1_BADTAG);
2461 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
2462 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
2464 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2465 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2466 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2470 CryptDecodeObjectExFunc decodeFunc = NULL;
2472 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
2473 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
2474 "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
2475 pvStructInfo, pcbStructInfo);
2477 if (!pvStructInfo && !pcbStructInfo)
2479 SetLastError(ERROR_INVALID_PARAMETER);
2482 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2483 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2485 SetLastError(ERROR_FILE_NOT_FOUND);
2489 SetLastError(NOERROR);
2490 if (!HIWORD(lpszStructType))
2492 switch (LOWORD(lpszStructType))
2494 case (WORD)X509_NAME:
2495 decodeFunc = CRYPT_AsnDecodeName;
2497 case (WORD)X509_OCTET_STRING:
2498 decodeFunc = CRYPT_AsnDecodeOctets;
2500 case (WORD)X509_BITS:
2501 case (WORD)X509_KEY_USAGE:
2502 decodeFunc = CRYPT_AsnDecodeBits;
2504 case (WORD)X509_INTEGER:
2505 decodeFunc = CRYPT_AsnDecodeInt;
2507 case (WORD)X509_MULTI_BYTE_INTEGER:
2508 decodeFunc = CRYPT_AsnDecodeInteger;
2510 case (WORD)X509_MULTI_BYTE_UINT:
2511 decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
2513 case (WORD)X509_ENUMERATED:
2514 decodeFunc = CRYPT_AsnDecodeEnumerated;
2516 case (WORD)X509_CHOICE_OF_TIME:
2517 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
2519 case (WORD)PKCS_UTC_TIME:
2520 decodeFunc = CRYPT_AsnDecodeUtcTime;
2523 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2526 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2527 decodeFunc = CRYPT_AsnDecodeUtcTime;
2528 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2529 decodeFunc = CRYPT_AsnDecodeEnumerated;
2530 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2531 decodeFunc = CRYPT_AsnDecodeBits;
2532 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2533 decodeFunc = CRYPT_AsnDecodeOctets;
2535 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
2536 lpszStructType, "CryptDecodeObjectEx", &lib);
2538 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
2539 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
2541 SetLastError(ERROR_FILE_NOT_FOUND);