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
39 #define NONAMELESSUNION
47 #include "wine/debug.h"
48 #include "wine/exception.h"
50 /* This is a bit arbitrary, but to set some limit: */
51 #define MAX_ENCODED_LEN 0x02000000
53 /* a few asn.1 tags we need */
54 #define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
55 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
56 #define ASN_OCTETSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
57 #define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
58 #define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
59 #define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
60 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
61 #define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
62 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
63 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
65 #define ASN_FLAGS_MASK 0xf0
66 #define ASN_TYPE_MASK 0x0f
68 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
70 static const WCHAR szDllName[] = { 'D','l','l',0 };
72 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
74 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
75 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
76 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
77 DWORD, DWORD, void *, DWORD *);
78 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
79 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
81 /* Prototypes for built-in encoders/decoders. They follow the Ex style
82 * prototypes. The dwCertEncodingType and lpszStructType are ignored by the
83 * built-in functions, but the parameters are retained to simplify
84 * CryptEncodeObjectEx/CryptDecodeObjectEx, since they must call functions in
85 * external DLLs that follow these signatures.
86 * FIXME: some built-in functions are suitable to be called directly by
87 * CryptEncodeObjectEx/CryptDecodeObjectEx (they implement exception handling
88 * and memory allocation if requested), others are only suitable to be called
89 * internally. Comment which are which.
91 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
92 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
93 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
94 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
95 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
96 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
97 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
98 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
99 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
100 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
101 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
102 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
103 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
104 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
105 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
106 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
107 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
108 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
109 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
110 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
111 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
112 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
113 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
114 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
115 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
116 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
117 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
118 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
119 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
120 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
122 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(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_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
126 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
127 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
128 /* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of
129 * time, doesn't do memory allocation, and doesn't do exception handling.
130 * (This isn't intended to be the externally-called one.)
132 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
133 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
134 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
135 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
136 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
137 /* Assumes algo->Parameters.pbData is set ahead of time */
138 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
139 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
140 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
141 static BOOL WINAPI CRYPT_AsnDecodeBool(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_AsnDecodeOctets(DWORD dwCertEncodingType,
145 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
146 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
147 /* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
148 * member has been initialized, doesn't do exception handling, and doesn't do
151 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
152 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
153 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
154 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
155 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
156 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
157 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
158 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
159 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
160 /* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
161 * member has been initialized, doesn't do exception handling, and doesn't do
164 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
165 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
166 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
168 /* filter for page-fault exceptions */
169 static WINE_EXCEPTION_FILTER(page_fault)
171 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
172 return EXCEPTION_EXECUTE_HANDLER;
173 return EXCEPTION_CONTINUE_SEARCH;
176 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
179 static const char szEncodingTypeFmt[] =
180 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
182 char numericOID[7]; /* enough for "#65535" */
186 /* MSDN says the encoding type is a mask, but it isn't treated that way.
187 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
188 * "EncodingType 2" would be expected if it were a mask. Instead native
189 * stores values in "EncodingType 3".
193 snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
199 /* This is enough: the lengths of the two string parameters are explicitly
200 * counted, and we need up to five additional characters for the encoding
201 * type. These are covered by the "%d", "%s", and "%s" characters in the
202 * format specifier that are removed by sprintf.
204 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
205 szKey = HeapAlloc(GetProcessHeap(), 0, len);
207 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
211 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
212 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
218 TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
219 debugstr_w(pwszDll), pszOverrideFuncName);
221 /* This only registers functions for encoding certs, not messages */
222 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
225 /* Native does nothing pwszDll is NULL */
229 /* I'm not matching MS bug for bug here, because I doubt any app depends on
231 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
232 * it creates would never be used
233 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
234 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
236 if (!pszFuncName || !pszOID)
238 SetLastError(ERROR_INVALID_PARAMETER);
242 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
243 TRACE("Key name is %s\n", debugstr_a(szKey));
248 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
249 HeapFree(GetProcessHeap(), 0, szKey);
250 if(r != ERROR_SUCCESS)
253 /* write the values */
254 if (pszOverrideFuncName)
255 RegSetValueExA(hKey, "FuncName", 0, REG_SZ, (const BYTE*)pszOverrideFuncName,
256 lstrlenA(pszOverrideFuncName) + 1);
257 RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
258 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
264 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
270 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
272 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
275 if (!pszFuncName || !pszOID)
277 SetLastError(ERROR_INVALID_PARAMETER);
281 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
282 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
283 HeapFree(GetProcessHeap(), 0, szKey);
286 return rc ? FALSE : TRUE;
289 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
290 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
297 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
298 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
301 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
304 if (!pszFuncName || !pszOID || !pwszValueName)
306 SetLastError(ERROR_INVALID_PARAMETER);
310 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
311 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
312 HeapFree(GetProcessHeap(), 0, szKey);
317 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
318 pbValueData, pcbValueData);
323 return rc ? FALSE : TRUE;
326 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
327 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
328 const BYTE *pbValueData, DWORD cbValueData)
334 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
335 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
338 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
341 if (!pszFuncName || !pszOID || !pwszValueName)
343 SetLastError(ERROR_INVALID_PARAMETER);
347 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
348 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
349 HeapFree(GetProcessHeap(), 0, szKey);
354 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
360 return rc ? FALSE : TRUE;
363 /* Gets the registered function named szFuncName for dwCertEncodingType and
364 * lpszStructType, or NULL if one could not be found. *lib will be set to the
365 * handle of the module it's in, or NULL if no module was loaded. If the
366 * return value is NULL, *lib will also be NULL, to simplify error handling.
368 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
369 LPCSTR szFuncName, HMODULE *lib)
372 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
374 const char *funcName;
377 DWORD type, size = 0;
379 TRACE("(%08lx %s %s %p)\n", dwCertEncodingType, debugstr_a(lpszStructType),
380 debugstr_a(szFuncName), lib);
383 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
384 HeapFree(GetProcessHeap(), 0, szKey);
385 if(r != ERROR_SUCCESS)
388 RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
389 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
391 funcName = HeapAlloc(GetProcessHeap(), 0, size);
392 RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
396 funcName = szFuncName;
397 RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
398 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
400 LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
402 RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
404 *lib = LoadLibraryW(dllName);
407 ret = GetProcAddress(*lib, funcName);
410 /* Unload the library, the caller doesn't want to unload it
411 * when the return value is NULL.
417 HeapFree(GetProcessHeap(), 0, dllName);
419 if (funcName != szFuncName)
420 HeapFree(GetProcessHeap(), 0, (char *)funcName);
421 TRACE("returning %p\n", ret);
425 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
426 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
430 CryptEncodeObjectFunc pCryptEncodeObject;
432 TRACE("(0x%08lx, %s, %p, %p, %p)\n", dwCertEncodingType,
433 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
436 if (!pbEncoded && !pcbEncoded)
438 SetLastError(ERROR_INVALID_PARAMETER);
442 /* Try registered DLL first.. */
444 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
445 lpszStructType, "CryptEncodeObject", &lib);
446 if (pCryptEncodeObject)
448 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
449 pvStructInfo, pbEncoded, pcbEncoded);
454 /* If not, use CryptEncodeObjectEx */
455 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
456 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
461 /* Helper function to check *pcbEncoded, set it to the required size, and
462 * optionally to allocate memory. Assumes pbEncoded is not NULL.
463 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
464 * pointer to the newly allocated memory.
466 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
467 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
472 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
474 if (pEncodePara && pEncodePara->pfnAlloc)
475 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
477 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
478 if (!*(BYTE **)pbEncoded)
481 *pcbEncoded = bytesNeeded;
483 else if (bytesNeeded > *pcbEncoded)
485 *pcbEncoded = bytesNeeded;
486 SetLastError(ERROR_MORE_DATA);
492 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
494 DWORD bytesNeeded, significantBytes = 0;
502 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
503 temp <<= 8, significantBytes--)
505 bytesNeeded = significantBytes + 1;
509 *pcbEncoded = bytesNeeded;
512 if (*pcbEncoded < bytesNeeded)
514 SetLastError(ERROR_MORE_DATA);
518 *pbEncoded = (BYTE)len;
523 *pbEncoded++ = significantBytes | 0x80;
524 for (i = 0; i < significantBytes; i++)
526 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
530 *pcbEncoded = bytesNeeded;
534 struct AsnEncodeSequenceItem
536 const void *pvStructInfo;
537 CryptEncodeObjectExFunc encodeFunc;
538 DWORD size; /* used during encoding, not for your use */
541 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
542 struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
543 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
546 DWORD i, dataLen = 0;
548 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", items, cItem, dwFlags, pEncodePara,
549 pbEncoded, *pcbEncoded);
550 for (i = 0, ret = TRUE; ret && i < cItem; i++)
552 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
553 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
554 NULL, &items[i].size);
555 dataLen += items[i].size;
559 DWORD lenBytes, bytesNeeded;
561 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
562 bytesNeeded = 1 + lenBytes + dataLen;
564 *pcbEncoded = bytesNeeded;
567 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
568 pcbEncoded, bytesNeeded)))
570 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
571 pbEncoded = *(BYTE **)pbEncoded;
572 *pbEncoded++ = ASN_SEQUENCE;
573 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
574 pbEncoded += lenBytes;
575 for (i = 0; ret && i < cItem; i++)
577 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
578 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
579 NULL, pbEncoded, &items[i].size);
580 pbEncoded += items[i].size;
585 TRACE("returning %d (%08lx)\n", ret, GetLastError());
589 struct AsnConstructedItem
592 const void *pvStructInfo;
593 CryptEncodeObjectExFunc encodeFunc;
596 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
597 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
598 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
601 const struct AsnConstructedItem *item =
602 (const struct AsnConstructedItem *)pvStructInfo;
605 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
606 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
608 DWORD dataLen, bytesNeeded;
610 CRYPT_EncodeLen(len, NULL, &dataLen);
611 bytesNeeded = 1 + dataLen + len;
613 *pcbEncoded = bytesNeeded;
614 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
615 pbEncoded, pcbEncoded, bytesNeeded)))
617 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
618 pbEncoded = *(BYTE **)pbEncoded;
619 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
620 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
621 pbEncoded += dataLen;
622 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
623 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
630 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
631 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
632 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
634 const DWORD *ver = (const DWORD *)pvStructInfo;
637 /* CERT_V1 is not encoded */
645 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
647 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
648 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
653 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
654 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
655 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
657 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
662 *pcbEncoded = blob->cbData;
665 else if (*pcbEncoded < blob->cbData)
667 *pcbEncoded = blob->cbData;
668 SetLastError(ERROR_MORE_DATA);
674 memcpy(pbEncoded, blob->pbData, blob->cbData);
675 *pcbEncoded = blob->cbData;
681 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
682 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
683 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
686 /* This has two filetimes in a row, a NotBefore and a NotAfter */
687 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
688 struct AsnEncodeSequenceItem items[] = {
689 { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
690 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
693 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
694 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
699 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
700 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
701 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
704 const CRYPT_ALGORITHM_IDENTIFIER *algo =
705 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
707 struct AsnEncodeSequenceItem items[] = {
708 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
709 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
712 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
713 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
718 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
719 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
720 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
726 const CERT_PUBLIC_KEY_INFO *info =
727 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
728 struct AsnEncodeSequenceItem items[] = {
729 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
730 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
733 TRACE("Encoding public key with OID %s\n",
734 debugstr_a(info->Algorithm.pszObjId));
735 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
736 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
741 SetLastError(STATUS_ACCESS_VIOLATION);
748 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
749 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
750 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
756 const CERT_SIGNED_CONTENT_INFO *info =
757 (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
758 struct AsnEncodeSequenceItem items[] = {
759 { &info->ToBeSigned, CRYPT_CopyEncodedBlob, 0 },
760 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
761 { &info->Signature, CRYPT_AsnEncodeBitsSwapBytes, 0 },
764 if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
765 items[2].encodeFunc = CRYPT_AsnEncodeBits;
766 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
767 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
772 SetLastError(STATUS_ACCESS_VIOLATION);
779 /* Like in Windows, this blithely ignores the validity of the passed-in
780 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
781 * decode properly, see CRYPT_AsnDecodeCertInfo.
783 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
784 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
785 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
791 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
792 struct AsnEncodeSequenceItem items[10] = {
793 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
794 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
795 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
796 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
797 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
798 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
799 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
802 struct AsnConstructedItem constructed[3] = { { 0 } };
803 DWORD cItem = 7, cConstructed = 0;
805 if (info->IssuerUniqueId.cbData)
807 constructed[cConstructed].tag = 1;
808 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
809 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
810 items[cItem].pvStructInfo = &constructed[cConstructed];
811 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
815 if (info->SubjectUniqueId.cbData)
817 constructed[cConstructed].tag = 2;
818 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
819 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
820 items[cItem].pvStructInfo = &constructed[cConstructed];
821 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
825 if (info->cExtension)
827 constructed[cConstructed].tag = 3;
828 constructed[cConstructed].pvStructInfo = &info->cExtension;
829 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
830 items[cItem].pvStructInfo = &constructed[cConstructed];
831 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
836 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
837 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
841 SetLastError(STATUS_ACCESS_VIOLATION);
848 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
849 BYTE *pbEncoded, DWORD *pcbEncoded)
851 struct AsnEncodeSequenceItem items[3] = {
852 { &entry->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
853 { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
859 TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
861 if (entry->cExtension)
863 items[cItem].pvStructInfo = &entry->cExtension;
864 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
868 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
869 pbEncoded, pcbEncoded);
871 TRACE("returning %d (%08lx)\n", ret, GetLastError());
875 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
876 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
877 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
879 DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
880 DWORD bytesNeeded, dataLen, lenBytes, i;
881 const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY **)
882 ((const BYTE *)pvStructInfo + sizeof(DWORD));
885 for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
889 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
893 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
894 bytesNeeded = 1 + lenBytes + dataLen;
896 *pcbEncoded = bytesNeeded;
899 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
900 pcbEncoded, bytesNeeded)))
902 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
903 pbEncoded = *(BYTE **)pbEncoded;
904 *pbEncoded++ = ASN_SEQUENCEOF;
905 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
906 pbEncoded += lenBytes;
907 for (i = 0; i < cCRLEntry; i++)
909 DWORD size = dataLen;
911 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
920 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
921 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
922 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
924 const DWORD *ver = (const DWORD *)pvStructInfo;
927 /* CRL_V1 is not encoded */
934 ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
935 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
939 /* Like in Windows, this blithely ignores the validity of the passed-in
940 * CRL_INFO, and just encodes it as-is. The resulting encoded data may not
941 * decode properly, see CRYPT_AsnDecodeCRLInfo.
943 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
944 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
945 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
951 const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
952 struct AsnEncodeSequenceItem items[7] = {
953 { &info->dwVersion, CRYPT_AsnEncodeCRLVersion, 0 },
954 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
955 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
956 { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 },
959 struct AsnConstructedItem constructed = { 0 };
962 if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
964 items[cItem].pvStructInfo = &info->NextUpdate;
965 items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
970 items[cItem].pvStructInfo = &info->cCRLEntry;
971 items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
974 if (info->cExtension)
976 /* FIXME: is this really constructed? if so, is this the right tag?
979 constructed.pvStructInfo = &info->cExtension;
980 constructed.encodeFunc = CRYPT_AsnEncodeExtensions;
981 items[cItem].pvStructInfo = &constructed;
982 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
986 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
987 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
991 SetLastError(STATUS_ACCESS_VIOLATION);
998 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
1002 struct AsnEncodeSequenceItem items[3] = {
1003 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
1009 TRACE("%p, %p, %ld\n", ext, pbEncoded, *pcbEncoded);
1013 items[cItem].pvStructInfo = &ext->fCritical;
1014 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1017 items[cItem].pvStructInfo = &ext->Value;
1018 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
1021 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
1022 pbEncoded, pcbEncoded);
1023 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1027 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
1028 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1029 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1035 DWORD bytesNeeded, dataLen, lenBytes, i;
1036 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
1039 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
1043 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
1047 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1048 bytesNeeded = 1 + lenBytes + dataLen;
1050 *pcbEncoded = bytesNeeded;
1053 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1054 pcbEncoded, bytesNeeded)))
1056 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1057 pbEncoded = *(BYTE **)pbEncoded;
1058 *pbEncoded++ = ASN_SEQUENCEOF;
1059 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1060 pbEncoded += lenBytes;
1061 for (i = 0; i < exts->cExtension; i++)
1063 DWORD size = dataLen;
1065 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
1073 __EXCEPT(page_fault)
1075 SetLastError(STATUS_ACCESS_VIOLATION);
1082 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
1083 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1084 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1086 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
1087 DWORD bytesNeeded = 0, lenBytes;
1092 TRACE("%s\n", debugstr_a(pszObjId));
1099 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
1101 SetLastError(CRYPT_E_ASN1_ERROR);
1105 firstByte = val1 * 40 + val2;
1106 ptr = pszObjId + firstPos;
1111 /* note I assume each component is at most 32-bits long in base 2 */
1112 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
1114 if (val1 >= 0x10000000)
1116 else if (val1 >= 0x200000)
1118 else if (val1 >= 0x4000)
1120 else if (val1 >= 0x80)
1130 SetLastError(CRYPT_E_ASN1_ERROR);
1134 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1138 bytesNeeded += 1 + lenBytes;
1141 if (*pcbEncoded < bytesNeeded)
1143 SetLastError(ERROR_MORE_DATA);
1148 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
1149 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
1150 pbEncoded += lenBytes;
1156 *pbEncoded++ = firstByte;
1157 ptr = pszObjId + firstPos;
1160 sscanf(ptr, "%d%n", &val, &pos);
1162 unsigned char outBytes[5];
1165 if (val >= 0x10000000)
1167 else if (val >= 0x200000)
1169 else if (val >= 0x4000)
1171 else if (val >= 0x80)
1175 for (i = numBytes; i > 0; i--)
1177 outBytes[i - 1] = val & 0x7f;
1180 for (i = 0; i < numBytes - 1; i++)
1181 *pbEncoded++ = outBytes[i] | 0x80;
1182 *pbEncoded++ = outBytes[i];
1191 *pcbEncoded = bytesNeeded;
1195 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
1196 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
1199 DWORD bytesNeeded, lenBytes, encodedLen;
1202 switch (value->dwValueType)
1204 case CERT_RDN_NUMERIC_STRING:
1205 tag = ASN_NUMERICSTRING;
1206 encodedLen = value->Value.cbData;
1208 case CERT_RDN_PRINTABLE_STRING:
1209 tag = ASN_PRINTABLESTRING;
1210 encodedLen = value->Value.cbData;
1212 case CERT_RDN_IA5_STRING:
1213 tag = ASN_IA5STRING;
1214 encodedLen = value->Value.cbData;
1216 case CERT_RDN_ANY_TYPE:
1217 /* explicitly disallowed */
1218 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1221 FIXME("String type %ld unimplemented\n", value->dwValueType);
1224 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1225 bytesNeeded = 1 + lenBytes + encodedLen;
1228 if (*pcbEncoded < bytesNeeded)
1230 SetLastError(ERROR_MORE_DATA);
1236 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1237 pbEncoded += lenBytes;
1238 switch (value->dwValueType)
1240 case CERT_RDN_NUMERIC_STRING:
1241 case CERT_RDN_PRINTABLE_STRING:
1242 case CERT_RDN_IA5_STRING:
1243 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
1247 *pcbEncoded = bytesNeeded;
1251 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1252 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
1254 DWORD bytesNeeded = 0, lenBytes, size;
1257 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1258 0, NULL, NULL, &size);
1261 bytesNeeded += size;
1262 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1263 * with dwValueType, so "cast" it to get its encoded size
1265 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1266 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
1269 bytesNeeded += size;
1270 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1271 bytesNeeded += 1 + lenBytes;
1274 if (*pcbEncoded < bytesNeeded)
1276 SetLastError(ERROR_MORE_DATA);
1281 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
1282 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1284 pbEncoded += lenBytes;
1285 size = bytesNeeded - 1 - lenBytes;
1286 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1287 attr->pszObjId, 0, NULL, pbEncoded, &size);
1291 size = bytesNeeded - 1 - lenBytes - size;
1292 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1293 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
1298 *pcbEncoded = bytesNeeded;
1304 static int BLOBComp(const void *l, const void *r)
1306 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
1309 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1310 ret = a->cbData - b->cbData;
1314 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1316 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1317 BYTE *pbEncoded, DWORD *pcbEncoded)
1320 CRYPT_DER_BLOB *blobs = NULL;
1324 DWORD bytesNeeded = 0, lenBytes, i;
1329 blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1330 rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1334 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1336 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1337 NULL, &blobs[i].cbData);
1339 bytesNeeded += blobs[i].cbData;
1343 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1344 bytesNeeded += 1 + lenBytes;
1347 if (*pcbEncoded < bytesNeeded)
1349 SetLastError(ERROR_MORE_DATA);
1354 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1356 blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
1358 if (!blobs[i].pbData)
1361 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1362 &rdn->rgRDNAttr[i], blobs[i].pbData,
1367 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1369 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1370 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1372 pbEncoded += lenBytes;
1373 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1375 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1376 pbEncoded += blobs[i].cbData;
1381 *pcbEncoded = bytesNeeded;
1385 for (i = 0; i < rdn->cRDNAttr; i++)
1386 HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
1389 __EXCEPT(page_fault)
1391 SetLastError(STATUS_ACCESS_VIOLATION);
1395 HeapFree(GetProcessHeap(), 0, blobs);
1399 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1400 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1401 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1407 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1408 DWORD bytesNeeded = 0, lenBytes, size, i;
1410 TRACE("encoding name with %ld RDNs\n", info->cRDN);
1412 for (i = 0; ret && i < info->cRDN; i++)
1414 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1417 bytesNeeded += size;
1419 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1420 bytesNeeded += 1 + lenBytes;
1424 *pcbEncoded = bytesNeeded;
1427 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1428 pbEncoded, pcbEncoded, bytesNeeded)))
1430 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1431 pbEncoded = *(BYTE **)pbEncoded;
1432 *pbEncoded++ = ASN_SEQUENCEOF;
1433 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1435 pbEncoded += lenBytes;
1436 for (i = 0; ret && i < info->cRDN; i++)
1439 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1440 &info->rgRDN[i], pbEncoded, &size);
1444 bytesNeeded -= size;
1451 __EXCEPT(page_fault)
1453 SetLastError(STATUS_ACCESS_VIOLATION);
1460 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1461 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1462 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1464 BOOL val = *(const BOOL *)pvStructInfo, ret;
1473 else if (*pcbEncoded < 3)
1476 SetLastError(ERROR_MORE_DATA);
1482 *pbEncoded++ = ASN_BOOL;
1484 *pbEncoded++ = val ? 0xff : 0;
1487 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1491 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1492 BYTE *pbEncoded, DWORD *pcbEncoded)
1498 switch (entry->dwAltNameChoice)
1500 case CERT_ALT_NAME_RFC822_NAME:
1501 case CERT_ALT_NAME_DNS_NAME:
1502 case CERT_ALT_NAME_URL:
1503 if (entry->u.pwszURL)
1507 /* Not + 1: don't encode the NULL-terminator */
1508 dataLen = lstrlenW(entry->u.pwszURL);
1509 for (i = 0; ret && i < dataLen; i++)
1511 if (entry->u.pwszURL[i] > 0x7f)
1513 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1522 case CERT_ALT_NAME_IP_ADDRESS:
1523 dataLen = entry->u.IPAddress.cbData;
1525 case CERT_ALT_NAME_REGISTERED_ID:
1526 /* FIXME: encode OID */
1527 case CERT_ALT_NAME_OTHER_NAME:
1528 case CERT_ALT_NAME_DIRECTORY_NAME:
1529 FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice);
1532 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1537 DWORD bytesNeeded, lenBytes;
1539 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1540 bytesNeeded = 1 + dataLen + lenBytes;
1542 *pcbEncoded = bytesNeeded;
1543 else if (*pcbEncoded < bytesNeeded)
1545 SetLastError(ERROR_MORE_DATA);
1546 *pcbEncoded = bytesNeeded;
1551 *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1552 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1553 pbEncoded += lenBytes;
1554 switch (entry->dwAltNameChoice)
1556 case CERT_ALT_NAME_RFC822_NAME:
1557 case CERT_ALT_NAME_DNS_NAME:
1558 case CERT_ALT_NAME_URL:
1562 for (i = 0; i < dataLen; i++)
1563 *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1566 case CERT_ALT_NAME_IP_ADDRESS:
1567 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1571 *pcbEncoded = bytesNeeded;
1577 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1578 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1579 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1585 const CERT_ALT_NAME_INFO *info =
1586 (const CERT_ALT_NAME_INFO *)pvStructInfo;
1588 DWORD bytesNeeded, dataLen, lenBytes, i;
1591 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1592 * can't encode an erroneous entry index if it's bigger than this.
1594 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1598 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1605 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1606 bytesNeeded = 1 + lenBytes + dataLen;
1609 *pcbEncoded = bytesNeeded;
1614 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1615 pbEncoded, pcbEncoded, bytesNeeded)))
1617 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1618 pbEncoded = *(BYTE **)pbEncoded;
1619 *pbEncoded++ = ASN_SEQUENCEOF;
1620 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1621 pbEncoded += lenBytes;
1622 for (i = 0; ret && i < info->cAltEntry; i++)
1624 DWORD len = dataLen;
1626 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1633 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1635 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1636 * the bad character, now set the index of the bad
1639 *pcbEncoded |= (BYTE)i <<
1640 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT;
1647 __EXCEPT(page_fault)
1649 SetLastError(STATUS_ACCESS_VIOLATION);
1656 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1657 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1658 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1664 const CERT_BASIC_CONSTRAINTS2_INFO *info =
1665 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1666 struct AsnEncodeSequenceItem items[2] = { { 0 } };
1671 items[cItem].pvStructInfo = &info->fCA;
1672 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1675 if (info->fPathLenConstraint)
1677 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1678 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1681 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1682 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1684 __EXCEPT(page_fault)
1686 SetLastError(STATUS_ACCESS_VIOLATION);
1693 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1694 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1695 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1701 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1702 DWORD bytesNeeded, lenBytes;
1704 TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1705 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1707 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1708 bytesNeeded = 1 + lenBytes + blob->cbData;
1711 *pcbEncoded = bytesNeeded;
1716 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1717 pcbEncoded, bytesNeeded)))
1719 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1720 pbEncoded = *(BYTE **)pbEncoded;
1721 *pbEncoded++ = ASN_OCTETSTRING;
1722 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1723 pbEncoded += lenBytes;
1725 memcpy(pbEncoded, blob->pbData, blob->cbData);
1729 __EXCEPT(page_fault)
1731 SetLastError(STATUS_ACCESS_VIOLATION);
1735 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1739 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1740 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1741 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1747 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1748 DWORD bytesNeeded, lenBytes, dataBytes;
1751 /* yep, MS allows cUnusedBits to be >= 8 */
1752 if (!blob->cUnusedBits)
1754 dataBytes = blob->cbData;
1757 else if (blob->cbData * 8 > blob->cUnusedBits)
1759 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1760 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1768 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1769 bytesNeeded = 1 + lenBytes + dataBytes + 1;
1772 *pcbEncoded = bytesNeeded;
1777 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1778 pcbEncoded, bytesNeeded)))
1780 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1781 pbEncoded = *(BYTE **)pbEncoded;
1782 *pbEncoded++ = ASN_BITSTRING;
1783 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1784 pbEncoded += lenBytes;
1785 *pbEncoded++ = unusedBits;
1788 BYTE mask = 0xff << unusedBits;
1792 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1793 pbEncoded += dataBytes - 1;
1795 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1800 __EXCEPT(page_fault)
1802 SetLastError(STATUS_ACCESS_VIOLATION);
1809 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
1810 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1811 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1817 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1818 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
1823 newBlob.pbData = HeapAlloc(GetProcessHeap(), 0, newBlob.cbData);
1828 for (i = 0; i < newBlob.cbData; i++)
1829 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
1835 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
1836 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1837 HeapFree(GetProcessHeap(), 0, newBlob.pbData);
1839 __EXCEPT(page_fault)
1841 SetLastError(STATUS_ACCESS_VIOLATION);
1848 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1849 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1850 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1852 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1854 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1855 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1858 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1859 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1860 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1866 DWORD significantBytes, lenBytes;
1867 BYTE padByte = 0, bytesNeeded;
1869 const CRYPT_INTEGER_BLOB *blob =
1870 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1872 significantBytes = blob->cbData;
1873 if (significantBytes)
1875 if (blob->pbData[significantBytes - 1] & 0x80)
1877 /* negative, lop off leading (little-endian) 0xffs */
1878 for (; significantBytes > 0 &&
1879 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1881 if (blob->pbData[significantBytes - 1] < 0x80)
1889 /* positive, lop off leading (little-endian) zeroes */
1890 for (; significantBytes > 0 &&
1891 !blob->pbData[significantBytes - 1]; significantBytes--)
1893 if (significantBytes == 0)
1894 significantBytes = 1;
1895 if (blob->pbData[significantBytes - 1] > 0x7f)
1903 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1905 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1906 bytesNeeded = 1 + lenBytes + significantBytes;
1911 *pcbEncoded = bytesNeeded;
1916 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1917 pcbEncoded, bytesNeeded)))
1919 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1920 pbEncoded = *(BYTE **)pbEncoded;
1921 *pbEncoded++ = ASN_INTEGER;
1924 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1925 pbEncoded += lenBytes;
1926 *pbEncoded++ = padByte;
1930 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1931 pbEncoded += lenBytes;
1933 for (; significantBytes > 0; significantBytes--)
1934 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1938 __EXCEPT(page_fault)
1940 SetLastError(STATUS_ACCESS_VIOLATION);
1947 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1948 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1949 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1955 DWORD significantBytes, lenBytes;
1958 const CRYPT_INTEGER_BLOB *blob =
1959 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1961 significantBytes = blob->cbData;
1962 if (significantBytes)
1964 /* positive, lop off leading (little-endian) zeroes */
1965 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1968 if (significantBytes == 0)
1969 significantBytes = 1;
1970 if (blob->pbData[significantBytes - 1] > 0x7f)
1974 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1976 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1977 bytesNeeded = 1 + lenBytes + significantBytes;
1982 *pcbEncoded = bytesNeeded;
1987 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1988 pcbEncoded, bytesNeeded)))
1990 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1991 pbEncoded = *(BYTE **)pbEncoded;
1992 *pbEncoded++ = ASN_INTEGER;
1995 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1996 pbEncoded += lenBytes;
2001 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2002 pbEncoded += lenBytes;
2004 for (; significantBytes > 0; significantBytes--)
2005 *(pbEncoded++) = blob->pbData[significantBytes - 1];
2009 __EXCEPT(page_fault)
2011 SetLastError(STATUS_ACCESS_VIOLATION);
2018 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2019 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2020 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2022 CRYPT_INTEGER_BLOB blob;
2025 /* Encode as an unsigned integer, then change the tag to enumerated */
2026 blob.cbData = sizeof(DWORD);
2027 blob.pbData = (BYTE *)pvStructInfo;
2028 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2029 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2030 if (ret && pbEncoded)
2032 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2033 pbEncoded = *(BYTE **)pbEncoded;
2034 pbEncoded[0] = ASN_ENUMERATED;
2039 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2040 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2041 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2048 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
2049 * temporary buffer because the output buffer is not NULL-terminated.
2052 static const DWORD bytesNeeded = sizeof(buf) - 1;
2056 *pcbEncoded = bytesNeeded;
2061 /* Sanity check the year, this is a two-digit year format */
2062 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2064 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2066 SetLastError(CRYPT_E_BAD_ENCODE);
2071 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2072 pbEncoded, pcbEncoded, bytesNeeded)))
2074 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2075 pbEncoded = *(BYTE **)pbEncoded;
2076 buf[0] = ASN_UTCTIME;
2077 buf[1] = bytesNeeded - 2;
2078 snprintf(buf + 2, sizeof(buf) - 2,
2079 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2080 sysTime.wYear - 2000 : sysTime.wYear - 1900,
2081 sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2082 sysTime.wMinute, sysTime.wSecond);
2083 memcpy(pbEncoded, buf, bytesNeeded);
2088 __EXCEPT(page_fault)
2090 SetLastError(STATUS_ACCESS_VIOLATION);
2097 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2098 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2099 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2106 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
2107 * temporary buffer because the output buffer is not NULL-terminated.
2110 static const DWORD bytesNeeded = sizeof(buf) - 1;
2114 *pcbEncoded = bytesNeeded;
2119 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2122 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2123 pcbEncoded, bytesNeeded);
2126 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2127 pbEncoded = *(BYTE **)pbEncoded;
2128 buf[0] = ASN_GENERALTIME;
2129 buf[1] = bytesNeeded - 2;
2130 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2131 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2132 sysTime.wMinute, sysTime.wSecond);
2133 memcpy(pbEncoded, buf, bytesNeeded);
2137 __EXCEPT(page_fault)
2139 SetLastError(STATUS_ACCESS_VIOLATION);
2146 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2147 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2148 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2156 /* Check the year, if it's in the UTCTime range call that encode func */
2157 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2159 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2160 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2161 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2163 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2164 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2167 __EXCEPT(page_fault)
2169 SetLastError(STATUS_ACCESS_VIOLATION);
2176 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2177 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2178 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2184 DWORD bytesNeeded, dataLen, lenBytes, i;
2185 const CRYPT_SEQUENCE_OF_ANY *seq =
2186 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2188 for (i = 0, dataLen = 0; i < seq->cValue; i++)
2189 dataLen += seq->rgValue[i].cbData;
2190 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2191 bytesNeeded = 1 + lenBytes + dataLen;
2194 *pcbEncoded = bytesNeeded;
2199 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2200 pcbEncoded, bytesNeeded)))
2202 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2203 pbEncoded = *(BYTE **)pbEncoded;
2204 *pbEncoded++ = ASN_SEQUENCEOF;
2205 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2206 pbEncoded += lenBytes;
2207 for (i = 0; i < seq->cValue; i++)
2209 memcpy(pbEncoded, seq->rgValue[i].pbData,
2210 seq->rgValue[i].cbData);
2211 pbEncoded += seq->rgValue[i].cbData;
2216 __EXCEPT(page_fault)
2218 SetLastError(STATUS_ACCESS_VIOLATION);
2225 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2226 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2227 void *pvEncoded, DWORD *pcbEncoded)
2231 CryptEncodeObjectExFunc encodeFunc = NULL;
2233 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2234 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2235 pvEncoded, pcbEncoded);
2237 if (!pvEncoded && !pcbEncoded)
2239 SetLastError(ERROR_INVALID_PARAMETER);
2242 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2243 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2245 SetLastError(ERROR_FILE_NOT_FOUND);
2249 SetLastError(NOERROR);
2250 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2251 *(BYTE **)pvEncoded = NULL;
2252 if (!HIWORD(lpszStructType))
2254 switch (LOWORD(lpszStructType))
2256 case (WORD)X509_CERT:
2257 encodeFunc = CRYPT_AsnEncodeCert;
2259 case (WORD)X509_CERT_TO_BE_SIGNED:
2260 encodeFunc = CRYPT_AsnEncodeCertInfo;
2262 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2263 encodeFunc = CRYPT_AsnEncodeCRLInfo;
2265 case (WORD)X509_EXTENSIONS:
2266 encodeFunc = CRYPT_AsnEncodeExtensions;
2268 case (WORD)X509_NAME:
2269 encodeFunc = CRYPT_AsnEncodeName;
2271 case (WORD)X509_PUBLIC_KEY_INFO:
2272 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2274 case (WORD)X509_ALTERNATE_NAME:
2275 encodeFunc = CRYPT_AsnEncodeAltName;
2277 case (WORD)X509_BASIC_CONSTRAINTS2:
2278 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2280 case (WORD)X509_OCTET_STRING:
2281 encodeFunc = CRYPT_AsnEncodeOctets;
2283 case (WORD)X509_BITS:
2284 case (WORD)X509_KEY_USAGE:
2285 encodeFunc = CRYPT_AsnEncodeBits;
2287 case (WORD)X509_INTEGER:
2288 encodeFunc = CRYPT_AsnEncodeInt;
2290 case (WORD)X509_MULTI_BYTE_INTEGER:
2291 encodeFunc = CRYPT_AsnEncodeInteger;
2293 case (WORD)X509_MULTI_BYTE_UINT:
2294 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2296 case (WORD)X509_ENUMERATED:
2297 encodeFunc = CRYPT_AsnEncodeEnumerated;
2299 case (WORD)X509_CHOICE_OF_TIME:
2300 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2302 case (WORD)X509_SEQUENCE_OF_ANY:
2303 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2305 case (WORD)PKCS_UTC_TIME:
2306 encodeFunc = CRYPT_AsnEncodeUtcTime;
2309 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2312 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2313 encodeFunc = CRYPT_AsnEncodeExtensions;
2314 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2315 encodeFunc = CRYPT_AsnEncodeUtcTime;
2316 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2317 encodeFunc = CRYPT_AsnEncodeEnumerated;
2318 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2319 encodeFunc = CRYPT_AsnEncodeBits;
2320 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2321 encodeFunc = CRYPT_AsnEncodeOctets;
2322 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2323 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2324 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2325 encodeFunc = CRYPT_AsnEncodeAltName;
2326 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2327 encodeFunc = CRYPT_AsnEncodeAltName;
2328 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2329 encodeFunc = CRYPT_AsnEncodeAltName;
2330 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2331 encodeFunc = CRYPT_AsnEncodeAltName;
2332 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2333 encodeFunc = CRYPT_AsnEncodeAltName;
2335 TRACE("OID %s not found or unimplemented, looking for DLL\n",
2336 debugstr_a(lpszStructType));
2338 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
2339 lpszStructType, "CryptEncodeObjectEx", &lib);
2341 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2342 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2344 SetLastError(ERROR_FILE_NOT_FOUND);
2350 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2351 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
2352 DWORD *pcbStructInfo)
2356 CryptDecodeObjectFunc pCryptDecodeObject;
2358 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType,
2359 debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
2360 pvStructInfo, pcbStructInfo);
2362 if (!pvStructInfo && !pcbStructInfo)
2364 SetLastError(ERROR_INVALID_PARAMETER);
2368 /* Try registered DLL first.. */
2369 pCryptDecodeObject =
2370 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
2371 lpszStructType, "CryptDecodeObject", &lib);
2372 if (pCryptDecodeObject)
2374 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
2375 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
2380 /* If not, use CryptDecodeObjectEx */
2381 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
2382 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
2387 /* Gets the number of length bytes from the given (leading) length byte */
2388 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
2390 /* Helper function to get the encoded length of the data starting at pbEncoded,
2391 * where pbEncoded[0] is the tag. If the data are too short to contain a
2392 * length or if the length is too large for cbEncoded, sets an appropriate
2393 * error code and returns FALSE.
2395 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
2402 SetLastError(CRYPT_E_ASN1_CORRUPT);
2405 else if (pbEncoded[1] <= 0x7f)
2407 *len = pbEncoded[1];
2412 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
2414 if (lenLen > sizeof(DWORD) + 1)
2416 SetLastError(CRYPT_E_ASN1_LARGE);
2419 else if (lenLen + 2 > cbEncoded)
2421 SetLastError(CRYPT_E_ASN1_CORRUPT);
2432 out |= *pbEncoded++;
2434 if (out + lenLen + 1 > cbEncoded)
2436 SetLastError(CRYPT_E_ASN1_EOD);
2449 /* Helper function to check *pcbStructInfo, set it to the required size, and
2450 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
2451 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
2452 * pointer to the newly allocated memory.
2454 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
2455 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2460 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2462 if (pDecodePara && pDecodePara->pfnAlloc)
2463 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
2465 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
2466 if (!*(BYTE **)pvStructInfo)
2469 *pcbStructInfo = bytesNeeded;
2471 else if (*pcbStructInfo < bytesNeeded)
2473 *pcbStructInfo = bytesNeeded;
2474 SetLastError(ERROR_MORE_DATA);
2480 /* A few of the members need explanation:
2482 * A sequence is decoded into a struct. The offset member is the
2483 * offset of this item within that struct.
2485 * The decoder function to use. If this is NULL, then the member isn't
2486 * decoded, but minSize space is reserved for it.
2488 * The minimum amount of space occupied after decoding. You must set this.
2489 * hasPointer, pointerOffset, minSize:
2490 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
2491 * the offset within the (outer) struct of the data pointer (or to the
2492 * first data pointer, if more than one exist).
2494 * Used by CRYPT_AsnDecodeSequence, not for your use.
2496 struct AsnDecodeSequenceItem
2499 CryptDecodeObjectExFunc decodeFunc;
2503 DWORD pointerOffset;
2507 /* This decodes an arbitrary sequence into a contiguous block of memory
2508 * (basically, a struct.) Each element being decoded is described by a struct
2509 * AsnDecodeSequenceItem, see above.
2510 * startingPointer is an optional pointer to the first place where dynamic
2511 * data will be stored. If you know the starting offset, you may pass it
2512 * here. Otherwise, pass NULL, and one will be inferred from the items.
2513 * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
2514 * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
2515 * FIXME: use to decode more sequences.
2517 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
2518 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2519 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
2520 void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer)
2524 TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld\n", items, cItem, pbEncoded,
2525 cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo);
2527 if (pbEncoded[0] == ASN_SEQUENCE)
2531 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2533 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2534 DWORD i, bytesNeeded = 0, minSize = 0;
2537 ptr = pbEncoded + 1 + lenBytes;
2538 for (i = 0; ret && i < cItem; i++)
2542 minSize += items[i].minSize;
2543 if (cbEncoded - (ptr - pbEncoded) != 0)
2545 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2548 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2550 if (items[i].decodeFunc)
2552 ret = items[i].decodeFunc(dwCertEncodingType, NULL,
2553 ptr, 1 + nextItemLenBytes + nextItemLen,
2554 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
2558 /* Account for alignment padding */
2559 bytesNeeded += items[i].size;
2560 if (items[i].size % sizeof(DWORD))
2561 bytesNeeded += sizeof(DWORD) -
2562 items[i].size % sizeof(DWORD);
2563 ptr += 1 + nextItemLenBytes + nextItemLen;
2565 else if (items[i].optional &&
2566 GetLastError() == CRYPT_E_ASN1_BADTAG)
2568 bytesNeeded += items[i].minSize;
2569 SetLastError(NOERROR);
2574 bytesNeeded += items[i].minSize;
2577 else if (items[i].optional)
2578 bytesNeeded += items[i].minSize;
2581 SetLastError(CRYPT_E_ASN1_CORRUPT);
2588 *pcbStructInfo = bytesNeeded;
2589 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2590 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2594 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2595 pvStructInfo = *(BYTE **)pvStructInfo;
2596 if (startingPointer)
2597 nextData = (BYTE *)startingPointer;
2599 nextData = (BYTE *)pvStructInfo + minSize;
2600 memset(pvStructInfo, 0, minSize);
2601 ptr = pbEncoded + 1 + lenBytes;
2602 for (i = 0; ret && i < cItem; i++)
2604 if (cbEncoded - (ptr - pbEncoded) != 0)
2607 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2609 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2611 if (items[i].hasPointer)
2612 *(BYTE **)((BYTE *)pvStructInfo +
2613 items[i].pointerOffset) = nextData;
2614 if (items[i].decodeFunc)
2615 ret = items[i].decodeFunc(dwCertEncodingType,
2616 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
2617 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2618 (BYTE *)pvStructInfo + items[i].offset,
2621 items[i].size = items[i].minSize;
2624 if (items[i].hasPointer &&
2625 items[i].size > items[i].minSize)
2627 nextData += items[i].size -
2629 /* align nextData to DWORD boundaries */
2630 if (items[i].size % sizeof(DWORD))
2631 nextData += sizeof(DWORD) -
2632 items[i].size % sizeof(DWORD);
2634 ptr += 1 + nextItemLenBytes + nextItemLen;
2636 else if (items[i].optional &&
2637 GetLastError() == CRYPT_E_ASN1_BADTAG)
2639 SetLastError(NOERROR);
2643 else if (!items[i].optional)
2645 SetLastError(CRYPT_E_ASN1_CORRUPT);
2655 SetLastError(CRYPT_E_ASN1_BADTAG);
2658 TRACE("returning %d (%08lx)\n", ret, GetLastError());
2662 /* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
2663 * pvStructInfo. The BLOB must be non-empty, otherwise the last error is set
2664 * to CRYPT_E_ASN1_CORRUPT.
2665 * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
2668 static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
2669 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2670 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2675 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2677 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2678 DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
2680 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2681 bytesNeeded += 1 + lenBytes + dataLen;
2684 *pcbStructInfo = bytesNeeded;
2685 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2686 pvStructInfo, pcbStructInfo, bytesNeeded)))
2688 CRYPT_DER_BLOB *blob = (CRYPT_DER_BLOB *)pvStructInfo;
2690 blob->cbData = 1 + lenBytes + dataLen;
2693 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2694 blob->pbData = (BYTE *)pbEncoded;
2697 assert(blob->pbData);
2698 memcpy(blob->pbData, pbEncoded, blob->cbData);
2703 SetLastError(CRYPT_E_ASN1_CORRUPT);
2711 /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */
2712 static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType,
2713 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2714 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2718 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType,
2719 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
2720 if (ret && pvStructInfo)
2722 CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
2726 for (i = 0; i < blob->cbData / 2; i++)
2728 temp = blob->pbData[i];
2729 blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
2730 blob->pbData[blob->cbData - i - 1] = temp;
2736 static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
2737 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2738 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2742 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2743 pDecodePara, pvStructInfo, *pcbStructInfo);
2747 struct AsnDecodeSequenceItem items[] = {
2748 { offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
2749 CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2750 offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 },
2751 { offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm),
2752 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2753 FALSE, TRUE, offsetof(CERT_SIGNED_CONTENT_INFO,
2754 SignatureAlgorithm.Parameters.pbData), 0 },
2755 { offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
2756 CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
2757 offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 },
2760 if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
2761 items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
2762 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2763 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2764 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2766 __EXCEPT(page_fault)
2768 SetLastError(STATUS_ACCESS_VIOLATION);
2775 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
2776 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2777 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2781 if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR))
2785 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2787 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2789 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
2790 pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
2791 pvStructInfo, pcbStructInfo);
2796 SetLastError(CRYPT_E_ASN1_BADTAG);
2802 static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
2803 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2804 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2808 struct AsnDecodeSequenceItem items[] = {
2809 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
2810 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2811 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
2812 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2815 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2816 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2817 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2821 static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
2822 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2823 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2827 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2828 pDecodePara, pvStructInfo, *pcbStructInfo);
2832 struct AsnDecodeSequenceItem items[] = {
2833 { offsetof(CERT_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
2834 sizeof(DWORD), TRUE, FALSE, 0, 0 },
2835 { offsetof(CERT_INFO, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2836 sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2837 SerialNumber.pbData), 0 },
2838 { offsetof(CERT_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
2839 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CERT_INFO,
2840 SignatureAlgorithm.Parameters.pbData), 0 },
2841 { offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
2842 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2844 { offsetof(CERT_INFO, NotBefore), CRYPT_AsnDecodeValidity,
2845 sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, FALSE, 0 },
2846 { offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
2847 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2849 { offsetof(CERT_INFO, SubjectPublicKeyInfo), CRYPT_AsnDecodePubKeyInfo,
2850 sizeof(CERT_PUBLIC_KEY_INFO), FALSE, TRUE, offsetof(CERT_INFO,
2851 SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
2852 { offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal,
2853 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2854 IssuerUniqueId.pbData), 0 },
2855 { offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal,
2856 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2857 SubjectUniqueId.pbData), 0 },
2858 { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeExtensionsInternal,
2859 sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CERT_INFO,
2863 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2864 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2865 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2867 __EXCEPT(page_fault)
2869 SetLastError(STATUS_ACCESS_VIOLATION);
2876 static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded,
2877 DWORD dwFlags, PCRL_ENTRY entry, DWORD *pcbEntry)
2880 struct AsnDecodeSequenceItem items[] = {
2881 { offsetof(CRL_ENTRY, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2882 sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CRL_ENTRY,
2883 SerialNumber.pbData), 0 },
2884 { offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
2885 sizeof(FILETIME), FALSE, FALSE, 0 },
2886 { offsetof(CRL_ENTRY, cExtension), CRYPT_AsnDecodeExtensionsInternal,
2887 sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CRL_ENTRY,
2891 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry,
2894 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
2895 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2896 NULL, entry, pcbEntry, entry ? entry->SerialNumber.pbData : NULL);
2897 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
2901 typedef struct _WINE_CRL_ENTRIES {
2903 PCRL_ENTRY rgCRLEntry;
2904 } WINE_CRL_ENTRIES, *PWINE_CRL_ENTRIES;
2906 /* Warning: assumes pvStructInfo is a WINE_CRL_ENTRIES whose rgCRLEntry has
2907 * been set prior to calling.
2909 static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
2910 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2911 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2915 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2916 pDecodePara, pvStructInfo, *pcbStructInfo);
2918 if (pbEncoded[0] == ASN_SEQUENCEOF)
2920 DWORD dataLen, bytesNeeded;
2922 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2924 DWORD cCRLEntry = 0;
2925 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2927 bytesNeeded = sizeof(WINE_CRL_ENTRIES);
2933 for (ptr = pbEncoded + 1 + lenBytes; ret &&
2934 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2937 ret = CRYPT_AsnDecodeCRLEntry(ptr,
2938 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
2944 bytesNeeded += size;
2945 ret = CRYPT_GetLen(ptr,
2946 cbEncoded - (ptr - pbEncoded), &nextLen);
2948 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2955 *pcbStructInfo = bytesNeeded;
2956 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2957 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2962 PWINE_CRL_ENTRIES entries;
2964 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2965 pvStructInfo = *(BYTE **)pvStructInfo;
2966 *pcbStructInfo = bytesNeeded;
2967 entries = (PWINE_CRL_ENTRIES)pvStructInfo;
2968 entries->cCRLEntry = cCRLEntry;
2969 assert(entries->rgCRLEntry);
2970 nextData = (BYTE *)entries->rgCRLEntry +
2971 entries->cCRLEntry * sizeof(CRL_ENTRY);
2972 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
2973 i < cCRLEntry && ptr - pbEncoded - 1 - lenBytes <
2976 entries->rgCRLEntry[i].SerialNumber.pbData = nextData;
2978 ret = CRYPT_AsnDecodeCRLEntry(ptr,
2979 cbEncoded - (ptr - pbEncoded), dwFlags,
2980 &entries->rgCRLEntry[i], &size);
2985 bytesNeeded -= size;
2986 /* Increment nextData by the difference of the
2987 * minimum size and the actual size.
2989 if (size > sizeof(CRL_ENTRY))
2990 nextData += size - sizeof(CRL_ENTRY);
2991 ret = CRYPT_GetLen(ptr,
2992 cbEncoded - (ptr - pbEncoded), &nextLen);
2994 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3003 SetLastError(CRYPT_E_ASN1_BADTAG);
3006 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3010 static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
3011 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3012 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3016 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3017 pDecodePara, pvStructInfo, *pcbStructInfo);
3021 struct AsnDecodeSequenceItem items[] = {
3022 { offsetof(CRL_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
3023 sizeof(DWORD), TRUE, FALSE, 0, 0 },
3024 { offsetof(CRL_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
3025 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CRL_INFO,
3026 SignatureAlgorithm.Parameters.pbData), 0 },
3027 { offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
3028 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO,
3030 { offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
3031 sizeof(FILETIME), FALSE, FALSE, 0 },
3032 { offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
3033 sizeof(FILETIME), TRUE, FALSE, 0 },
3034 { offsetof(CRL_INFO, cCRLEntry), CRYPT_AsnDecodeCRLEntries,
3035 sizeof(WINE_CRL_ENTRIES), TRUE, TRUE, offsetof(CRL_INFO,
3037 /* Note that the extensions are ignored by MS, so I'll ignore them too
3039 { offsetof(CRL_INFO, cExtension), NULL,
3040 sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 },
3043 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3044 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3045 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3047 __EXCEPT(page_fault)
3049 SetLastError(STATUS_ACCESS_VIOLATION);
3054 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3058 /* Warning: assumes ext->Value.pbData is set ahead of time! */
3059 static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
3060 DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
3064 if (pbEncoded[0] == ASN_SEQUENCE)
3066 DWORD dataLen, bytesNeeded;
3068 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3070 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]), oidLenBytes = 0;
3072 bytesNeeded = sizeof(CERT_EXTENSION);
3075 const BYTE *ptr = pbEncoded + 1 + lenBytes;
3076 DWORD encodedOidLen, oidLen;
3078 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
3080 oidLenBytes = GET_LEN_BYTES(ptr[1]);
3081 ret = CRYPT_AsnDecodeOid(ptr, cbEncoded - (ptr - pbEncoded),
3082 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &oidLen);
3085 bytesNeeded += oidLen;
3086 ptr += 1 + encodedOidLen + oidLenBytes;
3087 if (*ptr == ASN_BOOL)
3089 ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
3090 X509_OCTET_STRING, ptr, cbEncoded - (ptr - pbEncoded),
3091 0, NULL, NULL, &dataLen);
3092 bytesNeeded += dataLen;
3096 *pcbExt = bytesNeeded;
3097 else if (*pcbExt < bytesNeeded)
3099 SetLastError(ERROR_MORE_DATA);
3104 ptr = pbEncoded + 2 + lenBytes + encodedOidLen +
3106 if (*ptr == ASN_BOOL)
3108 DWORD size = sizeof(BOOL);
3110 CRYPT_AsnDecodeBool(X509_ASN_ENCODING, NULL,
3111 ptr, cbEncoded - (ptr - pbEncoded),
3112 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
3113 &ext->fCritical, &size);
3117 ext->fCritical = FALSE;
3118 ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
3119 X509_OCTET_STRING, ptr,
3120 cbEncoded - (ptr - pbEncoded),
3121 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
3122 &ext->Value, &dataLen);
3125 ext->pszObjId = (LPSTR)ext->Value.pbData +
3127 ptr = pbEncoded + 1 + lenBytes;
3128 ret = CRYPT_AsnDecodeOid(ptr,
3129 cbEncoded - (ptr - pbEncoded),
3130 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
3131 ext->pszObjId, &oidLen);
3139 SetLastError(CRYPT_E_ASN1_EOD);
3146 SetLastError(CRYPT_E_ASN1_BADTAG);
3152 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
3153 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3154 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3158 if (pbEncoded[0] == ASN_SEQUENCEOF)
3160 DWORD dataLen, bytesNeeded;
3162 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3164 DWORD cExtension = 0;
3165 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3167 bytesNeeded = sizeof(CERT_EXTENSIONS);
3173 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3174 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3176 ret = CRYPT_AsnDecodeExtension(ptr,
3177 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3183 bytesNeeded += size;
3184 ret = CRYPT_GetLen(ptr,
3185 cbEncoded - (ptr - pbEncoded), &nextLen);
3187 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3194 *pcbStructInfo = bytesNeeded;
3195 else if (*pcbStructInfo < bytesNeeded)
3197 SetLastError(ERROR_MORE_DATA);
3198 *pcbStructInfo = bytesNeeded;
3206 CERT_EXTENSIONS *exts;
3208 *pcbStructInfo = bytesNeeded;
3209 exts = (CERT_EXTENSIONS *)pvStructInfo;
3210 exts->cExtension = cExtension;
3211 assert(exts->rgExtension);
3212 nextData = (BYTE *)exts->rgExtension +
3213 exts->cExtension * sizeof(CERT_EXTENSION);
3214 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3215 i < cExtension && ptr - pbEncoded - 1 - lenBytes <
3218 exts->rgExtension[i].Value.pbData = nextData;
3220 ret = CRYPT_AsnDecodeExtension(ptr,
3221 cbEncoded - (ptr - pbEncoded), dwFlags,
3222 &exts->rgExtension[i], &size);
3227 bytesNeeded -= size;
3228 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
3229 * data may not have been copied.
3231 if (exts->rgExtension[i].Value.pbData ==
3234 exts->rgExtension[i].Value.cbData;
3235 /* Ugly: the OID, if copied, is stored in
3236 * memory after the value, so increment by its
3237 * string length if it's set and points here.
3239 if ((const BYTE *)exts->rgExtension[i].pszObjId
3242 exts->rgExtension[i].pszObjId) + 1;
3243 ret = CRYPT_GetLen(ptr,
3244 cbEncoded - (ptr - pbEncoded), &nextLen);
3246 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3255 SetLastError(CRYPT_E_ASN1_BADTAG);
3261 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
3262 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3263 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3269 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3270 lpszStructType, pbEncoded, cbEncoded,
3271 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
3272 if (ret && pvStructInfo)
3274 ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
3275 pcbStructInfo, *pcbStructInfo);
3278 CERT_EXTENSIONS *exts;
3280 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3281 pvStructInfo = *(BYTE **)pvStructInfo;
3282 exts = (CERT_EXTENSIONS *)pvStructInfo;
3283 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
3284 sizeof(CERT_EXTENSIONS));
3285 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3286 lpszStructType, pbEncoded, cbEncoded,
3287 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3292 __EXCEPT(page_fault)
3294 SetLastError(STATUS_ACCESS_VIOLATION);
3301 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
3302 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
3303 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
3309 if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
3313 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3315 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3320 /* The largest possible string for the first two components
3321 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
3326 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
3327 pbEncoded[1 + lenBytes] / 40,
3328 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
3330 bytesNeeded = strlen(firstTwo) + 1;
3331 for (ptr = pbEncoded + 2 + lenBytes; ret &&
3332 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3334 /* large enough for ".4000000" */
3338 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3345 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
3348 SetLastError(CRYPT_E_ASN1_CORRUPT);
3355 snprintf(str, sizeof(str), ".%d", val);
3356 bytesNeeded += strlen(str);
3360 *pcbObjId = bytesNeeded;
3361 else if (*pcbObjId < bytesNeeded)
3363 *pcbObjId = bytesNeeded;
3364 SetLastError(ERROR_MORE_DATA);
3369 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
3370 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
3372 pszObjId += strlen(pszObjId);
3373 for (ptr = pbEncoded + 2 + lenBytes; ret &&
3374 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3378 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3387 sprintf(pszObjId, ".%d", val);
3388 pszObjId += strlen(pszObjId);
3394 *pcbObjId = bytesNeeded;
3399 SetLastError(CRYPT_E_ASN1_BADTAG);
3403 __EXCEPT(page_fault)
3405 SetLastError(STATUS_ACCESS_VIOLATION);
3412 /* Warning: this assumes the address of value->Value.pbData is already set, in
3413 * order to avoid overwriting memory. (In some cases, it may change it, if it
3414 * doesn't copy anything to memory.) Be sure to set it correctly!
3416 static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
3417 DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD *pcbValue)
3425 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3427 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3429 switch (pbEncoded[0])
3431 case ASN_NUMERICSTRING:
3432 case ASN_PRINTABLESTRING:
3436 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
3437 SetLastError(OSS_UNIMPLEMENTED);
3442 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
3444 switch (pbEncoded[0])
3446 case ASN_NUMERICSTRING:
3447 case ASN_PRINTABLESTRING:
3449 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3450 bytesNeeded += dataLen;
3454 *pcbValue = bytesNeeded;
3455 else if (*pcbValue < bytesNeeded)
3457 *pcbValue = bytesNeeded;
3458 SetLastError(ERROR_MORE_DATA);
3463 *pcbValue = bytesNeeded;
3464 switch (pbEncoded[0])
3466 case ASN_NUMERICSTRING:
3467 value->dwValueType = CERT_RDN_NUMERIC_STRING;
3469 case ASN_PRINTABLESTRING:
3470 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
3473 value->dwValueType = CERT_RDN_IA5_STRING;
3478 switch (pbEncoded[0])
3480 case ASN_NUMERICSTRING:
3481 case ASN_PRINTABLESTRING:
3483 value->Value.cbData = dataLen;
3484 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3485 value->Value.pbData = (BYTE *)pbEncoded + 1 +
3489 assert(value->Value.pbData);
3490 memcpy(value->Value.pbData,
3491 pbEncoded + 1 + lenBytes, dataLen);
3498 value->Value.cbData = 0;
3499 value->Value.pbData = NULL;
3505 __EXCEPT(page_fault)
3507 SetLastError(STATUS_ACCESS_VIOLATION);
3514 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded,
3515 DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD *pcbAttr)
3521 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCE))
3523 DWORD bytesNeeded, dataLen, size;
3526 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3528 /* The data length must be at least 4, two for the tag and
3529 * length for the OID, and two for the string (assuming both
3530 * have short-form lengths.)
3534 SetLastError(CRYPT_E_ASN1_EOD);
3539 bytesNeeded = sizeof(CERT_RDN_ATTR);
3540 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3541 ret = CRYPT_AsnDecodeOid(pbEncoded + 1 + lenBytes,
3542 cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
3545 /* ugly: need to know the size of the next element of
3546 * the sequence, so get it directly
3548 DWORD objIdOfset = 1 + lenBytes, objIdLen,
3549 nameValueOffset = 0;
3551 ret = CRYPT_GetLen(pbEncoded + objIdOfset,
3552 cbEncoded - objIdOfset, &objIdLen);
3553 bytesNeeded += size;
3554 /* hack: like encoding, this takes advantage of the
3555 * fact that the rest of the structure is identical to
3556 * a CERT_NAME_VALUE.
3560 nameValueOffset = objIdOfset + objIdLen + 1 +
3561 GET_LEN_BYTES(pbEncoded[objIdOfset]);
3562 ret = CRYPT_AsnDecodeNameValue(
3563 pbEncoded + nameValueOffset,
3564 cbEncoded - nameValueOffset, dwFlags, NULL, &size);
3568 bytesNeeded += size;
3570 *pcbAttr = bytesNeeded;
3571 else if (*pcbAttr < bytesNeeded)
3573 *pcbAttr = bytesNeeded;
3574 SetLastError(ERROR_MORE_DATA);
3579 BYTE *originalData = attr->Value.pbData;
3581 *pcbAttr = bytesNeeded;
3582 /* strange: decode the value first, because it
3583 * has a counted size, and we can store the OID
3584 * after it. Keep track of the original data
3585 * pointer, we'll need to know whether it was
3589 ret = CRYPT_AsnDecodeNameValue(
3590 pbEncoded + nameValueOffset,
3591 cbEncoded - nameValueOffset, dwFlags,
3592 (CERT_NAME_VALUE *)&attr->dwValueType, &size);
3597 /* if the data were copied to the
3598 * original location, the OID goes
3599 * after. Otherwise it goes in the
3600 * spot originally reserved for the
3603 if (attr->Value.pbData == originalData)
3605 (LPSTR)(attr->Value.pbData +
3606 attr->Value.cbData);
3608 attr->pszObjId = (LPSTR)originalData;
3609 size = bytesNeeded - size;
3610 ret = CRYPT_AsnDecodeOid(
3611 pbEncoded + objIdOfset,
3612 cbEncoded - objIdOfset,
3613 dwFlags, attr->pszObjId, &size);
3616 attr->pszObjId = NULL;
3626 SetLastError(CRYPT_E_ASN1_BADTAG);
3630 __EXCEPT(page_fault)
3632 SetLastError(STATUS_ACCESS_VIOLATION);
3639 static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
3640 DWORD dwFlags, CERT_RDN *rdn, DWORD *pcbRdn)
3646 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SETOF))
3650 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3652 DWORD bytesNeeded, cRDNAttr = 0;
3653 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3655 bytesNeeded = sizeof(CERT_RDN);
3661 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3662 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3664 ret = CRYPT_AsnDecodeRdnAttr(ptr,
3665 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3671 bytesNeeded += size;
3672 ret = CRYPT_GetLen(ptr,
3673 cbEncoded - (ptr - pbEncoded), &nextLen);
3675 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3682 *pcbRdn = bytesNeeded;
3683 else if (*pcbRdn < bytesNeeded)
3685 *pcbRdn = bytesNeeded;
3686 SetLastError(ERROR_MORE_DATA);
3695 *pcbRdn = bytesNeeded;
3696 rdn->cRDNAttr = cRDNAttr;
3697 rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn +
3699 nextData = (BYTE *)rdn->rgRDNAttr +
3700 rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
3701 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3702 i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
3705 rdn->rgRDNAttr[i].Value.pbData = nextData;
3707 ret = CRYPT_AsnDecodeRdnAttr(ptr,
3708 cbEncoded - (ptr - pbEncoded), dwFlags,
3709 &rdn->rgRDNAttr[i], &size);
3714 bytesNeeded -= size;
3715 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
3716 * data may not have been copied.
3718 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
3720 rdn->rgRDNAttr[i].Value.cbData;
3721 /* Ugly: the OID, if copied, is stored in
3722 * memory after the value, so increment by its
3723 * string length if it's set and points here.
3725 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId
3728 rdn->rgRDNAttr[i].pszObjId) + 1;
3729 ret = CRYPT_GetLen(ptr,
3730 cbEncoded - (ptr - pbEncoded), &nextLen);
3732 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3741 SetLastError(CRYPT_E_ASN1_BADTAG);
3745 __EXCEPT(page_fault)
3747 SetLastError(STATUS_ACCESS_VIOLATION);
3754 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
3755 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3756 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3762 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
3766 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3768 DWORD bytesNeeded, cRDN = 0;
3769 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3771 bytesNeeded = sizeof(CERT_NAME_INFO);
3776 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3777 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3781 ret = CRYPT_AsnDecodeRdn(ptr,
3782 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3788 bytesNeeded += size;
3789 ret = CRYPT_GetLen(ptr,
3790 cbEncoded - (ptr - pbEncoded), &nextLen);
3792 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3799 *pcbStructInfo = bytesNeeded;
3800 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3801 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3803 CERT_NAME_INFO *info;
3805 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3806 pvStructInfo = *(BYTE **)pvStructInfo;
3807 info = (CERT_NAME_INFO *)pvStructInfo;
3809 if (info->cRDN == 0)
3817 info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
3818 sizeof(CERT_NAME_INFO));
3819 nextData = (BYTE *)info->rgRDN +
3820 info->cRDN * sizeof(CERT_RDN);
3821 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3822 i < cRDN && ptr - pbEncoded - 1 - lenBytes <
3825 info->rgRDN[i].rgRDNAttr =
3826 (CERT_RDN_ATTR *)nextData;
3828 ret = CRYPT_AsnDecodeRdn(ptr,
3829 cbEncoded - (ptr - pbEncoded), dwFlags,
3830 &info->rgRDN[i], &size);
3836 bytesNeeded -= size;
3837 ret = CRYPT_GetLen(ptr,
3838 cbEncoded - (ptr - pbEncoded), &nextLen);
3840 ptr += nextLen + 1 +
3841 GET_LEN_BYTES(ptr[1]);
3851 SetLastError(CRYPT_E_ASN1_BADTAG);
3855 __EXCEPT(page_fault)
3857 SetLastError(STATUS_ACCESS_VIOLATION);
3864 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
3865 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3866 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3868 CRYPT_ALGORITHM_IDENTIFIER *algo =
3869 (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
3872 if (pbEncoded[0] == ASN_SEQUENCE)
3874 DWORD dataLen, bytesNeeded;
3876 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3878 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3880 bytesNeeded = sizeof(CRYPT_ALGORITHM_IDENTIFIER);
3883 const BYTE *ptr = pbEncoded + 1 + lenBytes;
3885 DWORD encodedOidLen, oidLen;
3887 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
3889 oidLenBytes = GET_LEN_BYTES(ptr[1]);
3890 ret = CRYPT_AsnDecodeOid(ptr, cbEncoded - (ptr - pbEncoded),
3891 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &oidLen);
3894 bytesNeeded += oidLen;
3895 ptr += 1 + encodedOidLen + oidLenBytes;
3896 /* The remaining bytes are just copied as-is, no decoding
3899 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3900 bytesNeeded += cbEncoded - (ptr - pbEncoded);
3902 *pcbStructInfo = bytesNeeded;
3903 else if (*pcbStructInfo < bytesNeeded)
3905 SetLastError(ERROR_MORE_DATA);
3910 /* Get and sanity-check parameter length first */
3911 if (dataLen - 1 - oidLenBytes - encodedOidLen != 0)
3915 if ((ret = CRYPT_GetLen(ptr, cbEncoded -
3916 (ptr - pbEncoded), ¶msLen)))
3918 BYTE paramsLenBytes = GET_LEN_BYTES(ptr[1]);
3920 if (paramsLen != dataLen - encodedOidLen - 1 -
3921 oidLenBytes - 1 - paramsLenBytes)
3923 SetLastError(CRYPT_E_ASN1_CORRUPT);
3930 *pcbStructInfo = bytesNeeded;
3931 algo->Parameters.cbData = dataLen - 1 -
3932 oidLenBytes - encodedOidLen;
3933 if (algo->Parameters.cbData)
3935 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3937 memcpy(algo->Parameters.pbData, ptr,
3938 algo->Parameters.cbData);
3939 algo->pszObjId = (LPSTR)algo->Parameters.pbData +
3940 algo->Parameters.cbData;
3944 algo->Parameters.pbData = (BYTE *)ptr;
3945 algo->pszObjId = (LPSTR)algo->Parameters.pbData;
3949 algo->pszObjId = (LPSTR)algo->Parameters.pbData;
3950 ptr = pbEncoded + 1 + lenBytes;
3951 ret = CRYPT_AsnDecodeOid(ptr,
3952 cbEncoded - (ptr - pbEncoded),
3953 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
3954 algo->pszObjId, &oidLen);
3961 SetLastError(CRYPT_E_ASN1_EOD);
3968 SetLastError(CRYPT_E_ASN1_BADTAG);
3974 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
3975 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3976 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3982 struct AsnDecodeSequenceItem items[] = {
3983 { offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
3984 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3985 FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO,
3986 Algorithm.Parameters.pbData) },
3987 { offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
3988 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
3989 offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) },
3992 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3993 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3994 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3996 __EXCEPT(page_fault)
3998 SetLastError(STATUS_ACCESS_VIOLATION);
4005 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
4006 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4007 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4013 SetLastError(CRYPT_E_ASN1_CORRUPT);
4016 if (pbEncoded[0] != ASN_BOOL)
4018 SetLastError(CRYPT_E_ASN1_BADTAG);
4021 if (GET_LEN_BYTES(pbEncoded[1]) > 1)
4023 SetLastError(CRYPT_E_ASN1_CORRUPT);
4026 if (pbEncoded[1] > 1)
4028 SetLastError(CRYPT_E_ASN1_CORRUPT);
4033 *pcbStructInfo = sizeof(BOOL);
4036 else if (*pcbStructInfo < sizeof(BOOL))
4038 *pcbStructInfo = sizeof(BOOL);
4039 SetLastError(ERROR_MORE_DATA);
4044 *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
4050 static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded,
4051 DWORD dwFlags, CERT_ALT_NAME_ENTRY *entry, DWORD *pcbEntry)
4053 DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY);
4058 SetLastError(CRYPT_E_ASN1_CORRUPT);
4061 if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT)
4063 SetLastError(CRYPT_E_ASN1_BADTAG);
4066 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4067 if (1 + lenBytes > cbEncoded)
4069 SetLastError(CRYPT_E_ASN1_CORRUPT);
4072 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4074 switch (pbEncoded[0] & ASN_TYPE_MASK)
4076 case 1: /* rfc822Name */
4077 case 2: /* dNSName */
4078 case 6: /* uniformResourceIdentifier */
4079 bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
4081 case 7: /* iPAddress */
4082 bytesNeeded += dataLen;
4084 case 8: /* registeredID */
4085 /* FIXME: decode as OID */
4086 case 0: /* otherName */
4087 case 4: /* directoryName */
4089 SetLastError(CRYPT_E_ASN1_BADTAG);
4092 case 3: /* x400Address, unimplemented */
4093 case 5: /* ediPartyName, unimplemented */
4094 SetLastError(CRYPT_E_ASN1_BADTAG);
4098 SetLastError(CRYPT_E_ASN1_CORRUPT);
4104 *pcbEntry = bytesNeeded;
4105 else if (*pcbEntry < bytesNeeded)
4107 SetLastError(ERROR_MORE_DATA);
4112 /* MS used values one greater than the asn1 ones.. sigh */
4113 entry->dwAltNameChoice = (pbEncoded[0] & 0x7f) + 1;
4114 switch (pbEncoded[0] & ASN_TYPE_MASK)
4116 case 1: /* rfc822Name */
4117 case 2: /* dNSName */
4118 case 6: /* uniformResourceIdentifier */
4122 for (i = 0; i < dataLen; i++)
4123 entry->u.pwszURL[i] = (WCHAR)pbEncoded[1 + lenBytes + i];
4124 entry->u.pwszURL[i] = 0;
4127 case 7: /* iPAddress */
4128 /* The next data pointer is in the pwszURL spot, that is,
4129 * the first 4 bytes. Need to move it to the next spot.
4131 entry->u.IPAddress.pbData = (LPBYTE)entry->u.pwszURL;
4132 entry->u.IPAddress.cbData = dataLen;
4133 memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes,
4143 static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
4144 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4145 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4151 if (pbEncoded[0] == ASN_SEQUENCEOF)
4155 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4157 DWORD bytesNeeded, cEntry = 0;
4158 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4160 bytesNeeded = sizeof(CERT_ALT_NAME_INFO);
4165 for (ptr = pbEncoded + 1 + lenBytes; ret &&
4166 ptr - pbEncoded - 1 - lenBytes < dataLen; )
4170 ret = CRYPT_AsnDecodeAltNameEntry(ptr,
4171 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
4177 bytesNeeded += size;
4178 ret = CRYPT_GetLen(ptr,
4179 cbEncoded - (ptr - pbEncoded), &nextLen);
4181 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
4188 *pcbStructInfo = bytesNeeded;
4189 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
4190 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
4192 CERT_ALT_NAME_INFO *info;
4194 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4195 pvStructInfo = *(BYTE **)pvStructInfo;
4196 info = (CERT_ALT_NAME_INFO *)pvStructInfo;
4197 info->cAltEntry = 0;
4199 info->rgAltEntry = NULL;
4207 (CERT_ALT_NAME_ENTRY *)((BYTE *)pvStructInfo +
4208 sizeof(CERT_ALT_NAME_INFO));
4209 nextData = (BYTE *)info->rgAltEntry +
4210 cEntry * sizeof(CERT_ALT_NAME_ENTRY);
4211 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
4212 i < cEntry && ptr - pbEncoded - 1 - lenBytes <
4215 info->rgAltEntry[i].u.pwszURL = (LPWSTR)nextData;
4217 ret = CRYPT_AsnDecodeAltNameEntry(ptr,
4218 cbEncoded - (ptr - pbEncoded), dwFlags,
4219 &info->rgAltEntry[i], &size);
4226 sizeof(CERT_ALT_NAME_ENTRY);
4227 bytesNeeded -= size;
4228 ret = CRYPT_GetLen(ptr,
4229 cbEncoded - (ptr - pbEncoded), &nextLen);
4231 ptr += nextLen + 1 +
4232 GET_LEN_BYTES(ptr[1]);
4242 SetLastError(CRYPT_E_ASN1_BADTAG);
4246 __EXCEPT(page_fault)
4248 SetLastError(STATUS_ACCESS_VIOLATION);
4255 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
4256 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4257 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4263 if (pbEncoded[0] == ASN_SEQUENCE)
4267 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4269 /* sanity-check length, space enough for 7 bytes of integer and
4274 SetLastError(CRYPT_E_ASN1_CORRUPT);
4279 DWORD bytesNeeded = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
4282 *pcbStructInfo = bytesNeeded;
4286 CERT_BASIC_CONSTRAINTS2_INFO info = { 0 };
4288 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4289 pbEncoded += 1 + lenBytes;
4290 cbEncoded -= 1 + lenBytes;
4295 if (pbEncoded[0] == ASN_BOOL)
4297 size = sizeof(BOOL);
4298 ret = CRYPT_AsnDecodeBool(dwCertEncodingType,
4299 NULL, pbEncoded, cbEncoded,
4300 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
4304 cbEncoded -= 2 + pbEncoded[1];
4305 pbEncoded += 2 + pbEncoded[1];
4308 if (ret && cbEncoded && pbEncoded[0] == ASN_INTEGER)
4310 size = sizeof(info.dwPathLenConstraint);
4311 ret = CRYPT_AsnDecodeInt(dwCertEncodingType,
4312 X509_INTEGER, pbEncoded, cbEncoded, 0, NULL,
4313 &info.dwPathLenConstraint, &size);
4316 cbEncoded -= 2 + pbEncoded[1];
4317 pbEncoded += 2 + pbEncoded[1];
4320 SetLastError(CRYPT_E_ASN1_CORRUPT);
4324 info.fPathLenConstraint = TRUE;
4330 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
4331 pDecodePara, pvStructInfo, pcbStructInfo,
4334 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4335 pvStructInfo = *(BYTE **)pvStructInfo;
4336 memcpy(pvStructInfo, &info,
4337 sizeof(CERT_BASIC_CONSTRAINTS2_INFO));
4346 SetLastError(CRYPT_E_ASN1_BADTAG);
4350 __EXCEPT(page_fault)
4352 SetLastError(STATUS_ACCESS_VIOLATION);
4359 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
4360 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4361 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4367 if (pbEncoded[0] == ASN_OCTETSTRING)
4369 DWORD bytesNeeded, dataLen;
4371 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4373 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4374 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
4376 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
4378 *pcbStructInfo = bytesNeeded;
4379 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4380 pvStructInfo, pcbStructInfo, bytesNeeded)))
4382 CRYPT_DATA_BLOB *blob;
4383 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4385 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4386 pvStructInfo = *(BYTE **)pvStructInfo;
4387 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4388 blob->cbData = dataLen;
4389 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4390 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
4393 blob->pbData = (BYTE *)pvStructInfo +
4394 sizeof(CRYPT_DATA_BLOB);
4396 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
4404 SetLastError(CRYPT_E_ASN1_BADTAG);
4408 __EXCEPT(page_fault)
4410 SetLastError(STATUS_ACCESS_VIOLATION);
4417 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
4418 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4419 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4423 TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
4424 pDecodePara, pvStructInfo, *pcbStructInfo);
4426 if (pbEncoded[0] == ASN_BITSTRING)
4428 DWORD bytesNeeded, dataLen;
4430 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4432 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4433 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
4435 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
4437 *pcbStructInfo = bytesNeeded;
4438 else if (*pcbStructInfo < bytesNeeded)
4440 *pcbStructInfo = bytesNeeded;
4441 SetLastError(ERROR_MORE_DATA);
4446 CRYPT_BIT_BLOB *blob;
4448 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4449 blob->cbData = dataLen - 1;
4450 blob->cUnusedBits = *(pbEncoded + 1 +
4451 GET_LEN_BYTES(pbEncoded[1]));
4452 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4454 blob->pbData = (BYTE *)pbEncoded + 2 +
4455 GET_LEN_BYTES(pbEncoded[1]);
4459 assert(blob->pbData);
4462 BYTE mask = 0xff << blob->cUnusedBits;
4464 memcpy(blob->pbData, pbEncoded + 2 +
4465 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
4466 blob->pbData[blob->cbData - 1] &= mask;
4474 SetLastError(CRYPT_E_ASN1_BADTAG);
4480 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
4481 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4482 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4486 TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
4487 pDecodePara, pvStructInfo, pcbStructInfo);
4493 if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4494 lpszStructType, pbEncoded, cbEncoded,
4495 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4498 *pcbStructInfo = bytesNeeded;
4499 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4500 pvStructInfo, pcbStructInfo, bytesNeeded)))
4502 CRYPT_BIT_BLOB *blob;
4504 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4505 pvStructInfo = *(BYTE **)pvStructInfo;
4506 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4507 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
4508 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4509 lpszStructType, pbEncoded, cbEncoded,
4510 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4515 __EXCEPT(page_fault)
4517 SetLastError(STATUS_ACCESS_VIOLATION);
4524 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
4525 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4526 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4532 *pcbStructInfo = sizeof(int);
4537 BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
4538 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
4539 DWORD size = sizeof(buf);
4541 blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
4542 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4543 X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
4546 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4547 pvStructInfo, pcbStructInfo, sizeof(int))))
4551 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4552 pvStructInfo = *(BYTE **)pvStructInfo;
4553 if (blob->pbData[blob->cbData - 1] & 0x80)
4555 /* initialize to a negative value to sign-extend */
4560 for (i = 0; i < blob->cbData; i++)
4563 val |= blob->pbData[blob->cbData - i - 1];
4565 memcpy(pvStructInfo, &val, sizeof(int));
4568 else if (GetLastError() == ERROR_MORE_DATA)
4569 SetLastError(CRYPT_E_ASN1_LARGE);
4571 __EXCEPT(page_fault)
4573 SetLastError(STATUS_ACCESS_VIOLATION);
4580 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
4581 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4582 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4586 if (pbEncoded[0] == ASN_INTEGER)
4588 DWORD bytesNeeded, dataLen;
4590 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4592 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4594 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4596 *pcbStructInfo = bytesNeeded;
4597 else if (*pcbStructInfo < bytesNeeded)
4599 *pcbStructInfo = bytesNeeded;
4600 SetLastError(ERROR_MORE_DATA);
4605 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4607 blob->cbData = dataLen;
4608 assert(blob->pbData);
4613 for (i = 0; i < blob->cbData; i++)
4615 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4624 SetLastError(CRYPT_E_ASN1_BADTAG);
4630 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
4631 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4632 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4640 if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4641 lpszStructType, pbEncoded, cbEncoded,
4642 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4645 *pcbStructInfo = bytesNeeded;
4646 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4647 pvStructInfo, pcbStructInfo, bytesNeeded)))
4649 CRYPT_INTEGER_BLOB *blob;
4651 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4652 pvStructInfo = *(BYTE **)pvStructInfo;
4653 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4654 blob->pbData = (BYTE *)pvStructInfo +
4655 sizeof(CRYPT_INTEGER_BLOB);
4656 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4657 lpszStructType, pbEncoded, cbEncoded,
4658 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4663 __EXCEPT(page_fault)
4665 SetLastError(STATUS_ACCESS_VIOLATION);
4672 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
4673 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4674 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4680 if (pbEncoded[0] == ASN_INTEGER)
4682 DWORD bytesNeeded, dataLen;
4683 CRYPT_INTEGER_BLOB *blob;
4685 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4687 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4689 *pcbStructInfo = bytesNeeded;
4690 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4691 pvStructInfo, pcbStructInfo, bytesNeeded)))
4693 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4695 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4696 pvStructInfo = *(BYTE **)pvStructInfo;
4697 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4698 blob->cbData = dataLen;
4699 blob->pbData = (BYTE *)pvStructInfo +
4700 sizeof(CRYPT_INTEGER_BLOB);
4701 /* remove leading zero byte if it exists */
4702 if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
4711 for (i = 0; i < blob->cbData; i++)
4712 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4713 pbEncoded[1] - i - 1);
4720 SetLastError(CRYPT_E_ASN1_BADTAG);
4724 __EXCEPT(page_fault)
4726 SetLastError(STATUS_ACCESS_VIOLATION);
4733 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
4734 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4735 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4741 *pcbStructInfo = sizeof(int);
4746 if (pbEncoded[0] == ASN_ENUMERATED)
4748 unsigned int val = 0, i;
4752 SetLastError(CRYPT_E_ASN1_EOD);
4755 else if (pbEncoded[1] == 0)
4757 SetLastError(CRYPT_E_ASN1_CORRUPT);
4762 /* A little strange looking, but we have to accept a sign byte:
4763 * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff. Also,
4764 * assuming a small length is okay here, it has to be in short
4767 if (pbEncoded[1] > sizeof(unsigned int) + 1)
4769 SetLastError(CRYPT_E_ASN1_LARGE);
4772 for (i = 0; i < pbEncoded[1]; i++)
4775 val |= pbEncoded[2 + i];
4777 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4778 pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
4780 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4781 pvStructInfo = *(BYTE **)pvStructInfo;
4782 memcpy(pvStructInfo, &val, sizeof(unsigned int));
4788 SetLastError(CRYPT_E_ASN1_BADTAG);
4792 __EXCEPT(page_fault)
4794 SetLastError(STATUS_ACCESS_VIOLATION);
4801 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
4804 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
4809 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
4811 if (!isdigit(*(pbEncoded))) \
4813 SetLastError(CRYPT_E_ASN1_CORRUPT); \
4819 (word) += *(pbEncoded)++ - '0'; \
4824 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
4825 SYSTEMTIME *sysTime)
4831 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
4833 WORD hours, minutes = 0;
4834 BYTE sign = *pbEncoded++;
4837 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
4838 if (ret && hours >= 24)
4840 SetLastError(CRYPT_E_ASN1_CORRUPT);
4845 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
4846 if (ret && minutes >= 60)
4848 SetLastError(CRYPT_E_ASN1_CORRUPT);
4856 sysTime->wHour += hours;
4857 sysTime->wMinute += minutes;
4861 if (hours > sysTime->wHour)
4864 sysTime->wHour = 24 - (hours - sysTime->wHour);
4867 sysTime->wHour -= hours;
4868 if (minutes > sysTime->wMinute)
4871 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
4874 sysTime->wMinute -= minutes;
4879 __EXCEPT(page_fault)
4881 SetLastError(STATUS_ACCESS_VIOLATION);
4888 #define MIN_ENCODED_TIME_LENGTH 10
4890 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
4891 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4892 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4898 *pcbStructInfo = sizeof(FILETIME);
4903 if (pbEncoded[0] == ASN_UTCTIME)
4907 SetLastError(CRYPT_E_ASN1_EOD);
4910 else if (pbEncoded[1] > 0x7f)
4912 /* long-form date strings really can't be valid */
4913 SetLastError(CRYPT_E_ASN1_CORRUPT);
4918 SYSTEMTIME sysTime = { 0 };
4919 BYTE len = pbEncoded[1];
4921 if (len < MIN_ENCODED_TIME_LENGTH)
4923 SetLastError(CRYPT_E_ASN1_CORRUPT);
4929 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
4930 if (sysTime.wYear >= 50)
4931 sysTime.wYear += 1900;
4933 sysTime.wYear += 2000;
4934 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
4935 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
4936 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
4937 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
4940 if (len >= 2 && isdigit(*pbEncoded) &&
4941 isdigit(*(pbEncoded + 1)))
4942 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4944 else if (isdigit(*pbEncoded))
4945 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
4948 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
4951 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
4952 pDecodePara, pvStructInfo, pcbStructInfo,
4955 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4956 pvStructInfo = *(BYTE **)pvStructInfo;
4957 ret = SystemTimeToFileTime(&sysTime,
4958 (FILETIME *)pvStructInfo);
4965 SetLastError(CRYPT_E_ASN1_BADTAG);
4969 __EXCEPT(page_fault)
4971 SetLastError(STATUS_ACCESS_VIOLATION);
4978 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
4979 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4980 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4986 *pcbStructInfo = sizeof(FILETIME);
4991 if (pbEncoded[0] == ASN_GENERALTIME)
4995 SetLastError(CRYPT_E_ASN1_EOD);
4998 else if (pbEncoded[1] > 0x7f)
5000 /* long-form date strings really can't be valid */
5001 SetLastError(CRYPT_E_ASN1_CORRUPT);
5006 BYTE len = pbEncoded[1];
5008 if (len < MIN_ENCODED_TIME_LENGTH)
5010 SetLastError(CRYPT_E_ASN1_CORRUPT);
5015 SYSTEMTIME sysTime = { 0 };
5018 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
5019 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
5020 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
5021 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
5024 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5027 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5029 if (ret && len > 0 && (*pbEncoded == '.' ||
5036 /* workaround macro weirdness */
5037 digits = min(len, 3);
5038 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
5039 sysTime.wMilliseconds);
5042 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
5045 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
5046 pDecodePara, pvStructInfo, pcbStructInfo,
5049 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5050 pvStructInfo = *(BYTE **)pvStructInfo;
5051 ret = SystemTimeToFileTime(&sysTime,
5052 (FILETIME *)pvStructInfo);
5059 SetLastError(CRYPT_E_ASN1_BADTAG);
5063 __EXCEPT(page_fault)
5065 SetLastError(STATUS_ACCESS_VIOLATION);
5072 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
5073 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5074 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5080 if (pbEncoded[0] == ASN_UTCTIME)
5081 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
5082 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
5084 else if (pbEncoded[0] == ASN_GENERALTIME)
5085 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
5086 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
5087 pvStructInfo, pcbStructInfo);
5090 SetLastError(CRYPT_E_ASN1_BADTAG);
5094 __EXCEPT(page_fault)
5096 SetLastError(STATUS_ACCESS_VIOLATION);
5103 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
5104 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5105 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5111 if (pbEncoded[0] == ASN_SEQUENCEOF)
5113 DWORD bytesNeeded, dataLen, remainingLen, cValue;
5115 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
5120 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
5121 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
5123 ptr = pbEncoded + 1 + lenBytes;
5124 remainingLen = dataLen;
5125 while (ret && remainingLen)
5129 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5132 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5134 remainingLen -= 1 + nextLenBytes + nextLen;
5135 ptr += 1 + nextLenBytes + nextLen;
5136 bytesNeeded += sizeof(CRYPT_DER_BLOB);
5137 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
5138 bytesNeeded += 1 + nextLenBytes + nextLen;
5144 CRYPT_SEQUENCE_OF_ANY *seq;
5148 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
5149 pvStructInfo, pcbStructInfo, bytesNeeded)))
5151 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5152 pvStructInfo = *(BYTE **)pvStructInfo;
5153 seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
5154 seq->cValue = cValue;
5155 seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
5157 nextPtr = (BYTE *)seq->rgValue +
5158 cValue * sizeof(CRYPT_DER_BLOB);
5159 ptr = pbEncoded + 1 + lenBytes;
5160 remainingLen = dataLen;
5162 while (ret && remainingLen)
5166 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5169 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5171 seq->rgValue[i].cbData = 1 + nextLenBytes +
5173 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
5174 seq->rgValue[i].pbData = (BYTE *)ptr;
5177 seq->rgValue[i].pbData = nextPtr;
5178 memcpy(nextPtr, ptr, 1 + nextLenBytes +
5180 nextPtr += 1 + nextLenBytes + nextLen;
5182 remainingLen -= 1 + nextLenBytes + nextLen;
5183 ptr += 1 + nextLenBytes + nextLen;
5193 SetLastError(CRYPT_E_ASN1_BADTAG);
5197 __EXCEPT(page_fault)
5199 SetLastError(STATUS_ACCESS_VIOLATION);
5206 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
5207 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5208 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5212 CryptDecodeObjectExFunc decodeFunc = NULL;
5214 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
5215 dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded,
5216 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5218 if (!pvStructInfo && !pcbStructInfo)
5220 SetLastError(ERROR_INVALID_PARAMETER);
5223 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
5224 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
5226 SetLastError(ERROR_FILE_NOT_FOUND);
5231 SetLastError(CRYPT_E_ASN1_EOD);
5234 if (cbEncoded > MAX_ENCODED_LEN)
5236 SetLastError(CRYPT_E_ASN1_LARGE);
5240 SetLastError(NOERROR);
5241 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
5242 *(BYTE **)pvStructInfo = NULL;
5243 if (!HIWORD(lpszStructType))
5245 switch (LOWORD(lpszStructType))
5247 case (WORD)X509_CERT:
5248 decodeFunc = CRYPT_AsnDecodeCert;
5250 case (WORD)X509_CERT_TO_BE_SIGNED:
5251 decodeFunc = CRYPT_AsnDecodeCertInfo;
5253 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
5254 decodeFunc = CRYPT_AsnDecodeCRLInfo;
5256 case (WORD)X509_EXTENSIONS:
5257 decodeFunc = CRYPT_AsnDecodeExtensions;
5259 case (WORD)X509_NAME:
5260 decodeFunc = CRYPT_AsnDecodeName;
5262 case (WORD)X509_PUBLIC_KEY_INFO:
5263 decodeFunc = CRYPT_AsnDecodePubKeyInfo;
5265 case (WORD)X509_ALTERNATE_NAME:
5266 decodeFunc = CRYPT_AsnDecodeAltName;
5268 case (WORD)X509_BASIC_CONSTRAINTS2:
5269 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5271 case (WORD)X509_OCTET_STRING:
5272 decodeFunc = CRYPT_AsnDecodeOctets;
5274 case (WORD)X509_BITS:
5275 case (WORD)X509_KEY_USAGE:
5276 decodeFunc = CRYPT_AsnDecodeBits;
5278 case (WORD)X509_INTEGER:
5279 decodeFunc = CRYPT_AsnDecodeInt;
5281 case (WORD)X509_MULTI_BYTE_INTEGER:
5282 decodeFunc = CRYPT_AsnDecodeInteger;
5284 case (WORD)X509_MULTI_BYTE_UINT:
5285 decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
5287 case (WORD)X509_ENUMERATED:
5288 decodeFunc = CRYPT_AsnDecodeEnumerated;
5290 case (WORD)X509_CHOICE_OF_TIME:
5291 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
5293 case (WORD)X509_SEQUENCE_OF_ANY:
5294 decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
5296 case (WORD)PKCS_UTC_TIME:
5297 decodeFunc = CRYPT_AsnDecodeUtcTime;
5300 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
5303 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
5304 decodeFunc = CRYPT_AsnDecodeExtensions;
5305 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
5306 decodeFunc = CRYPT_AsnDecodeUtcTime;
5307 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
5308 decodeFunc = CRYPT_AsnDecodeEnumerated;
5309 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
5310 decodeFunc = CRYPT_AsnDecodeBits;
5311 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
5312 decodeFunc = CRYPT_AsnDecodeOctets;
5313 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
5314 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5315 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
5316 decodeFunc = CRYPT_AsnDecodeAltName;
5317 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
5318 decodeFunc = CRYPT_AsnDecodeAltName;
5319 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
5320 decodeFunc = CRYPT_AsnDecodeAltName;
5321 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
5322 decodeFunc = CRYPT_AsnDecodeAltName;
5323 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
5324 decodeFunc = CRYPT_AsnDecodeAltName;
5326 TRACE("OID %s not found or unimplemented, looking for DLL\n",
5327 debugstr_a(lpszStructType));
5329 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
5330 lpszStructType, "CryptDecodeObjectEx", &lib);
5332 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
5333 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5335 SetLastError(ERROR_FILE_NOT_FOUND);