2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2005 Juan Lang
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * This file implements ASN.1 DER encoding and decoding of a limited set of
20 * types. It isn't a full ASN.1 implementation. Microsoft implements BER
21 * encoding of many of the basic types in msasn1.dll, but that interface is
22 * undocumented, so I implement them here.
25 * "A Layman's Guide to a Subset of ASN.1, BER, and DER", by Burton Kaliski
26 * (available online, look for a PDF copy as the HTML versions tend to have
27 * translation errors.)
29 * RFC3280, http://www.faqs.org/rfcs/rfc3280.html
32 * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
44 #include "wine/debug.h"
45 #include "wine/exception.h"
47 /* This is a bit arbitrary, but to set some limit: */
48 #define MAX_ENCODED_LEN 0x02000000
50 /* a few asn.1 tags we need */
51 #define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
52 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
53 #define ASN_OCTETSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
54 #define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
55 #define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
56 #define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
57 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
58 #define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
59 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
60 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
62 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
64 static const WCHAR szDllName[] = { 'D','l','l',0 };
66 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
68 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
69 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
70 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
71 DWORD, DWORD, void *, DWORD *);
72 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
73 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
75 /* Prototypes for built-in encoders/decoders. They follow the Ex style
76 * prototypes. The dwCertEncodingType and lpszStructType are ignored by the
77 * built-in functions, but the parameters are retained to simplify
78 * CryptEncodeObjectEx/CryptDecodeObjectEx, since they must call functions in
79 * external DLLs that follow these signatures.
80 * FIXME: some built-in functions are suitable to be called directly by
81 * CryptEncodeObjectEx/CryptDecodeObjectEx (they implement exception handling
82 * and memory allocation if requested), others are only suitable to be called
83 * internally. Comment which are which.
85 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
86 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
87 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
88 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
89 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
90 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
91 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
92 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
93 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
94 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
95 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
96 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
97 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
98 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
99 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
100 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
101 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
102 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
103 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
104 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
105 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
106 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
107 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
108 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
109 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
110 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
111 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
112 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
113 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
114 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
116 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
117 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
118 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
119 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
120 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
121 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
122 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
123 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
124 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
125 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
126 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
127 /* Assumes algo->Parameters.pbData is set ahead of time */
128 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
129 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
130 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
131 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
132 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
133 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
134 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
135 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
136 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
137 /* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
138 * member has been initialized, doesn't do exception handling, and doesn't do
141 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
142 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
143 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
144 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
145 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
146 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
147 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
148 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
149 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
150 /* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
151 * member has been initialized, doesn't do exception handling, and doesn't do
154 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
155 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
156 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
158 /* filter for page-fault exceptions */
159 static WINE_EXCEPTION_FILTER(page_fault)
161 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
162 return EXCEPTION_EXECUTE_HANDLER;
163 return EXCEPTION_CONTINUE_SEARCH;
166 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
169 static const char szEncodingTypeFmt[] =
170 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
172 char numericOID[7]; /* enough for "#65535" */
176 /* MSDN says the encoding type is a mask, but it isn't treated that way.
177 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
178 * "EncodingType 2" would be expected if it were a mask. Instead native
179 * stores values in "EncodingType 3".
183 snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
189 /* This is enough: the lengths of the two string parameters are explicitly
190 * counted, and we need up to five additional characters for the encoding
191 * type. These are covered by the "%d", "%s", and "%s" characters in the
192 * format specifier that are removed by sprintf.
194 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
195 szKey = HeapAlloc(GetProcessHeap(), 0, len);
197 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
201 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
202 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
208 TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
209 debugstr_w(pwszDll), pszOverrideFuncName);
211 /* This only registers functions for encoding certs, not messages */
212 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
215 /* Native does nothing pwszDll is NULL */
219 /* I'm not matching MS bug for bug here, because I doubt any app depends on
221 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
222 * it creates would never be used
223 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
224 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
226 if (!pszFuncName || !pszOID)
228 SetLastError(ERROR_INVALID_PARAMETER);
232 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
233 TRACE("Key name is %s\n", debugstr_a(szKey));
238 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
239 HeapFree(GetProcessHeap(), 0, szKey);
240 if(r != ERROR_SUCCESS)
243 /* write the values */
244 if (pszOverrideFuncName)
245 RegSetValueExA(hKey, "FuncName", 0, REG_SZ, (const BYTE*)pszOverrideFuncName,
246 lstrlenA(pszOverrideFuncName) + 1);
247 RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
248 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
254 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
260 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
262 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
265 if (!pszFuncName || !pszOID)
267 SetLastError(ERROR_INVALID_PARAMETER);
271 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
272 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
273 HeapFree(GetProcessHeap(), 0, szKey);
276 return rc ? FALSE : TRUE;
279 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
280 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
287 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
288 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
291 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
294 if (!pszFuncName || !pszOID || !pwszValueName)
296 SetLastError(ERROR_INVALID_PARAMETER);
300 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
301 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
302 HeapFree(GetProcessHeap(), 0, szKey);
307 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
308 pbValueData, pcbValueData);
313 return rc ? FALSE : TRUE;
316 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
317 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
318 const BYTE *pbValueData, DWORD cbValueData)
324 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
325 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
328 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
331 if (!pszFuncName || !pszOID || !pwszValueName)
333 SetLastError(ERROR_INVALID_PARAMETER);
337 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
338 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
339 HeapFree(GetProcessHeap(), 0, szKey);
344 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
350 return rc ? FALSE : TRUE;
353 /* Gets the registered function named szFuncName for dwCertEncodingType and
354 * lpszStructType, or NULL if one could not be found. *lib will be set to the
355 * handle of the module it's in, or NULL if no module was loaded. If the
356 * return value is NULL, *lib will also be NULL, to simplify error handling.
358 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
359 LPCSTR szFuncName, HMODULE *lib)
362 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
364 const char *funcName;
367 DWORD type, size = 0;
369 TRACE("(%08lx %s %s %p)\n", dwCertEncodingType, debugstr_a(lpszStructType),
370 debugstr_a(szFuncName), lib);
373 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
374 HeapFree(GetProcessHeap(), 0, szKey);
375 if(r != ERROR_SUCCESS)
378 RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
379 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
381 funcName = HeapAlloc(GetProcessHeap(), 0, size);
382 RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
386 funcName = szFuncName;
387 RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
388 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
390 LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
392 RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
394 *lib = LoadLibraryW(dllName);
397 ret = GetProcAddress(*lib, funcName);
400 /* Unload the library, the caller doesn't want to unload it
401 * when the return value is NULL.
407 HeapFree(GetProcessHeap(), 0, dllName);
409 if (funcName != szFuncName)
410 HeapFree(GetProcessHeap(), 0, (char *)funcName);
411 TRACE("returning %p\n", ret);
415 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
416 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
420 CryptEncodeObjectFunc pCryptEncodeObject;
422 TRACE("(0x%08lx, %s, %p, %p, %p)\n",
423 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
424 "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
426 if (!pbEncoded && !pcbEncoded)
428 SetLastError(ERROR_INVALID_PARAMETER);
432 /* Try registered DLL first.. */
434 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
435 lpszStructType, "CryptEncodeObject", &lib);
436 if (pCryptEncodeObject)
438 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
439 pvStructInfo, pbEncoded, pcbEncoded);
444 /* If not, use CryptEncodeObjectEx */
445 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
446 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
451 /* Helper function to check *pcbEncoded, set it to the required size, and
452 * optionally to allocate memory. Assumes pbEncoded is not NULL.
453 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
454 * pointer to the newly allocated memory.
456 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
457 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
462 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
464 if (pEncodePara && pEncodePara->pfnAlloc)
465 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
467 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
468 if (!*(BYTE **)pbEncoded)
471 *pcbEncoded = bytesNeeded;
473 else if (bytesNeeded > *pcbEncoded)
475 *pcbEncoded = bytesNeeded;
476 SetLastError(ERROR_MORE_DATA);
482 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
484 DWORD bytesNeeded, significantBytes = 0;
492 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
493 temp <<= 8, significantBytes--)
495 bytesNeeded = significantBytes + 1;
499 *pcbEncoded = bytesNeeded;
502 if (*pcbEncoded < bytesNeeded)
504 SetLastError(ERROR_MORE_DATA);
508 *pbEncoded = (BYTE)len;
513 *pbEncoded++ = significantBytes | 0x80;
514 for (i = 0; i < significantBytes; i++)
516 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
520 *pcbEncoded = bytesNeeded;
524 struct AsnEncodeSequenceItem
526 const void *pvStructInfo;
527 CryptEncodeObjectExFunc encodeFunc;
528 DWORD size; /* used during encoding, not for your use */
531 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
532 struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
533 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
536 DWORD i, dataLen = 0;
538 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", items, cItem, dwFlags, pEncodePara,
539 pbEncoded, *pcbEncoded);
540 for (i = 0, ret = TRUE; ret && i < cItem; i++)
542 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
543 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
544 NULL, &items[i].size);
545 dataLen += items[i].size;
549 DWORD lenBytes, bytesNeeded;
551 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
552 bytesNeeded = 1 + lenBytes + dataLen;
554 *pcbEncoded = bytesNeeded;
557 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
558 pcbEncoded, bytesNeeded)))
560 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
561 pbEncoded = *(BYTE **)pbEncoded;
562 *pbEncoded++ = ASN_SEQUENCE;
563 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
564 pbEncoded += lenBytes;
565 for (i = 0; ret && i < cItem; i++)
567 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
568 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
569 NULL, pbEncoded, &items[i].size);
570 pbEncoded += items[i].size;
575 TRACE("returning %d (%08lx)\n", ret, GetLastError());
579 struct AsnConstructedItem
582 const void *pvStructInfo;
583 CryptEncodeObjectExFunc encodeFunc;
586 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
587 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
588 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
591 const struct AsnConstructedItem *item =
592 (const struct AsnConstructedItem *)pvStructInfo;
595 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
596 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
598 DWORD dataLen, bytesNeeded;
600 CRYPT_EncodeLen(len, NULL, &dataLen);
601 bytesNeeded = 1 + dataLen + len;
603 *pcbEncoded = bytesNeeded;
604 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
605 pbEncoded, pcbEncoded, bytesNeeded)))
607 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
608 pbEncoded = *(BYTE **)pbEncoded;
609 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
610 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
611 pbEncoded += dataLen;
612 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
613 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
620 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
621 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
622 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
624 const DWORD *ver = (const DWORD *)pvStructInfo;
627 /* CERT_V1 is not encoded */
635 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
637 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
638 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
643 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
644 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
645 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
647 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
652 *pcbEncoded = blob->cbData;
655 else if (*pcbEncoded < blob->cbData)
657 *pcbEncoded = blob->cbData;
658 SetLastError(ERROR_MORE_DATA);
664 memcpy(pbEncoded, blob->pbData, blob->cbData);
665 *pcbEncoded = blob->cbData;
671 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
672 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
673 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
676 /* This has two filetimes in a row, a NotBefore and a NotAfter */
677 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
678 struct AsnEncodeSequenceItem items[] = {
679 { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
680 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
683 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
684 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
689 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
690 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
691 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
694 const CRYPT_ALGORITHM_IDENTIFIER *algo =
695 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
697 struct AsnEncodeSequenceItem items[] = {
698 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
699 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
702 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
703 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
708 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
709 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
710 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
716 const CERT_PUBLIC_KEY_INFO *info =
717 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
718 struct AsnEncodeSequenceItem items[] = {
719 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
720 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
723 TRACE("Encoding public key with OID %s\n",
724 debugstr_a(info->Algorithm.pszObjId));
725 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
726 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
731 SetLastError(STATUS_ACCESS_VIOLATION);
738 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
739 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
740 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
746 const CERT_SIGNED_CONTENT_INFO *info =
747 (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
748 struct AsnEncodeSequenceItem items[] = {
749 { &info->ToBeSigned, CRYPT_CopyEncodedBlob, 0 },
750 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
751 { &info->Signature, CRYPT_AsnEncodeBitsSwapBytes, 0 },
754 if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
755 items[2].encodeFunc = CRYPT_AsnEncodeBits;
756 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
757 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
762 SetLastError(STATUS_ACCESS_VIOLATION);
769 /* Like in Windows, this blithely ignores the validity of the passed-in
770 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
771 * decode properly, see CRYPT_AsnDecodeCertInfo.
773 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
774 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
775 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
781 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
782 struct AsnEncodeSequenceItem items[10] = {
783 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
784 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
785 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
786 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
787 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
788 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
789 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
792 struct AsnConstructedItem constructed[3] = { { 0 } };
793 DWORD cItem = 7, cConstructed = 0;
795 if (info->IssuerUniqueId.cbData)
797 constructed[cConstructed].tag = 1;
798 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
799 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
800 items[cItem].pvStructInfo = &constructed[cConstructed];
801 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
805 if (info->SubjectUniqueId.cbData)
807 constructed[cConstructed].tag = 2;
808 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
809 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
810 items[cItem].pvStructInfo = &constructed[cConstructed];
811 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
815 if (info->cExtension)
817 constructed[cConstructed].tag = 3;
818 constructed[cConstructed].pvStructInfo = &info->cExtension;
819 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
820 items[cItem].pvStructInfo = &constructed[cConstructed];
821 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
826 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
827 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
831 SetLastError(STATUS_ACCESS_VIOLATION);
838 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
842 struct AsnEncodeSequenceItem items[3] = {
843 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
849 TRACE("%p, %p, %ld\n", ext, pbEncoded, *pcbEncoded);
853 items[cItem].pvStructInfo = &ext->fCritical;
854 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
857 items[cItem].pvStructInfo = &ext->Value;
858 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
861 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
862 pbEncoded, pcbEncoded);
863 TRACE("returning %d (%08lx)\n", ret, GetLastError());
867 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
868 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
869 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
875 DWORD bytesNeeded, dataLen, lenBytes, i;
876 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
879 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
883 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
887 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
888 bytesNeeded = 1 + lenBytes + dataLen;
890 *pcbEncoded = bytesNeeded;
893 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
894 pcbEncoded, bytesNeeded)))
896 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
897 pbEncoded = *(BYTE **)pbEncoded;
898 *pbEncoded++ = ASN_SEQUENCEOF;
899 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
900 pbEncoded += lenBytes;
901 for (i = 0; i < exts->cExtension; i++)
903 DWORD size = dataLen;
905 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
915 SetLastError(STATUS_ACCESS_VIOLATION);
922 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
923 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
924 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
926 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
927 DWORD bytesNeeded = 0, lenBytes;
932 TRACE("%s\n", debugstr_a(pszObjId));
939 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
941 SetLastError(CRYPT_E_ASN1_ERROR);
945 firstByte = val1 * 40 + val2;
946 ptr = pszObjId + firstPos;
951 /* note I assume each component is at most 32-bits long in base 2 */
952 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
954 if (val1 >= 0x10000000)
956 else if (val1 >= 0x200000)
958 else if (val1 >= 0x4000)
960 else if (val1 >= 0x80)
970 SetLastError(CRYPT_E_ASN1_ERROR);
974 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
978 bytesNeeded += 1 + lenBytes;
981 if (*pcbEncoded < bytesNeeded)
983 SetLastError(ERROR_MORE_DATA);
988 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
989 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
990 pbEncoded += lenBytes;
996 *pbEncoded++ = firstByte;
997 ptr = pszObjId + firstPos;
1000 sscanf(ptr, "%d%n", &val, &pos);
1002 unsigned char outBytes[5];
1005 if (val >= 0x10000000)
1007 else if (val >= 0x200000)
1009 else if (val >= 0x4000)
1011 else if (val >= 0x80)
1015 for (i = numBytes; i > 0; i--)
1017 outBytes[i - 1] = val & 0x7f;
1020 for (i = 0; i < numBytes - 1; i++)
1021 *pbEncoded++ = outBytes[i] | 0x80;
1022 *pbEncoded++ = outBytes[i];
1031 *pcbEncoded = bytesNeeded;
1035 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
1036 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
1039 DWORD bytesNeeded, lenBytes, encodedLen;
1042 switch (value->dwValueType)
1044 case CERT_RDN_NUMERIC_STRING:
1045 tag = ASN_NUMERICSTRING;
1046 encodedLen = value->Value.cbData;
1048 case CERT_RDN_PRINTABLE_STRING:
1049 tag = ASN_PRINTABLESTRING;
1050 encodedLen = value->Value.cbData;
1052 case CERT_RDN_IA5_STRING:
1053 tag = ASN_IA5STRING;
1054 encodedLen = value->Value.cbData;
1056 case CERT_RDN_ANY_TYPE:
1057 /* explicitly disallowed */
1058 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1061 FIXME("String type %ld unimplemented\n", value->dwValueType);
1064 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1065 bytesNeeded = 1 + lenBytes + encodedLen;
1068 if (*pcbEncoded < bytesNeeded)
1070 SetLastError(ERROR_MORE_DATA);
1076 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1077 pbEncoded += lenBytes;
1078 switch (value->dwValueType)
1080 case CERT_RDN_NUMERIC_STRING:
1081 case CERT_RDN_PRINTABLE_STRING:
1082 case CERT_RDN_IA5_STRING:
1083 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
1087 *pcbEncoded = bytesNeeded;
1091 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1092 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
1094 DWORD bytesNeeded = 0, lenBytes, size;
1097 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1098 0, NULL, NULL, &size);
1101 bytesNeeded += size;
1102 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1103 * with dwValueType, so "cast" it to get its encoded size
1105 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1106 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
1109 bytesNeeded += size;
1110 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1111 bytesNeeded += 1 + lenBytes;
1114 if (*pcbEncoded < bytesNeeded)
1116 SetLastError(ERROR_MORE_DATA);
1121 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
1122 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1124 pbEncoded += lenBytes;
1125 size = bytesNeeded - 1 - lenBytes;
1126 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1127 attr->pszObjId, 0, NULL, pbEncoded, &size);
1131 size = bytesNeeded - 1 - lenBytes - size;
1132 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1133 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
1138 *pcbEncoded = bytesNeeded;
1144 static int BLOBComp(const void *l, const void *r)
1146 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
1149 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1150 ret = a->cbData - b->cbData;
1154 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1156 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1157 BYTE *pbEncoded, DWORD *pcbEncoded)
1160 CRYPT_DER_BLOB *blobs = NULL;
1164 DWORD bytesNeeded = 0, lenBytes, i;
1169 blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1170 rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1174 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1176 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1177 NULL, &blobs[i].cbData);
1179 bytesNeeded += blobs[i].cbData;
1183 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1184 bytesNeeded += 1 + lenBytes;
1187 if (*pcbEncoded < bytesNeeded)
1189 SetLastError(ERROR_MORE_DATA);
1194 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1196 blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
1198 if (!blobs[i].pbData)
1201 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1202 &rdn->rgRDNAttr[i], blobs[i].pbData,
1207 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1209 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1210 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1212 pbEncoded += lenBytes;
1213 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1215 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1216 pbEncoded += blobs[i].cbData;
1221 *pcbEncoded = bytesNeeded;
1225 for (i = 0; i < rdn->cRDNAttr; i++)
1226 HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
1229 __EXCEPT(page_fault)
1231 SetLastError(STATUS_ACCESS_VIOLATION);
1235 HeapFree(GetProcessHeap(), 0, blobs);
1239 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1240 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1241 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1247 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1248 DWORD bytesNeeded = 0, lenBytes, size, i;
1250 TRACE("encoding name with %ld RDNs\n", info->cRDN);
1252 for (i = 0; ret && i < info->cRDN; i++)
1254 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1257 bytesNeeded += size;
1259 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1260 bytesNeeded += 1 + lenBytes;
1264 *pcbEncoded = bytesNeeded;
1267 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1268 pbEncoded, pcbEncoded, bytesNeeded)))
1270 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1271 pbEncoded = *(BYTE **)pbEncoded;
1272 *pbEncoded++ = ASN_SEQUENCEOF;
1273 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1275 pbEncoded += lenBytes;
1276 for (i = 0; ret && i < info->cRDN; i++)
1279 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1280 &info->rgRDN[i], pbEncoded, &size);
1284 bytesNeeded -= size;
1291 __EXCEPT(page_fault)
1293 SetLastError(STATUS_ACCESS_VIOLATION);
1300 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1301 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1302 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1304 BOOL val = *(const BOOL *)pvStructInfo, ret;
1313 else if (*pcbEncoded < 3)
1316 SetLastError(ERROR_MORE_DATA);
1322 *pbEncoded++ = ASN_BOOL;
1324 *pbEncoded++ = val ? 0xff : 0;
1327 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1331 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1332 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1333 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1339 const CERT_BASIC_CONSTRAINTS2_INFO *info =
1340 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1341 struct AsnEncodeSequenceItem items[2] = { { 0 } };
1346 items[cItem].pvStructInfo = &info->fCA;
1347 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1350 if (info->fPathLenConstraint)
1352 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1353 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1356 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1357 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1359 __EXCEPT(page_fault)
1361 SetLastError(STATUS_ACCESS_VIOLATION);
1368 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1369 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1370 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1376 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1377 DWORD bytesNeeded, lenBytes;
1379 TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1380 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1382 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1383 bytesNeeded = 1 + lenBytes + blob->cbData;
1386 *pcbEncoded = bytesNeeded;
1391 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1392 pcbEncoded, bytesNeeded)))
1394 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1395 pbEncoded = *(BYTE **)pbEncoded;
1396 *pbEncoded++ = ASN_OCTETSTRING;
1397 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1398 pbEncoded += lenBytes;
1400 memcpy(pbEncoded, blob->pbData, blob->cbData);
1404 __EXCEPT(page_fault)
1406 SetLastError(STATUS_ACCESS_VIOLATION);
1410 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1414 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1415 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1416 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1422 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1423 DWORD bytesNeeded, lenBytes, dataBytes;
1426 /* yep, MS allows cUnusedBits to be >= 8 */
1427 if (!blob->cUnusedBits)
1429 dataBytes = blob->cbData;
1432 else if (blob->cbData * 8 > blob->cUnusedBits)
1434 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1435 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1443 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1444 bytesNeeded = 1 + lenBytes + dataBytes + 1;
1447 *pcbEncoded = bytesNeeded;
1452 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1453 pcbEncoded, bytesNeeded)))
1455 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1456 pbEncoded = *(BYTE **)pbEncoded;
1457 *pbEncoded++ = ASN_BITSTRING;
1458 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1459 pbEncoded += lenBytes;
1460 *pbEncoded++ = unusedBits;
1463 BYTE mask = 0xff << unusedBits;
1467 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1468 pbEncoded += dataBytes - 1;
1470 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1475 __EXCEPT(page_fault)
1477 SetLastError(STATUS_ACCESS_VIOLATION);
1484 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
1485 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1486 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1492 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1493 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
1498 newBlob.pbData = HeapAlloc(GetProcessHeap(), 0, newBlob.cbData);
1503 for (i = 0; i < newBlob.cbData; i++)
1504 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
1510 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
1511 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1512 HeapFree(GetProcessHeap(), 0, newBlob.pbData);
1514 __EXCEPT(page_fault)
1516 SetLastError(STATUS_ACCESS_VIOLATION);
1523 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1524 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1525 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1527 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1529 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1530 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1533 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1534 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1535 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1541 DWORD significantBytes, lenBytes;
1542 BYTE padByte = 0, bytesNeeded;
1544 const CRYPT_INTEGER_BLOB *blob =
1545 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1547 significantBytes = blob->cbData;
1548 if (significantBytes)
1550 if (blob->pbData[significantBytes - 1] & 0x80)
1552 /* negative, lop off leading (little-endian) 0xffs */
1553 for (; significantBytes > 0 &&
1554 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1556 if (blob->pbData[significantBytes - 1] < 0x80)
1564 /* positive, lop off leading (little-endian) zeroes */
1565 for (; significantBytes > 0 &&
1566 !blob->pbData[significantBytes - 1]; significantBytes--)
1568 if (significantBytes == 0)
1569 significantBytes = 1;
1570 if (blob->pbData[significantBytes - 1] > 0x7f)
1578 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1580 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1581 bytesNeeded = 1 + lenBytes + significantBytes;
1586 *pcbEncoded = bytesNeeded;
1591 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1592 pcbEncoded, bytesNeeded)))
1594 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1595 pbEncoded = *(BYTE **)pbEncoded;
1596 *pbEncoded++ = ASN_INTEGER;
1599 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1600 pbEncoded += lenBytes;
1601 *pbEncoded++ = padByte;
1605 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1606 pbEncoded += lenBytes;
1608 for (; significantBytes > 0; significantBytes--)
1609 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1613 __EXCEPT(page_fault)
1615 SetLastError(STATUS_ACCESS_VIOLATION);
1622 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1623 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1624 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1630 DWORD significantBytes, lenBytes;
1633 const CRYPT_INTEGER_BLOB *blob =
1634 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1636 significantBytes = blob->cbData;
1637 if (significantBytes)
1639 /* positive, lop off leading (little-endian) zeroes */
1640 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1643 if (significantBytes == 0)
1644 significantBytes = 1;
1645 if (blob->pbData[significantBytes - 1] > 0x7f)
1649 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1651 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1652 bytesNeeded = 1 + lenBytes + significantBytes;
1657 *pcbEncoded = bytesNeeded;
1662 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1663 pcbEncoded, bytesNeeded)))
1665 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1666 pbEncoded = *(BYTE **)pbEncoded;
1667 *pbEncoded++ = ASN_INTEGER;
1670 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1671 pbEncoded += lenBytes;
1676 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1677 pbEncoded += lenBytes;
1679 for (; significantBytes > 0; significantBytes--)
1680 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1684 __EXCEPT(page_fault)
1686 SetLastError(STATUS_ACCESS_VIOLATION);
1693 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
1694 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1695 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1697 CRYPT_INTEGER_BLOB blob;
1700 /* Encode as an unsigned integer, then change the tag to enumerated */
1701 blob.cbData = sizeof(DWORD);
1702 blob.pbData = (BYTE *)pvStructInfo;
1703 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
1704 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1705 if (ret && pbEncoded)
1707 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1708 pbEncoded = *(BYTE **)pbEncoded;
1709 pbEncoded[0] = ASN_ENUMERATED;
1714 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
1715 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1716 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1723 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
1724 * temporary buffer because the output buffer is not NULL-terminated.
1727 static const DWORD bytesNeeded = sizeof(buf) - 1;
1731 *pcbEncoded = bytesNeeded;
1736 /* Sanity check the year, this is a two-digit year format */
1737 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1739 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
1741 SetLastError(CRYPT_E_BAD_ENCODE);
1746 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1747 pbEncoded, pcbEncoded, bytesNeeded)))
1749 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1750 pbEncoded = *(BYTE **)pbEncoded;
1751 buf[0] = ASN_UTCTIME;
1752 buf[1] = bytesNeeded - 2;
1753 snprintf(buf + 2, sizeof(buf) - 2,
1754 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
1755 sysTime.wYear - 2000 : sysTime.wYear - 1900,
1756 sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1757 sysTime.wMinute, sysTime.wSecond);
1758 memcpy(pbEncoded, buf, bytesNeeded);
1763 __EXCEPT(page_fault)
1765 SetLastError(STATUS_ACCESS_VIOLATION);
1772 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
1773 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1774 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1781 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
1782 * temporary buffer because the output buffer is not NULL-terminated.
1785 static const DWORD bytesNeeded = sizeof(buf) - 1;
1789 *pcbEncoded = bytesNeeded;
1794 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1797 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1798 pcbEncoded, bytesNeeded);
1801 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1802 pbEncoded = *(BYTE **)pbEncoded;
1803 buf[0] = ASN_GENERALTIME;
1804 buf[1] = bytesNeeded - 2;
1805 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
1806 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1807 sysTime.wMinute, sysTime.wSecond);
1808 memcpy(pbEncoded, buf, bytesNeeded);
1812 __EXCEPT(page_fault)
1814 SetLastError(STATUS_ACCESS_VIOLATION);
1821 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
1822 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1823 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1831 /* Check the year, if it's in the UTCTime range call that encode func */
1832 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1834 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
1835 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
1836 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1838 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
1839 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1842 __EXCEPT(page_fault)
1844 SetLastError(STATUS_ACCESS_VIOLATION);
1851 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
1852 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1853 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1859 DWORD bytesNeeded, dataLen, lenBytes, i;
1860 const CRYPT_SEQUENCE_OF_ANY *seq =
1861 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
1863 for (i = 0, dataLen = 0; i < seq->cValue; i++)
1864 dataLen += seq->rgValue[i].cbData;
1865 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1866 bytesNeeded = 1 + lenBytes + dataLen;
1869 *pcbEncoded = bytesNeeded;
1874 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1875 pcbEncoded, bytesNeeded)))
1877 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1878 pbEncoded = *(BYTE **)pbEncoded;
1879 *pbEncoded++ = ASN_SEQUENCEOF;
1880 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1881 pbEncoded += lenBytes;
1882 for (i = 0; i < seq->cValue; i++)
1884 memcpy(pbEncoded, seq->rgValue[i].pbData,
1885 seq->rgValue[i].cbData);
1886 pbEncoded += seq->rgValue[i].cbData;
1891 __EXCEPT(page_fault)
1893 SetLastError(STATUS_ACCESS_VIOLATION);
1900 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1901 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
1902 void *pvEncoded, DWORD *pcbEncoded)
1906 CryptEncodeObjectExFunc encodeFunc = NULL;
1908 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n",
1909 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1910 "(integer value)", pvStructInfo, dwFlags, pEncodePara, pvEncoded,
1913 if (!pvEncoded && !pcbEncoded)
1915 SetLastError(ERROR_INVALID_PARAMETER);
1918 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
1919 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
1921 SetLastError(ERROR_FILE_NOT_FOUND);
1925 SetLastError(NOERROR);
1926 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
1927 *(BYTE **)pvEncoded = NULL;
1928 if (!HIWORD(lpszStructType))
1930 switch (LOWORD(lpszStructType))
1932 case (WORD)X509_CERT:
1933 encodeFunc = CRYPT_AsnEncodeCert;
1935 case (WORD)X509_CERT_TO_BE_SIGNED:
1936 encodeFunc = CRYPT_AsnEncodeCertInfo;
1938 case (WORD)X509_EXTENSIONS:
1939 encodeFunc = CRYPT_AsnEncodeExtensions;
1941 case (WORD)X509_NAME:
1942 encodeFunc = CRYPT_AsnEncodeName;
1944 case (WORD)X509_PUBLIC_KEY_INFO:
1945 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
1947 case (WORD)X509_BASIC_CONSTRAINTS2:
1948 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
1950 case (WORD)X509_OCTET_STRING:
1951 encodeFunc = CRYPT_AsnEncodeOctets;
1953 case (WORD)X509_BITS:
1954 case (WORD)X509_KEY_USAGE:
1955 encodeFunc = CRYPT_AsnEncodeBits;
1957 case (WORD)X509_INTEGER:
1958 encodeFunc = CRYPT_AsnEncodeInt;
1960 case (WORD)X509_MULTI_BYTE_INTEGER:
1961 encodeFunc = CRYPT_AsnEncodeInteger;
1963 case (WORD)X509_MULTI_BYTE_UINT:
1964 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
1966 case (WORD)X509_ENUMERATED:
1967 encodeFunc = CRYPT_AsnEncodeEnumerated;
1969 case (WORD)X509_CHOICE_OF_TIME:
1970 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
1972 case (WORD)X509_SEQUENCE_OF_ANY:
1973 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
1975 case (WORD)PKCS_UTC_TIME:
1976 encodeFunc = CRYPT_AsnEncodeUtcTime;
1979 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1982 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
1983 encodeFunc = CRYPT_AsnEncodeExtensions;
1984 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1985 encodeFunc = CRYPT_AsnEncodeUtcTime;
1986 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
1987 encodeFunc = CRYPT_AsnEncodeEnumerated;
1988 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
1989 encodeFunc = CRYPT_AsnEncodeBits;
1990 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
1991 encodeFunc = CRYPT_AsnEncodeOctets;
1992 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
1993 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
1995 TRACE("OID %s not found or unimplemented, looking for DLL\n",
1996 debugstr_a(lpszStructType));
1998 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1999 lpszStructType, "CryptEncodeObjectEx", &lib);
2001 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2002 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2004 SetLastError(ERROR_FILE_NOT_FOUND);
2010 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2011 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
2012 DWORD *pcbStructInfo)
2016 CryptDecodeObjectFunc pCryptDecodeObject;
2018 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
2019 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
2020 "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
2023 if (!pvStructInfo && !pcbStructInfo)
2025 SetLastError(ERROR_INVALID_PARAMETER);
2029 /* Try registered DLL first.. */
2030 pCryptDecodeObject =
2031 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
2032 lpszStructType, "CryptDecodeObject", &lib);
2033 if (pCryptDecodeObject)
2035 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
2036 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
2041 /* If not, use CryptDecodeObjectEx */
2042 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
2043 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
2048 /* Gets the number of length bytes from the given (leading) length byte */
2049 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
2051 /* Helper function to get the encoded length of the data starting at pbEncoded,
2052 * where pbEncoded[0] is the tag. If the data are too short to contain a
2053 * length or if the length is too large for cbEncoded, sets an appropriate
2054 * error code and returns FALSE.
2056 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
2063 SetLastError(CRYPT_E_ASN1_CORRUPT);
2066 else if (pbEncoded[1] <= 0x7f)
2068 *len = pbEncoded[1];
2073 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
2075 if (lenLen > sizeof(DWORD) + 1)
2077 SetLastError(CRYPT_E_ASN1_LARGE);
2080 else if (lenLen + 2 > cbEncoded)
2082 SetLastError(CRYPT_E_ASN1_CORRUPT);
2093 out |= *pbEncoded++;
2095 if (out + lenLen + 1 > cbEncoded)
2097 SetLastError(CRYPT_E_ASN1_EOD);
2110 /* Helper function to check *pcbStructInfo, set it to the required size, and
2111 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
2112 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
2113 * pointer to the newly allocated memory.
2115 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
2116 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2121 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2123 if (pDecodePara && pDecodePara->pfnAlloc)
2124 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
2126 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
2127 if (!*(BYTE **)pvStructInfo)
2130 *pcbStructInfo = bytesNeeded;
2132 else if (*pcbStructInfo < bytesNeeded)
2134 *pcbStructInfo = bytesNeeded;
2135 SetLastError(ERROR_MORE_DATA);
2141 /* A few of the members need explanation:
2143 * A sequence is decoded into a struct. The offset member is the
2144 * offset of this item within that struct.
2146 * The minimum amount of space occupied after decoding. You must set this.
2147 * hasPointer, pointerOffset, minSize:
2148 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
2149 * the offset within the (outer) struct of the data pointer (or to the
2150 * first data pointer, if more than one exist).
2152 * Used by CRYPT_AsnDecodeSequence, not for your use.
2154 struct AsnDecodeSequenceItem
2157 CryptDecodeObjectExFunc decodeFunc;
2161 DWORD pointerOffset;
2165 /* This decodes an arbitrary sequence into a contiguous block of memory
2166 * (basically, a struct.) Each element being decoded is described by a struct
2167 * AsnDecodeSequenceItem, see above.
2168 * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
2169 * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
2170 * FIXME: use to decode more sequences.
2172 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
2173 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2174 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
2175 void *pvStructInfo, DWORD *pcbStructInfo)
2179 if (pbEncoded[0] == ASN_SEQUENCE)
2183 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2185 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2186 DWORD i, bytesNeeded = 0, minSize = 0;
2189 ptr = pbEncoded + 1 + lenBytes;
2190 for (i = 0; ret && i < cItem; i++)
2194 minSize += items[i].minSize;
2195 if (cbEncoded - (ptr - pbEncoded) != 0)
2197 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2200 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2202 ret = items[i].decodeFunc(dwCertEncodingType, NULL,
2203 ptr, 1 + nextItemLenBytes + nextItemLen,
2204 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
2208 /* Account for alignment padding */
2209 bytesNeeded += items[i].size;
2210 if (items[i].size % sizeof(DWORD))
2211 bytesNeeded += sizeof(DWORD) -
2212 items[i].size % sizeof(DWORD);
2213 ptr += 1 + nextItemLenBytes + nextItemLen;
2215 else if (items[i].optional &&
2216 GetLastError() == CRYPT_E_ASN1_BADTAG)
2218 bytesNeeded += items[i].minSize;
2219 SetLastError(NOERROR);
2224 else if (items[i].optional)
2225 bytesNeeded += items[i].minSize;
2228 SetLastError(CRYPT_E_ASN1_CORRUPT);
2235 *pcbStructInfo = bytesNeeded;
2236 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2237 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2241 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2242 pvStructInfo = *(BYTE **)pvStructInfo;
2243 nextData = (BYTE *)pvStructInfo + minSize;
2244 memset(pvStructInfo, 0, minSize);
2245 ptr = pbEncoded + 1 + lenBytes;
2246 for (i = 0; ret && i < cItem; i++)
2248 if (cbEncoded - (ptr - pbEncoded) != 0)
2251 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2253 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2255 if (items[i].hasPointer)
2256 *(BYTE **)((BYTE *)pvStructInfo +
2257 items[i].pointerOffset) = nextData;
2258 ret = items[i].decodeFunc(dwCertEncodingType, NULL,
2259 ptr, 1 + nextItemLenBytes + nextItemLen,
2260 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2261 (BYTE *)pvStructInfo + items[i].offset,
2265 if (items[i].hasPointer &&
2266 items[i].size > items[i].minSize)
2268 nextData += items[i].size -
2270 /* align nextData to DWORD boundaries */
2271 if (items[i].size % sizeof(DWORD))
2272 nextData += sizeof(DWORD) -
2273 items[i].size % sizeof(DWORD);
2275 ptr += 1 + nextItemLenBytes + nextItemLen;
2277 else if (items[i].optional &&
2278 GetLastError() == CRYPT_E_ASN1_BADTAG)
2280 SetLastError(NOERROR);
2284 else if (!items[i].optional)
2286 SetLastError(CRYPT_E_ASN1_CORRUPT);
2296 SetLastError(CRYPT_E_ASN1_BADTAG);
2302 /* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
2303 * pvStructInfo. The BLOB must be non-empty, otherwise the last error is set
2304 * to CRYPT_E_ASN1_CORRUPT.
2305 * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
2308 static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
2309 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2310 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2315 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2317 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2318 DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
2320 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2321 bytesNeeded += 1 + lenBytes + dataLen;
2324 *pcbStructInfo = bytesNeeded;
2325 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2326 pvStructInfo, pcbStructInfo, bytesNeeded)))
2328 CRYPT_DER_BLOB *blob = (CRYPT_DER_BLOB *)pvStructInfo;
2330 blob->cbData = 1 + lenBytes + dataLen;
2333 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2334 blob->pbData = (BYTE *)pbEncoded;
2337 assert(blob->pbData);
2338 memcpy(blob->pbData, pbEncoded, blob->cbData);
2343 SetLastError(CRYPT_E_ASN1_CORRUPT);
2351 /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */
2352 static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType,
2353 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2354 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2358 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType,
2359 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
2360 if (ret && pvStructInfo)
2362 CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
2366 for (i = 0; i < blob->cbData / 2; i++)
2368 temp = blob->pbData[i];
2369 blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
2370 blob->pbData[blob->cbData - i - 1] = temp;
2376 static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
2377 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2378 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2384 struct AsnDecodeSequenceItem items[] = {
2385 { offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
2386 CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2387 offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 },
2388 { offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm),
2389 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2390 FALSE, TRUE, offsetof(CERT_SIGNED_CONTENT_INFO,
2391 SignatureAlgorithm.Parameters.pbData), 0 },
2392 { offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
2393 CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
2394 offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 },
2397 if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
2398 items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
2399 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2400 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2401 pDecodePara, pvStructInfo, pcbStructInfo);
2403 __EXCEPT(page_fault)
2405 SetLastError(STATUS_ACCESS_VIOLATION);
2412 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
2413 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2414 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2418 if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR))
2422 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2424 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2426 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
2427 pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
2428 pvStructInfo, pcbStructInfo);
2433 SetLastError(CRYPT_E_ASN1_BADTAG);
2439 static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
2440 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2441 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2445 struct AsnDecodeSequenceItem items[] = {
2446 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
2447 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2448 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
2449 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2452 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2453 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2454 pDecodePara, pvStructInfo, pcbStructInfo);
2458 static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
2459 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2460 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2466 struct AsnDecodeSequenceItem items[] = {
2467 { offsetof(CERT_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
2468 sizeof(DWORD), TRUE, FALSE, 0, 0 },
2469 { offsetof(CERT_INFO, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2470 sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2471 SerialNumber.pbData), 0 },
2472 { offsetof(CERT_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
2473 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CERT_INFO,
2474 SignatureAlgorithm.Parameters.pbData), 0 },
2475 { offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
2476 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2478 { offsetof(CERT_INFO, NotBefore), CRYPT_AsnDecodeValidity,
2479 sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, FALSE, 0 },
2480 { offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
2481 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2483 { offsetof(CERT_INFO, SubjectPublicKeyInfo), CRYPT_AsnDecodePubKeyInfo,
2484 sizeof(CERT_PUBLIC_KEY_INFO), FALSE, TRUE, offsetof(CERT_INFO,
2485 SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
2486 { offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal,
2487 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2488 IssuerUniqueId.pbData), 0 },
2489 { offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal,
2490 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2491 SubjectUniqueId.pbData), 0 },
2492 { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeExtensions,
2493 sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CERT_INFO,
2497 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2498 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2499 pDecodePara, pvStructInfo, pcbStructInfo);
2501 __EXCEPT(page_fault)
2503 SetLastError(STATUS_ACCESS_VIOLATION);
2510 /* Warning: assumes ext->Value.pbData is set ahead of time! */
2511 static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
2512 DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
2516 if (pbEncoded[0] == ASN_SEQUENCE)
2518 DWORD dataLen, bytesNeeded;
2520 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2522 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]), oidLenBytes = 0;
2524 bytesNeeded = sizeof(CERT_EXTENSION);
2527 const BYTE *ptr = pbEncoded + 1 + lenBytes;
2528 DWORD encodedOidLen, oidLen;
2530 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2532 oidLenBytes = GET_LEN_BYTES(ptr[1]);
2533 ret = CRYPT_AsnDecodeOid(ptr, cbEncoded - (ptr - pbEncoded),
2534 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &oidLen);
2537 bytesNeeded += oidLen;
2538 ptr += 1 + encodedOidLen + oidLenBytes;
2539 if (*ptr == ASN_BOOL)
2541 ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
2542 X509_OCTET_STRING, ptr, cbEncoded - (ptr - pbEncoded),
2543 0, NULL, NULL, &dataLen);
2544 bytesNeeded += dataLen;
2548 *pcbExt = bytesNeeded;
2549 else if (*pcbExt < bytesNeeded)
2551 SetLastError(ERROR_MORE_DATA);
2556 ptr = pbEncoded + 2 + lenBytes + encodedOidLen +
2558 if (*ptr == ASN_BOOL)
2560 DWORD size = sizeof(BOOL);
2562 CRYPT_AsnDecodeBool(X509_ASN_ENCODING, NULL,
2563 ptr, cbEncoded - (ptr - pbEncoded),
2564 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2565 &ext->fCritical, &size);
2569 ext->fCritical = FALSE;
2570 ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
2571 X509_OCTET_STRING, ptr,
2572 cbEncoded - (ptr - pbEncoded),
2573 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2574 &ext->Value, &dataLen);
2577 ext->pszObjId = (LPSTR)ext->Value.pbData +
2579 ptr = pbEncoded + 1 + lenBytes;
2580 ret = CRYPT_AsnDecodeOid(ptr,
2581 cbEncoded - (ptr - pbEncoded),
2582 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
2583 ext->pszObjId, &oidLen);
2591 SetLastError(CRYPT_E_ASN1_EOD);
2598 SetLastError(CRYPT_E_ASN1_BADTAG);
2604 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
2605 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2606 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2612 if (pbEncoded[0] == ASN_SEQUENCEOF)
2614 DWORD dataLen, bytesNeeded;
2616 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2618 DWORD cExtension = 0;
2619 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2621 bytesNeeded = sizeof(CERT_EXTENSIONS);
2627 for (ptr = pbEncoded + 1 + lenBytes; ret &&
2628 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2630 ret = CRYPT_AsnDecodeExtension(ptr,
2631 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
2637 bytesNeeded += size;
2638 ret = CRYPT_GetLen(ptr,
2639 cbEncoded - (ptr - pbEncoded), &nextLen);
2641 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2648 *pcbStructInfo = bytesNeeded;
2649 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2650 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2655 CERT_EXTENSIONS *exts;
2657 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2658 pvStructInfo = *(BYTE **)pvStructInfo;
2659 *pcbStructInfo = bytesNeeded;
2660 exts = (CERT_EXTENSIONS *)pvStructInfo;
2661 exts->cExtension = cExtension;
2662 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
2663 sizeof(CERT_EXTENSIONS));
2664 nextData = (BYTE *)exts->rgExtension +
2665 exts->cExtension * sizeof(CERT_EXTENSION);
2666 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
2667 i < cExtension && ptr - pbEncoded - 1 - lenBytes <
2670 exts->rgExtension[i].Value.pbData = nextData;
2672 ret = CRYPT_AsnDecodeExtension(ptr,
2673 cbEncoded - (ptr - pbEncoded), dwFlags,
2674 &exts->rgExtension[i], &size);
2679 bytesNeeded -= size;
2680 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
2681 * data may not have been copied.
2683 if (exts->rgExtension[i].Value.pbData ==
2686 exts->rgExtension[i].Value.cbData;
2687 /* Ugly: the OID, if copied, is stored in
2688 * memory after the value, so increment by its
2689 * string length if it's set and points here.
2691 if ((const BYTE *)exts->rgExtension[i].pszObjId
2694 exts->rgExtension[i].pszObjId) + 1;
2695 ret = CRYPT_GetLen(ptr,
2696 cbEncoded - (ptr - pbEncoded), &nextLen);
2698 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2707 SetLastError(CRYPT_E_ASN1_BADTAG);
2711 __EXCEPT(page_fault)
2713 SetLastError(STATUS_ACCESS_VIOLATION);
2720 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
2721 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
2722 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
2728 if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
2732 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2734 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2739 /* The largest possible string for the first two components
2740 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
2745 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
2746 pbEncoded[1 + lenBytes] / 40,
2747 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
2749 bytesNeeded = strlen(firstTwo) + 1;
2750 for (ptr = pbEncoded + 2 + lenBytes; ret &&
2751 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2753 /* large enough for ".4000000" */
2757 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
2764 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
2767 SetLastError(CRYPT_E_ASN1_CORRUPT);
2774 snprintf(str, sizeof(str), ".%d", val);
2775 bytesNeeded += strlen(str);
2779 *pcbObjId = bytesNeeded;
2780 else if (*pcbObjId < bytesNeeded)
2782 *pcbObjId = bytesNeeded;
2783 SetLastError(ERROR_MORE_DATA);
2788 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
2789 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
2791 pszObjId += strlen(pszObjId);
2792 for (ptr = pbEncoded + 2 + lenBytes; ret &&
2793 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2797 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
2806 sprintf(pszObjId, ".%d", val);
2807 pszObjId += strlen(pszObjId);
2813 *pcbObjId = bytesNeeded;
2818 SetLastError(CRYPT_E_ASN1_BADTAG);
2822 __EXCEPT(page_fault)
2824 SetLastError(STATUS_ACCESS_VIOLATION);
2831 /* Warning: this assumes the address of value->Value.pbData is already set, in
2832 * order to avoid overwriting memory. (In some cases, it may change it, if it
2833 * doesn't copy anything to memory.) Be sure to set it correctly!
2835 static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
2836 DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD *pcbValue)
2844 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2846 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2848 switch (pbEncoded[0])
2850 case ASN_NUMERICSTRING:
2851 case ASN_PRINTABLESTRING:
2855 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
2856 SetLastError(OSS_UNIMPLEMENTED);
2861 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
2863 switch (pbEncoded[0])
2865 case ASN_NUMERICSTRING:
2866 case ASN_PRINTABLESTRING:
2868 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2869 bytesNeeded += dataLen;
2873 *pcbValue = bytesNeeded;
2874 else if (*pcbValue < bytesNeeded)
2876 *pcbValue = bytesNeeded;
2877 SetLastError(ERROR_MORE_DATA);
2882 *pcbValue = bytesNeeded;
2883 switch (pbEncoded[0])
2885 case ASN_NUMERICSTRING:
2886 value->dwValueType = CERT_RDN_NUMERIC_STRING;
2888 case ASN_PRINTABLESTRING:
2889 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
2892 value->dwValueType = CERT_RDN_IA5_STRING;
2897 switch (pbEncoded[0])
2899 case ASN_NUMERICSTRING:
2900 case ASN_PRINTABLESTRING:
2902 value->Value.cbData = dataLen;
2903 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2904 value->Value.pbData = (BYTE *)pbEncoded + 1 +
2908 assert(value->Value.pbData);
2909 memcpy(value->Value.pbData,
2910 pbEncoded + 1 + lenBytes, dataLen);
2917 value->Value.cbData = 0;
2918 value->Value.pbData = NULL;
2924 __EXCEPT(page_fault)
2926 SetLastError(STATUS_ACCESS_VIOLATION);
2933 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded,
2934 DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD *pcbAttr)
2940 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCE))
2942 DWORD bytesNeeded, dataLen, size;
2945 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2947 /* The data length must be at least 4, two for the tag and
2948 * length for the OID, and two for the string (assuming both
2949 * have short-form lengths.)
2953 SetLastError(CRYPT_E_ASN1_EOD);
2958 bytesNeeded = sizeof(CERT_RDN_ATTR);
2959 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2960 ret = CRYPT_AsnDecodeOid(pbEncoded + 1 + lenBytes,
2961 cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
2964 /* ugly: need to know the size of the next element of
2965 * the sequence, so get it directly
2967 DWORD objIdOfset = 1 + lenBytes, objIdLen,
2968 nameValueOffset = 0;
2970 ret = CRYPT_GetLen(pbEncoded + objIdOfset,
2971 cbEncoded - objIdOfset, &objIdLen);
2972 bytesNeeded += size;
2973 /* hack: like encoding, this takes advantage of the
2974 * fact that the rest of the structure is identical to
2975 * a CERT_NAME_VALUE.
2979 nameValueOffset = objIdOfset + objIdLen + 1 +
2980 GET_LEN_BYTES(pbEncoded[objIdOfset]);
2981 ret = CRYPT_AsnDecodeNameValue(
2982 pbEncoded + nameValueOffset,
2983 cbEncoded - nameValueOffset, dwFlags, NULL, &size);
2987 bytesNeeded += size;
2989 *pcbAttr = bytesNeeded;
2990 else if (*pcbAttr < bytesNeeded)
2992 *pcbAttr = bytesNeeded;
2993 SetLastError(ERROR_MORE_DATA);
2998 BYTE *originalData = attr->Value.pbData;
3000 *pcbAttr = bytesNeeded;
3001 /* strange: decode the value first, because it
3002 * has a counted size, and we can store the OID
3003 * after it. Keep track of the original data
3004 * pointer, we'll need to know whether it was
3008 ret = CRYPT_AsnDecodeNameValue(
3009 pbEncoded + nameValueOffset,
3010 cbEncoded - nameValueOffset, dwFlags,
3011 (CERT_NAME_VALUE *)&attr->dwValueType, &size);
3016 /* if the data were copied to the
3017 * original location, the OID goes
3018 * after. Otherwise it goes in the
3019 * spot originally reserved for the
3022 if (attr->Value.pbData == originalData)
3024 (LPSTR)(attr->Value.pbData +
3025 attr->Value.cbData);
3027 attr->pszObjId = (LPSTR)originalData;
3028 size = bytesNeeded - size;
3029 ret = CRYPT_AsnDecodeOid(
3030 pbEncoded + objIdOfset,
3031 cbEncoded - objIdOfset,
3032 dwFlags, attr->pszObjId, &size);
3035 attr->pszObjId = NULL;
3045 SetLastError(CRYPT_E_ASN1_BADTAG);
3049 __EXCEPT(page_fault)
3051 SetLastError(STATUS_ACCESS_VIOLATION);
3058 static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
3059 DWORD dwFlags, CERT_RDN *rdn, DWORD *pcbRdn)
3065 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SETOF))
3069 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3071 DWORD bytesNeeded, cRDNAttr = 0;
3072 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3074 bytesNeeded = sizeof(CERT_RDN);
3080 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3081 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3083 ret = CRYPT_AsnDecodeRdnAttr(ptr,
3084 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3090 bytesNeeded += size;
3091 ret = CRYPT_GetLen(ptr,
3092 cbEncoded - (ptr - pbEncoded), &nextLen);
3094 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3101 *pcbRdn = bytesNeeded;
3102 else if (*pcbRdn < bytesNeeded)
3104 *pcbRdn = bytesNeeded;
3105 SetLastError(ERROR_MORE_DATA);
3114 *pcbRdn = bytesNeeded;
3115 rdn->cRDNAttr = cRDNAttr;
3116 rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn +
3118 nextData = (BYTE *)rdn->rgRDNAttr +
3119 rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
3120 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3121 i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
3124 rdn->rgRDNAttr[i].Value.pbData = nextData;
3126 ret = CRYPT_AsnDecodeRdnAttr(ptr,
3127 cbEncoded - (ptr - pbEncoded), dwFlags,
3128 &rdn->rgRDNAttr[i], &size);
3133 bytesNeeded -= size;
3134 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
3135 * data may not have been copied.
3137 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
3139 rdn->rgRDNAttr[i].Value.cbData;
3140 /* Ugly: the OID, if copied, is stored in
3141 * memory after the value, so increment by its
3142 * string length if it's set and points here.
3144 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId
3147 rdn->rgRDNAttr[i].pszObjId) + 1;
3148 ret = CRYPT_GetLen(ptr,
3149 cbEncoded - (ptr - pbEncoded), &nextLen);
3151 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3160 SetLastError(CRYPT_E_ASN1_BADTAG);
3164 __EXCEPT(page_fault)
3166 SetLastError(STATUS_ACCESS_VIOLATION);
3173 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
3174 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3175 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3181 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
3185 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3187 DWORD bytesNeeded, cRDN = 0;
3188 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3190 bytesNeeded = sizeof(CERT_NAME_INFO);
3195 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3196 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3200 ret = CRYPT_AsnDecodeRdn(ptr,
3201 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3207 bytesNeeded += size;
3208 ret = CRYPT_GetLen(ptr,
3209 cbEncoded - (ptr - pbEncoded), &nextLen);
3211 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3218 *pcbStructInfo = bytesNeeded;
3219 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3220 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3222 CERT_NAME_INFO *info;
3224 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3225 pvStructInfo = *(BYTE **)pvStructInfo;
3226 info = (CERT_NAME_INFO *)pvStructInfo;
3228 if (info->cRDN == 0)
3236 info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
3237 sizeof(CERT_NAME_INFO));
3238 nextData = (BYTE *)info->rgRDN +
3239 info->cRDN * sizeof(CERT_RDN);
3240 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3241 i < cRDN && ptr - pbEncoded - 1 - lenBytes <
3244 info->rgRDN[i].rgRDNAttr =
3245 (CERT_RDN_ATTR *)nextData;
3247 ret = CRYPT_AsnDecodeRdn(ptr,
3248 cbEncoded - (ptr - pbEncoded), dwFlags,
3249 &info->rgRDN[i], &size);
3255 bytesNeeded -= size;
3256 ret = CRYPT_GetLen(ptr,
3257 cbEncoded - (ptr - pbEncoded), &nextLen);
3259 ptr += nextLen + 1 +
3260 GET_LEN_BYTES(ptr[1]);
3270 SetLastError(CRYPT_E_ASN1_BADTAG);
3274 __EXCEPT(page_fault)
3276 SetLastError(STATUS_ACCESS_VIOLATION);
3283 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
3284 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3285 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3287 CRYPT_ALGORITHM_IDENTIFIER *algo =
3288 (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
3291 if (pbEncoded[0] == ASN_SEQUENCE)
3293 DWORD dataLen, bytesNeeded;
3295 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3297 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3299 bytesNeeded = sizeof(CRYPT_ALGORITHM_IDENTIFIER);
3302 const BYTE *ptr = pbEncoded + 1 + lenBytes;
3304 DWORD encodedOidLen, oidLen;
3306 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
3308 oidLenBytes = GET_LEN_BYTES(ptr[1]);
3309 ret = CRYPT_AsnDecodeOid(ptr, cbEncoded - (ptr - pbEncoded),
3310 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &oidLen);
3313 bytesNeeded += oidLen;
3314 ptr += 1 + encodedOidLen + oidLenBytes;
3315 /* The remaining bytes are just copied as-is, no decoding
3318 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3319 bytesNeeded += cbEncoded - (ptr - pbEncoded);
3321 *pcbStructInfo = bytesNeeded;
3322 else if (*pcbStructInfo < bytesNeeded)
3324 SetLastError(ERROR_MORE_DATA);
3329 /* Get and sanity-check parameter length first */
3330 if (dataLen - 1 - oidLenBytes - encodedOidLen != 0)
3334 if ((ret = CRYPT_GetLen(ptr, cbEncoded -
3335 (ptr - pbEncoded), ¶msLen)))
3337 BYTE paramsLenBytes = GET_LEN_BYTES(ptr[1]);
3339 if (paramsLen != dataLen - encodedOidLen - 1 -
3340 oidLenBytes - 1 - paramsLenBytes)
3342 SetLastError(CRYPT_E_ASN1_CORRUPT);
3349 *pcbStructInfo = bytesNeeded;
3350 algo->Parameters.cbData = dataLen - 1 -
3351 oidLenBytes - encodedOidLen;
3352 if (algo->Parameters.cbData)
3354 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3356 memcpy(algo->Parameters.pbData, ptr,
3357 algo->Parameters.cbData);
3358 algo->pszObjId = (LPSTR)algo->Parameters.pbData +
3359 algo->Parameters.cbData;
3363 algo->Parameters.pbData = (BYTE *)ptr;
3364 algo->pszObjId = (LPSTR)algo->Parameters.pbData;
3368 algo->pszObjId = (LPSTR)algo->Parameters.pbData;
3369 ptr = pbEncoded + 1 + lenBytes;
3370 ret = CRYPT_AsnDecodeOid(ptr,
3371 cbEncoded - (ptr - pbEncoded),
3372 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
3373 algo->pszObjId, &oidLen);
3380 SetLastError(CRYPT_E_ASN1_EOD);
3387 SetLastError(CRYPT_E_ASN1_BADTAG);
3393 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
3394 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3395 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3401 struct AsnDecodeSequenceItem items[] = {
3402 { offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
3403 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3404 FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO,
3405 Algorithm.Parameters.pbData) },
3406 { offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
3407 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
3408 offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) },
3411 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3412 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3413 pDecodePara, pvStructInfo, pcbStructInfo);
3415 __EXCEPT(page_fault)
3417 SetLastError(STATUS_ACCESS_VIOLATION);
3424 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
3425 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3426 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3432 SetLastError(CRYPT_E_ASN1_CORRUPT);
3435 if (pbEncoded[0] != ASN_BOOL)
3437 SetLastError(CRYPT_E_ASN1_BADTAG);
3440 if (GET_LEN_BYTES(pbEncoded[1]) > 1)
3442 SetLastError(CRYPT_E_ASN1_CORRUPT);
3445 if (pbEncoded[1] > 1)
3447 SetLastError(CRYPT_E_ASN1_CORRUPT);
3452 *pcbStructInfo = sizeof(BOOL);
3455 else if (*pcbStructInfo < sizeof(BOOL))
3457 *pcbStructInfo = sizeof(BOOL);
3458 SetLastError(ERROR_MORE_DATA);
3463 *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
3469 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
3470 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3471 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3477 if (pbEncoded[0] == ASN_SEQUENCE)
3481 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3483 /* sanity-check length, space enough for 7 bytes of integer and
3488 SetLastError(CRYPT_E_ASN1_CORRUPT);
3493 DWORD bytesNeeded = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
3496 *pcbStructInfo = bytesNeeded;
3500 CERT_BASIC_CONSTRAINTS2_INFO info = { 0 };
3502 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3503 pbEncoded += 1 + lenBytes;
3504 cbEncoded -= 1 + lenBytes;
3509 if (pbEncoded[0] == ASN_BOOL)
3511 size = sizeof(BOOL);
3512 ret = CRYPT_AsnDecodeBool(dwCertEncodingType,
3513 NULL, pbEncoded, cbEncoded,
3514 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
3518 cbEncoded -= 2 + pbEncoded[1];
3519 pbEncoded += 2 + pbEncoded[1];
3522 if (ret && cbEncoded && pbEncoded[0] == ASN_INTEGER)
3524 size = sizeof(info.dwPathLenConstraint);
3525 ret = CRYPT_AsnDecodeInt(dwCertEncodingType,
3526 X509_INTEGER, pbEncoded, cbEncoded, 0, NULL,
3527 &info.dwPathLenConstraint, &size);
3530 cbEncoded -= 2 + pbEncoded[1];
3531 pbEncoded += 2 + pbEncoded[1];
3534 SetLastError(CRYPT_E_ASN1_CORRUPT);
3538 info.fPathLenConstraint = TRUE;
3544 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3545 pDecodePara, pvStructInfo, pcbStructInfo,
3548 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3549 pvStructInfo = *(BYTE **)pvStructInfo;
3550 memcpy(pvStructInfo, &info,
3551 sizeof(CERT_BASIC_CONSTRAINTS2_INFO));
3560 SetLastError(CRYPT_E_ASN1_BADTAG);
3564 __EXCEPT(page_fault)
3566 SetLastError(STATUS_ACCESS_VIOLATION);
3573 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
3574 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3575 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3581 if (pbEncoded[0] == ASN_OCTETSTRING)
3583 DWORD bytesNeeded, dataLen;
3585 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3587 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3588 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
3590 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
3592 *pcbStructInfo = bytesNeeded;
3593 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3594 pvStructInfo, pcbStructInfo, bytesNeeded)))
3596 CRYPT_DATA_BLOB *blob;
3597 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3599 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3600 pvStructInfo = *(BYTE **)pvStructInfo;
3601 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
3602 blob->cbData = dataLen;
3603 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3604 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
3607 blob->pbData = (BYTE *)pvStructInfo +
3608 sizeof(CRYPT_DATA_BLOB);
3610 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
3618 SetLastError(CRYPT_E_ASN1_BADTAG);
3622 __EXCEPT(page_fault)
3624 SetLastError(STATUS_ACCESS_VIOLATION);
3631 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
3632 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3633 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3637 TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
3638 pDecodePara, pvStructInfo, pcbStructInfo);
3640 if (pbEncoded[0] == ASN_BITSTRING)
3642 DWORD bytesNeeded, dataLen;
3644 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3646 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3647 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
3649 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
3651 *pcbStructInfo = bytesNeeded;
3652 else if (*pcbStructInfo < bytesNeeded)
3654 *pcbStructInfo = bytesNeeded;
3655 SetLastError(ERROR_MORE_DATA);
3660 CRYPT_BIT_BLOB *blob;
3662 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
3663 blob->cbData = dataLen - 1;
3664 blob->cUnusedBits = *(pbEncoded + 1 +
3665 GET_LEN_BYTES(pbEncoded[1]));
3666 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3668 blob->pbData = (BYTE *)pbEncoded + 2 +
3669 GET_LEN_BYTES(pbEncoded[1]);
3673 assert(blob->pbData);
3676 BYTE mask = 0xff << blob->cUnusedBits;
3678 memcpy(blob->pbData, pbEncoded + 2 +
3679 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
3680 blob->pbData[blob->cbData - 1] &= mask;
3688 SetLastError(CRYPT_E_ASN1_BADTAG);
3694 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
3695 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3696 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3700 TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
3701 pDecodePara, pvStructInfo, pcbStructInfo);
3707 if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
3708 lpszStructType, pbEncoded, cbEncoded,
3709 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
3712 *pcbStructInfo = bytesNeeded;
3713 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3714 pvStructInfo, pcbStructInfo, bytesNeeded)))
3716 CRYPT_BIT_BLOB *blob;
3718 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3719 pvStructInfo = *(BYTE **)pvStructInfo;
3720 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
3721 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
3722 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
3723 lpszStructType, pbEncoded, cbEncoded,
3724 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3729 __EXCEPT(page_fault)
3731 SetLastError(STATUS_ACCESS_VIOLATION);
3738 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
3739 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3740 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3746 *pcbStructInfo = sizeof(int);
3751 BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
3752 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
3753 DWORD size = sizeof(buf);
3755 blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
3756 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
3757 X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
3760 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3761 pvStructInfo, pcbStructInfo, sizeof(int))))
3765 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3766 pvStructInfo = *(BYTE **)pvStructInfo;
3767 if (blob->pbData[blob->cbData - 1] & 0x80)
3769 /* initialize to a negative value to sign-extend */
3774 for (i = 0; i < blob->cbData; i++)
3777 val |= blob->pbData[blob->cbData - i - 1];
3779 memcpy(pvStructInfo, &val, sizeof(int));
3782 else if (GetLastError() == ERROR_MORE_DATA)
3783 SetLastError(CRYPT_E_ASN1_LARGE);
3785 __EXCEPT(page_fault)
3787 SetLastError(STATUS_ACCESS_VIOLATION);
3794 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
3795 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3796 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3800 if (pbEncoded[0] == ASN_INTEGER)
3802 DWORD bytesNeeded, dataLen;
3804 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3806 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3808 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
3810 *pcbStructInfo = bytesNeeded;
3811 else if (*pcbStructInfo < bytesNeeded)
3813 *pcbStructInfo = bytesNeeded;
3814 SetLastError(ERROR_MORE_DATA);
3819 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
3821 blob->cbData = dataLen;
3822 assert(blob->pbData);
3827 for (i = 0; i < blob->cbData; i++)
3828 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
3836 SetLastError(CRYPT_E_ASN1_BADTAG);
3842 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
3843 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3844 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3852 if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
3853 lpszStructType, pbEncoded, cbEncoded,
3854 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
3857 *pcbStructInfo = bytesNeeded;
3858 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3859 pvStructInfo, pcbStructInfo, bytesNeeded)))
3861 CRYPT_INTEGER_BLOB *blob;
3863 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3864 pvStructInfo = *(BYTE **)pvStructInfo;
3865 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
3866 blob->pbData = (BYTE *)pvStructInfo +
3867 sizeof(CRYPT_INTEGER_BLOB);
3868 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
3869 lpszStructType, pbEncoded, cbEncoded,
3870 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
3875 __EXCEPT(page_fault)
3877 SetLastError(STATUS_ACCESS_VIOLATION);
3884 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
3885 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3886 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3892 if (pbEncoded[0] == ASN_INTEGER)
3894 DWORD bytesNeeded, dataLen;
3895 CRYPT_INTEGER_BLOB *blob;
3897 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3899 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
3901 *pcbStructInfo = bytesNeeded;
3902 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3903 pvStructInfo, pcbStructInfo, bytesNeeded)))
3905 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3907 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3908 pvStructInfo = *(BYTE **)pvStructInfo;
3909 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
3910 blob->cbData = dataLen;
3911 blob->pbData = (BYTE *)pvStructInfo +
3912 sizeof(CRYPT_INTEGER_BLOB);
3913 /* remove leading zero byte if it exists */
3914 if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
3923 for (i = 0; i < blob->cbData; i++)
3924 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
3925 pbEncoded[1] - i - 1);
3932 SetLastError(CRYPT_E_ASN1_BADTAG);
3936 __EXCEPT(page_fault)
3938 SetLastError(STATUS_ACCESS_VIOLATION);
3945 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
3946 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3947 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3953 *pcbStructInfo = sizeof(int);
3958 if (pbEncoded[0] == ASN_ENUMERATED)
3960 unsigned int val = 0, i;
3964 SetLastError(CRYPT_E_ASN1_EOD);
3967 else if (pbEncoded[1] == 0)
3969 SetLastError(CRYPT_E_ASN1_CORRUPT);
3974 /* A little strange looking, but we have to accept a sign byte:
3975 * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff. Also,
3976 * assuming a small length is okay here, it has to be in short
3979 if (pbEncoded[1] > sizeof(unsigned int) + 1)
3981 SetLastError(CRYPT_E_ASN1_LARGE);
3984 for (i = 0; i < pbEncoded[1]; i++)
3987 val |= pbEncoded[2 + i];
3989 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3990 pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
3992 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3993 pvStructInfo = *(BYTE **)pvStructInfo;
3994 memcpy(pvStructInfo, &val, sizeof(unsigned int));
4000 SetLastError(CRYPT_E_ASN1_BADTAG);
4004 __EXCEPT(page_fault)
4006 SetLastError(STATUS_ACCESS_VIOLATION);
4013 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
4016 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
4021 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
4023 if (!isdigit(*(pbEncoded))) \
4025 SetLastError(CRYPT_E_ASN1_CORRUPT); \
4031 (word) += *(pbEncoded)++ - '0'; \
4036 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
4037 SYSTEMTIME *sysTime)
4043 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
4045 WORD hours, minutes = 0;
4046 BYTE sign = *pbEncoded++;
4049 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
4050 if (ret && hours >= 24)
4052 SetLastError(CRYPT_E_ASN1_CORRUPT);
4057 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
4058 if (ret && minutes >= 60)
4060 SetLastError(CRYPT_E_ASN1_CORRUPT);
4068 sysTime->wHour += hours;
4069 sysTime->wMinute += minutes;
4073 if (hours > sysTime->wHour)
4076 sysTime->wHour = 24 - (hours - sysTime->wHour);
4079 sysTime->wHour -= hours;
4080 if (minutes > sysTime->wMinute)
4083 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
4086 sysTime->wMinute -= minutes;
4091 __EXCEPT(page_fault)
4093 SetLastError(STATUS_ACCESS_VIOLATION);
4100 #define MIN_ENCODED_TIME_LENGTH 10
4102 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
4103 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4104 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4110 *pcbStructInfo = sizeof(FILETIME);
4115 if (pbEncoded[0] == ASN_UTCTIME)
4119 SetLastError(CRYPT_E_ASN1_EOD);
4122 else if (pbEncoded[1] > 0x7f)
4124 /* long-form date strings really can't be valid */
4125 SetLastError(CRYPT_E_ASN1_CORRUPT);
4130 SYSTEMTIME sysTime = { 0 };
4131 BYTE len = pbEncoded[1];
4133 if (len < MIN_ENCODED_TIME_LENGTH)
4135 SetLastError(CRYPT_E_ASN1_CORRUPT);
4141 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
4142 if (sysTime.wYear >= 50)
4143 sysTime.wYear += 1900;
4145 sysTime.wYear += 2000;
4146 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
4147 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
4148 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
4149 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
4152 if (len >= 2 && isdigit(*pbEncoded) &&
4153 isdigit(*(pbEncoded + 1)))
4154 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4156 else if (isdigit(*pbEncoded))
4157 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
4160 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
4163 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
4164 pDecodePara, pvStructInfo, pcbStructInfo,
4167 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4168 pvStructInfo = *(BYTE **)pvStructInfo;
4169 ret = SystemTimeToFileTime(&sysTime,
4170 (FILETIME *)pvStructInfo);
4177 SetLastError(CRYPT_E_ASN1_BADTAG);
4181 __EXCEPT(page_fault)
4183 SetLastError(STATUS_ACCESS_VIOLATION);
4190 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
4191 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4192 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4198 *pcbStructInfo = sizeof(FILETIME);
4203 if (pbEncoded[0] == ASN_GENERALTIME)
4207 SetLastError(CRYPT_E_ASN1_EOD);
4210 else if (pbEncoded[1] > 0x7f)
4212 /* long-form date strings really can't be valid */
4213 SetLastError(CRYPT_E_ASN1_CORRUPT);
4218 BYTE len = pbEncoded[1];
4220 if (len < MIN_ENCODED_TIME_LENGTH)
4222 SetLastError(CRYPT_E_ASN1_CORRUPT);
4227 SYSTEMTIME sysTime = { 0 };
4230 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
4231 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
4232 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
4233 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
4236 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4239 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4241 if (ret && len > 0 && (*pbEncoded == '.' ||
4248 /* workaround macro weirdness */
4249 digits = min(len, 3);
4250 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
4251 sysTime.wMilliseconds);
4254 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
4257 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
4258 pDecodePara, pvStructInfo, pcbStructInfo,
4261 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4262 pvStructInfo = *(BYTE **)pvStructInfo;
4263 ret = SystemTimeToFileTime(&sysTime,
4264 (FILETIME *)pvStructInfo);
4271 SetLastError(CRYPT_E_ASN1_BADTAG);
4275 __EXCEPT(page_fault)
4277 SetLastError(STATUS_ACCESS_VIOLATION);
4284 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
4285 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4286 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4292 *pcbStructInfo = sizeof(FILETIME);
4298 if (pbEncoded[0] == ASN_UTCTIME)
4299 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
4300 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
4302 else if (pbEncoded[0] == ASN_GENERALTIME)
4303 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
4304 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
4305 pvStructInfo, pcbStructInfo);
4308 SetLastError(CRYPT_E_ASN1_BADTAG);
4312 __EXCEPT(page_fault)
4314 SetLastError(STATUS_ACCESS_VIOLATION);
4321 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
4322 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4323 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4329 if (pbEncoded[0] == ASN_SEQUENCEOF)
4331 DWORD bytesNeeded, dataLen, remainingLen, cValue;
4333 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4338 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4339 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
4341 ptr = pbEncoded + 1 + lenBytes;
4342 remainingLen = dataLen;
4343 while (ret && remainingLen)
4347 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
4350 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
4352 remainingLen -= 1 + nextLenBytes + nextLen;
4353 ptr += 1 + nextLenBytes + nextLen;
4354 bytesNeeded += sizeof(CRYPT_DER_BLOB);
4355 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
4356 bytesNeeded += 1 + nextLenBytes + nextLen;
4362 CRYPT_SEQUENCE_OF_ANY *seq;
4366 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4367 pvStructInfo, pcbStructInfo, bytesNeeded)))
4369 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4370 pvStructInfo = *(BYTE **)pvStructInfo;
4371 seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
4372 seq->cValue = cValue;
4373 seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
4375 nextPtr = (BYTE *)seq->rgValue +
4376 cValue * sizeof(CRYPT_DER_BLOB);
4377 ptr = pbEncoded + 1 + lenBytes;
4378 remainingLen = dataLen;
4380 while (ret && remainingLen)
4384 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
4387 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
4389 seq->rgValue[i].cbData = 1 + nextLenBytes +
4391 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4392 seq->rgValue[i].pbData = (BYTE *)ptr;
4395 seq->rgValue[i].pbData = nextPtr;
4396 memcpy(nextPtr, ptr, 1 + nextLenBytes +
4398 nextPtr += 1 + nextLenBytes + nextLen;
4400 remainingLen -= 1 + nextLenBytes + nextLen;
4401 ptr += 1 + nextLenBytes + nextLen;
4411 SetLastError(CRYPT_E_ASN1_BADTAG);
4415 __EXCEPT(page_fault)
4417 SetLastError(STATUS_ACCESS_VIOLATION);
4424 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
4425 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4426 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4430 CryptDecodeObjectExFunc decodeFunc = NULL;
4432 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
4433 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
4434 "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
4435 pvStructInfo, pcbStructInfo);
4437 if (!pvStructInfo && !pcbStructInfo)
4439 SetLastError(ERROR_INVALID_PARAMETER);
4442 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
4443 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
4445 SetLastError(ERROR_FILE_NOT_FOUND);
4450 SetLastError(CRYPT_E_ASN1_EOD);
4453 if (cbEncoded > MAX_ENCODED_LEN)
4455 SetLastError(CRYPT_E_ASN1_LARGE);
4459 SetLastError(NOERROR);
4460 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
4461 *(BYTE **)pvStructInfo = NULL;
4462 if (!HIWORD(lpszStructType))
4464 switch (LOWORD(lpszStructType))
4466 case (WORD)X509_CERT:
4467 decodeFunc = CRYPT_AsnDecodeCert;
4469 case (WORD)X509_CERT_TO_BE_SIGNED:
4470 decodeFunc = CRYPT_AsnDecodeCertInfo;
4472 case (WORD)X509_EXTENSIONS:
4473 decodeFunc = CRYPT_AsnDecodeExtensions;
4475 case (WORD)X509_NAME:
4476 decodeFunc = CRYPT_AsnDecodeName;
4478 case (WORD)X509_PUBLIC_KEY_INFO:
4479 decodeFunc = CRYPT_AsnDecodePubKeyInfo;
4481 case (WORD)X509_BASIC_CONSTRAINTS2:
4482 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
4484 case (WORD)X509_OCTET_STRING:
4485 decodeFunc = CRYPT_AsnDecodeOctets;
4487 case (WORD)X509_BITS:
4488 case (WORD)X509_KEY_USAGE:
4489 decodeFunc = CRYPT_AsnDecodeBits;
4491 case (WORD)X509_INTEGER:
4492 decodeFunc = CRYPT_AsnDecodeInt;
4494 case (WORD)X509_MULTI_BYTE_INTEGER:
4495 decodeFunc = CRYPT_AsnDecodeInteger;
4497 case (WORD)X509_MULTI_BYTE_UINT:
4498 decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
4500 case (WORD)X509_ENUMERATED:
4501 decodeFunc = CRYPT_AsnDecodeEnumerated;
4503 case (WORD)X509_CHOICE_OF_TIME:
4504 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
4506 case (WORD)X509_SEQUENCE_OF_ANY:
4507 decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
4509 case (WORD)PKCS_UTC_TIME:
4510 decodeFunc = CRYPT_AsnDecodeUtcTime;
4513 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
4516 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
4517 decodeFunc = CRYPT_AsnDecodeExtensions;
4518 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
4519 decodeFunc = CRYPT_AsnDecodeUtcTime;
4520 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
4521 decodeFunc = CRYPT_AsnDecodeEnumerated;
4522 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
4523 decodeFunc = CRYPT_AsnDecodeBits;
4524 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
4525 decodeFunc = CRYPT_AsnDecodeOctets;
4526 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
4527 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
4529 TRACE("OID %s not found or unimplemented, looking for DLL\n",
4530 debugstr_a(lpszStructType));
4532 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
4533 lpszStructType, "CryptDecodeObjectEx", &lib);
4535 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
4536 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
4538 SetLastError(ERROR_FILE_NOT_FOUND);