2 * Copyright 2002 Mike McCormack for CodeWeavers
3 * Copyright 2005 Juan Lang
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2.1 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 * This file implements ASN.1 DER encoding and decoding of a limited set of
20 * types. It isn't a full ASN.1 implementation. Microsoft implements BER
21 * encoding of many of the basic types in msasn1.dll, but that interface is
22 * undocumented, so I implement them here.
25 * "A Layman's Guide to a Subset of ASN.1, BER, and DER", by Burton Kaliski
26 * (available online, look for a PDF copy as the HTML versions tend to have
27 * translation errors.)
29 * RFC3280, http://www.faqs.org/rfcs/rfc3280.html
32 * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
44 #include "wine/debug.h"
45 #include "wine/exception.h"
47 /* This is a bit arbitrary, but to set some limit: */
48 #define MAX_ENCODED_LEN 0x02000000
50 /* a few asn.1 tags we need */
51 #define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
52 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
53 #define ASN_OCTETSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
54 #define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
55 #define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
56 #define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
57 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
58 #define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
59 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
60 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
62 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
64 static const WCHAR szDllName[] = { 'D','l','l',0 };
66 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
68 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
69 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
70 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
71 DWORD, DWORD, void *, DWORD *);
72 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
73 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
75 /* Prototypes for built-in encoders/decoders. They follow the Ex style
76 * prototypes. The dwCertEncodingType and lpszStructType are ignored by the
77 * built-in functions, but the parameters are retained to simplify
78 * CryptEncodeObjectEx/CryptDecodeObjectEx, since they must call functions in
79 * external DLLs that follow these signatures.
80 * FIXME: some built-in functions are suitable to be called directly by
81 * CryptEncodeObjectEx/CryptDecodeObjectEx (they implement exception handling
82 * and memory allocation if requested), others are only suitable to be called
83 * internally. Comment which are which.
85 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
86 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
87 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
88 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
89 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
90 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
91 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
92 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
93 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
94 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
95 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
96 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
97 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
98 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
99 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
100 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
101 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
102 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
103 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
104 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
105 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
106 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
107 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
108 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
109 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
110 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
111 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
113 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
114 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
115 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
116 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
117 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
118 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
119 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
120 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
121 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
122 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
123 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
124 /* Assumes algo->Parameters.pbData is set ahead of time */
125 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
126 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
127 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
128 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
129 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
130 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
131 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
132 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
133 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
134 /* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
135 * member has been initialized, doesn't do exception handling, and doesn't do
138 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(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_AsnDecodeBits(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_AsnDecodeInt(DWORD dwCertEncodingType,
145 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
146 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
147 /* Like CRYPT_AsnDecodeInteger, 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_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
152 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
153 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
155 /* filter for page-fault exceptions */
156 static WINE_EXCEPTION_FILTER(page_fault)
158 if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
159 return EXCEPTION_EXECUTE_HANDLER;
160 return EXCEPTION_CONTINUE_SEARCH;
163 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
166 static const char szEncodingTypeFmt[] =
167 "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
169 char numericOID[7]; /* enough for "#65535" */
173 /* MSDN says the encoding type is a mask, but it isn't treated that way.
174 * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
175 * "EncodingType 2" would be expected if it were a mask. Instead native
176 * stores values in "EncodingType 3".
180 snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
186 /* This is enough: the lengths of the two string parameters are explicitly
187 * counted, and we need up to five additional characters for the encoding
188 * type. These are covered by the "%d", "%s", and "%s" characters in the
189 * format specifier that are removed by sprintf.
191 len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
192 szKey = HeapAlloc(GetProcessHeap(), 0, len);
194 sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
198 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
199 LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
205 TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
206 debugstr_w(pwszDll), pszOverrideFuncName);
208 /* This only registers functions for encoding certs, not messages */
209 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
212 /* Native does nothing pwszDll is NULL */
216 /* I'm not matching MS bug for bug here, because I doubt any app depends on
218 * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
219 * it creates would never be used
220 * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
221 * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
223 if (!pszFuncName || !pszOID)
225 SetLastError(ERROR_INVALID_PARAMETER);
229 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
230 TRACE("Key name is %s\n", debugstr_a(szKey));
235 r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
236 HeapFree(GetProcessHeap(), 0, szKey);
237 if(r != ERROR_SUCCESS)
240 /* write the values */
241 if (pszOverrideFuncName)
242 RegSetValueExA(hKey, "FuncName", 0, REG_SZ, pszOverrideFuncName,
243 lstrlenA(pszOverrideFuncName) + 1);
244 RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
245 (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
251 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
257 TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
259 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
262 if (!pszFuncName || !pszOID)
264 SetLastError(ERROR_INVALID_PARAMETER);
268 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
269 rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
270 HeapFree(GetProcessHeap(), 0, szKey);
273 return rc ? FALSE : TRUE;
276 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
277 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
284 TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
285 debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
288 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
291 if (!pszFuncName || !pszOID || !pwszValueName)
293 SetLastError(ERROR_INVALID_PARAMETER);
297 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
298 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
299 HeapFree(GetProcessHeap(), 0, szKey);
304 rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
305 pbValueData, pcbValueData);
310 return rc ? FALSE : TRUE;
313 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
314 LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
315 const BYTE *pbValueData, DWORD cbValueData)
321 TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
322 debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
325 if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
328 if (!pszFuncName || !pszOID || !pwszValueName)
330 SetLastError(ERROR_INVALID_PARAMETER);
334 szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
335 rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
336 HeapFree(GetProcessHeap(), 0, szKey);
341 rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
347 return rc ? FALSE : TRUE;
350 /* Gets the registered function named szFuncName for dwCertEncodingType and
351 * lpszStructType, or NULL if one could not be found. *lib will be set to the
352 * handle of the module it's in, or NULL if no module was loaded. If the
353 * return value is NULL, *lib will also be NULL, to simplify error handling.
355 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
356 LPCSTR szFuncName, HMODULE *lib)
359 char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
361 const char *funcName;
364 DWORD type, size = 0;
366 TRACE("(%08lx %s %s %p)\n", dwCertEncodingType, debugstr_a(lpszStructType),
367 debugstr_a(szFuncName), lib);
370 r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
371 HeapFree(GetProcessHeap(), 0, szKey);
372 if(r != ERROR_SUCCESS)
375 RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
376 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
378 funcName = HeapAlloc(GetProcessHeap(), 0, size);
379 RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
383 funcName = szFuncName;
384 RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
385 if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
387 LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
389 RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
391 *lib = LoadLibraryW(dllName);
394 ret = GetProcAddress(*lib, funcName);
397 /* Unload the library, the caller doesn't want to unload it
398 * when the return value is NULL.
404 HeapFree(GetProcessHeap(), 0, dllName);
406 if (funcName != szFuncName)
407 HeapFree(GetProcessHeap(), 0, (char *)funcName);
408 TRACE("returning %p\n", ret);
412 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
413 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
417 CryptEncodeObjectFunc pCryptEncodeObject;
419 TRACE("(0x%08lx, %s, %p, %p, %p)\n",
420 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
421 "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
423 if (!pbEncoded && !pcbEncoded)
425 SetLastError(ERROR_INVALID_PARAMETER);
429 /* Try registered DLL first.. */
431 (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
432 lpszStructType, "CryptEncodeObject", &lib);
433 if (pCryptEncodeObject)
435 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
436 pvStructInfo, pbEncoded, pcbEncoded);
441 /* If not, use CryptEncodeObjectEx */
442 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
443 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
448 /* Helper function to check *pcbEncoded, set it to the required size, and
449 * optionally to allocate memory. Assumes pbEncoded is not NULL.
450 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
451 * pointer to the newly allocated memory.
453 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
454 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
459 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
461 if (pEncodePara && pEncodePara->pfnAlloc)
462 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
464 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
465 if (!*(BYTE **)pbEncoded)
468 *pcbEncoded = bytesNeeded;
470 else if (bytesNeeded > *pcbEncoded)
472 *pcbEncoded = bytesNeeded;
473 SetLastError(ERROR_MORE_DATA);
479 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
481 DWORD bytesNeeded, significantBytes = 0;
489 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
490 temp <<= 8, significantBytes--)
492 bytesNeeded = significantBytes + 1;
496 *pcbEncoded = bytesNeeded;
499 if (*pcbEncoded < bytesNeeded)
501 SetLastError(ERROR_MORE_DATA);
505 *pbEncoded = (BYTE)len;
510 *pbEncoded++ = significantBytes | 0x80;
511 for (i = 0; i < significantBytes; i++)
513 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
517 *pcbEncoded = bytesNeeded;
521 struct AsnEncodeSequenceItem
523 const void *pvStructInfo;
524 CryptEncodeObjectExFunc encodeFunc;
525 DWORD size; /* used during encoding, not for your use */
528 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
529 struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
530 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
533 DWORD i, dataLen = 0;
535 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", items, cItem, dwFlags, pEncodePara,
536 pbEncoded, *pcbEncoded);
537 for (i = 0, ret = TRUE; ret && i < cItem; i++)
539 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
540 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
541 NULL, &items[i].size);
542 dataLen += items[i].size;
546 DWORD lenBytes, bytesNeeded;
548 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
549 bytesNeeded = 1 + lenBytes + dataLen;
551 *pcbEncoded = bytesNeeded;
554 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
555 pcbEncoded, bytesNeeded)))
557 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
558 pbEncoded = *(BYTE **)pbEncoded;
559 *pbEncoded++ = ASN_SEQUENCE;
560 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
561 pbEncoded += lenBytes;
562 for (i = 0; ret && i < cItem; i++)
564 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
565 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
566 NULL, pbEncoded, &items[i].size);
567 pbEncoded += items[i].size;
572 TRACE("returning %d (%08lx)\n", ret, GetLastError());
576 struct AsnConstructedItem
579 const void *pvStructInfo;
580 CryptEncodeObjectExFunc encodeFunc;
583 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
584 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
585 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
588 const struct AsnConstructedItem *item =
589 (const struct AsnConstructedItem *)pvStructInfo;
592 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
593 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
595 DWORD dataLen, bytesNeeded;
597 CRYPT_EncodeLen(len, NULL, &dataLen);
598 bytesNeeded = 1 + dataLen + len;
600 *pcbEncoded = bytesNeeded;
601 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
602 pbEncoded, pcbEncoded, bytesNeeded)))
604 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
605 pbEncoded = *(BYTE **)pbEncoded;
606 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
607 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
608 pbEncoded += dataLen;
609 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
610 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
617 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
618 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
619 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
621 const DWORD *ver = (const DWORD *)pvStructInfo;
624 /* CERT_V1 is not encoded */
632 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
634 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
635 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
640 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
641 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
642 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
644 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
649 *pcbEncoded = blob->cbData;
652 else if (*pcbEncoded < blob->cbData)
654 *pcbEncoded = blob->cbData;
655 SetLastError(ERROR_MORE_DATA);
661 memcpy(pbEncoded, blob->pbData, blob->cbData);
662 *pcbEncoded = blob->cbData;
668 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
669 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
670 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
673 /* This has two filetimes in a row, a NotBefore and a NotAfter */
674 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
675 struct AsnEncodeSequenceItem items[] = {
676 { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
677 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
680 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
681 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
686 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
687 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
688 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
691 const CRYPT_ALGORITHM_IDENTIFIER *algo =
692 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
694 struct AsnEncodeSequenceItem items[] = {
695 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
696 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
699 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
700 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
705 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
706 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
707 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
713 const CERT_PUBLIC_KEY_INFO *info =
714 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
715 struct AsnEncodeSequenceItem items[] = {
716 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
717 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
720 TRACE("Encoding public key with OID %s\n",
721 debugstr_a(info->Algorithm.pszObjId));
722 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
723 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
728 SetLastError(STATUS_ACCESS_VIOLATION);
735 /* Like in Windows, this blithely ignores the validity of the passed-in
736 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
737 * decode properly, see CRYPT_AsnDecodeCertInfo.
739 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
740 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
741 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
747 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
748 struct AsnEncodeSequenceItem items[10] = {
749 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
750 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
751 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
752 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
753 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
754 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
755 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
758 struct AsnConstructedItem constructed[3] = { { 0 } };
759 DWORD cItem = 7, cConstructed = 0;
761 if (info->IssuerUniqueId.cbData)
763 constructed[cConstructed].tag = 1;
764 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
765 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
766 items[cItem].pvStructInfo = &constructed[cConstructed];
767 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
771 if (info->SubjectUniqueId.cbData)
773 constructed[cConstructed].tag = 2;
774 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
775 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
776 items[cItem].pvStructInfo = &constructed[cConstructed];
777 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
781 if (info->cExtension)
783 constructed[cConstructed].tag = 3;
784 constructed[cConstructed].pvStructInfo = &info->cExtension;
785 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
786 items[cItem].pvStructInfo = &constructed[cConstructed];
787 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
792 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
793 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
797 SetLastError(STATUS_ACCESS_VIOLATION);
804 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
808 struct AsnEncodeSequenceItem items[3] = {
809 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
815 TRACE("%p, %p, %ld\n", ext, pbEncoded, *pcbEncoded);
819 items[cItem].pvStructInfo = &ext->fCritical;
820 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
823 items[cItem].pvStructInfo = &ext->Value;
824 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
827 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
828 pbEncoded, pcbEncoded);
829 TRACE("returning %d (%08lx)\n", ret, GetLastError());
833 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
834 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
835 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
841 DWORD bytesNeeded, dataLen, lenBytes, i;
842 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
845 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
849 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
853 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
854 bytesNeeded = 1 + lenBytes + dataLen;
856 *pcbEncoded = bytesNeeded;
859 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
860 pcbEncoded, bytesNeeded)))
862 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
863 pbEncoded = *(BYTE **)pbEncoded;
864 *pbEncoded++ = ASN_SEQUENCEOF;
865 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
866 pbEncoded += lenBytes;
867 for (i = 0; i < exts->cExtension; i++)
869 DWORD size = dataLen;
871 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
881 SetLastError(STATUS_ACCESS_VIOLATION);
888 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
889 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
890 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
892 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
893 DWORD bytesNeeded = 0, lenBytes;
898 TRACE("%s\n", debugstr_a(pszObjId));
905 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
907 SetLastError(CRYPT_E_ASN1_ERROR);
911 firstByte = val1 * 40 + val2;
912 ptr = pszObjId + firstPos;
917 /* note I assume each component is at most 32-bits long in base 2 */
918 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
920 if (val1 >= 0x10000000)
922 else if (val1 >= 0x200000)
924 else if (val1 >= 0x4000)
926 else if (val1 >= 0x80)
936 SetLastError(CRYPT_E_ASN1_ERROR);
940 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
944 bytesNeeded += 1 + lenBytes;
947 if (*pcbEncoded < bytesNeeded)
949 SetLastError(ERROR_MORE_DATA);
954 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
955 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
956 pbEncoded += lenBytes;
962 *pbEncoded++ = firstByte;
963 ptr = pszObjId + firstPos;
966 sscanf(ptr, "%d%n", &val, &pos);
968 unsigned char outBytes[5];
971 if (val >= 0x10000000)
973 else if (val >= 0x200000)
975 else if (val >= 0x4000)
977 else if (val >= 0x80)
981 for (i = numBytes; i > 0; i--)
983 outBytes[i - 1] = val & 0x7f;
986 for (i = 0; i < numBytes - 1; i++)
987 *pbEncoded++ = outBytes[i] | 0x80;
988 *pbEncoded++ = outBytes[i];
997 *pcbEncoded = bytesNeeded;
1001 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
1002 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
1005 DWORD bytesNeeded, lenBytes, encodedLen;
1008 switch (value->dwValueType)
1010 case CERT_RDN_NUMERIC_STRING:
1011 tag = ASN_NUMERICSTRING;
1012 encodedLen = value->Value.cbData;
1014 case CERT_RDN_PRINTABLE_STRING:
1015 tag = ASN_PRINTABLESTRING;
1016 encodedLen = value->Value.cbData;
1018 case CERT_RDN_IA5_STRING:
1019 tag = ASN_IA5STRING;
1020 encodedLen = value->Value.cbData;
1022 case CERT_RDN_ANY_TYPE:
1023 /* explicitly disallowed */
1024 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1027 FIXME("String type %ld unimplemented\n", value->dwValueType);
1030 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1031 bytesNeeded = 1 + lenBytes + encodedLen;
1034 if (*pcbEncoded < bytesNeeded)
1036 SetLastError(ERROR_MORE_DATA);
1042 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1043 pbEncoded += lenBytes;
1044 switch (value->dwValueType)
1046 case CERT_RDN_NUMERIC_STRING:
1047 case CERT_RDN_PRINTABLE_STRING:
1048 case CERT_RDN_IA5_STRING:
1049 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
1053 *pcbEncoded = bytesNeeded;
1057 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1058 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
1060 DWORD bytesNeeded = 0, lenBytes, size;
1063 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1064 0, NULL, NULL, &size);
1067 bytesNeeded += size;
1068 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1069 * with dwValueType, so "cast" it to get its encoded size
1071 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1072 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
1075 bytesNeeded += size;
1076 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1077 bytesNeeded += 1 + lenBytes;
1080 if (*pcbEncoded < bytesNeeded)
1082 SetLastError(ERROR_MORE_DATA);
1087 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
1088 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1090 pbEncoded += lenBytes;
1091 size = bytesNeeded - 1 - lenBytes;
1092 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1093 attr->pszObjId, 0, NULL, pbEncoded, &size);
1097 size = bytesNeeded - 1 - lenBytes - size;
1098 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1099 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
1104 *pcbEncoded = bytesNeeded;
1110 static int BLOBComp(const void *l, const void *r)
1112 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
1115 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1116 ret = a->cbData - b->cbData;
1120 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1122 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1123 BYTE *pbEncoded, DWORD *pcbEncoded)
1126 CRYPT_DER_BLOB *blobs = NULL;
1130 DWORD bytesNeeded = 0, lenBytes, i;
1135 blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1136 rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1140 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1142 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1143 NULL, &blobs[i].cbData);
1145 bytesNeeded += blobs[i].cbData;
1149 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1150 bytesNeeded += 1 + lenBytes;
1153 if (*pcbEncoded < bytesNeeded)
1155 SetLastError(ERROR_MORE_DATA);
1160 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1162 blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
1164 if (!blobs[i].pbData)
1167 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1168 &rdn->rgRDNAttr[i], blobs[i].pbData,
1173 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1175 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1176 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1178 pbEncoded += lenBytes;
1179 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1181 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1182 pbEncoded += blobs[i].cbData;
1187 *pcbEncoded = bytesNeeded;
1191 for (i = 0; i < rdn->cRDNAttr; i++)
1192 HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
1195 __EXCEPT(page_fault)
1197 SetLastError(STATUS_ACCESS_VIOLATION);
1201 HeapFree(GetProcessHeap(), 0, blobs);
1205 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1206 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1207 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1213 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1214 DWORD bytesNeeded = 0, lenBytes, size, i;
1216 TRACE("encoding name with %ld RDNs\n", info->cRDN);
1218 for (i = 0; ret && i < info->cRDN; i++)
1220 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1223 bytesNeeded += size;
1225 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1226 bytesNeeded += 1 + lenBytes;
1230 *pcbEncoded = bytesNeeded;
1233 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1234 pbEncoded, pcbEncoded, bytesNeeded)))
1236 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1237 pbEncoded = *(BYTE **)pbEncoded;
1238 *pbEncoded++ = ASN_SEQUENCEOF;
1239 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1241 pbEncoded += lenBytes;
1242 for (i = 0; ret && i < info->cRDN; i++)
1245 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1246 &info->rgRDN[i], pbEncoded, &size);
1250 bytesNeeded -= size;
1257 __EXCEPT(page_fault)
1259 SetLastError(STATUS_ACCESS_VIOLATION);
1266 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1267 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1268 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1270 BOOL val = *(const BOOL *)pvStructInfo, ret;
1279 else if (*pcbEncoded < 3)
1282 SetLastError(ERROR_MORE_DATA);
1288 *pbEncoded++ = ASN_BOOL;
1290 *pbEncoded++ = val ? 0xff : 0;
1293 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1297 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1298 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1299 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1305 const CERT_BASIC_CONSTRAINTS2_INFO *info =
1306 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1307 struct AsnEncodeSequenceItem items[2] = { { 0 } };
1312 items[cItem].pvStructInfo = &info->fCA;
1313 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1316 if (info->fPathLenConstraint)
1318 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1319 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1322 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1323 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1325 __EXCEPT(page_fault)
1327 SetLastError(STATUS_ACCESS_VIOLATION);
1334 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1335 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1336 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1342 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1343 DWORD bytesNeeded, lenBytes;
1345 TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1346 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1348 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1349 bytesNeeded = 1 + lenBytes + blob->cbData;
1352 *pcbEncoded = bytesNeeded;
1357 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1358 pcbEncoded, bytesNeeded)))
1360 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1361 pbEncoded = *(BYTE **)pbEncoded;
1362 *pbEncoded++ = ASN_OCTETSTRING;
1363 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1364 pbEncoded += lenBytes;
1366 memcpy(pbEncoded, blob->pbData, blob->cbData);
1370 __EXCEPT(page_fault)
1372 SetLastError(STATUS_ACCESS_VIOLATION);
1376 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1380 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1381 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1382 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1388 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1389 DWORD bytesNeeded, lenBytes, dataBytes;
1392 /* yep, MS allows cUnusedBits to be >= 8 */
1393 if (!blob->cUnusedBits)
1395 dataBytes = blob->cbData;
1398 else if (blob->cbData * 8 > blob->cUnusedBits)
1400 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1401 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1409 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1410 bytesNeeded = 1 + lenBytes + dataBytes + 1;
1413 *pcbEncoded = bytesNeeded;
1418 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1419 pcbEncoded, bytesNeeded)))
1421 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1422 pbEncoded = *(BYTE **)pbEncoded;
1423 *pbEncoded++ = ASN_BITSTRING;
1424 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1425 pbEncoded += lenBytes;
1426 *pbEncoded++ = unusedBits;
1429 BYTE mask = 0xff << unusedBits;
1433 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1434 pbEncoded += dataBytes - 1;
1436 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1441 __EXCEPT(page_fault)
1443 SetLastError(STATUS_ACCESS_VIOLATION);
1450 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1451 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1452 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1454 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1456 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1457 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1460 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1461 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1462 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1468 DWORD significantBytes, lenBytes;
1469 BYTE padByte = 0, bytesNeeded;
1471 const CRYPT_INTEGER_BLOB *blob =
1472 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1474 significantBytes = blob->cbData;
1475 if (significantBytes)
1477 if (blob->pbData[significantBytes - 1] & 0x80)
1479 /* negative, lop off leading (little-endian) 0xffs */
1480 for (; significantBytes > 0 &&
1481 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1483 if (blob->pbData[significantBytes - 1] < 0x80)
1491 /* positive, lop off leading (little-endian) zeroes */
1492 for (; significantBytes > 0 &&
1493 !blob->pbData[significantBytes - 1]; significantBytes--)
1495 if (significantBytes == 0)
1496 significantBytes = 1;
1497 if (blob->pbData[significantBytes - 1] > 0x7f)
1505 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1507 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1508 bytesNeeded = 1 + lenBytes + significantBytes;
1513 *pcbEncoded = bytesNeeded;
1518 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1519 pcbEncoded, bytesNeeded)))
1521 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1522 pbEncoded = *(BYTE **)pbEncoded;
1523 *pbEncoded++ = ASN_INTEGER;
1526 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1527 pbEncoded += lenBytes;
1528 *pbEncoded++ = padByte;
1532 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1533 pbEncoded += lenBytes;
1535 for (; significantBytes > 0; significantBytes--)
1536 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1540 __EXCEPT(page_fault)
1542 SetLastError(STATUS_ACCESS_VIOLATION);
1549 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1550 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1551 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1557 DWORD significantBytes, lenBytes;
1560 const CRYPT_INTEGER_BLOB *blob =
1561 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1563 significantBytes = blob->cbData;
1564 if (significantBytes)
1566 /* positive, lop off leading (little-endian) zeroes */
1567 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1570 if (significantBytes == 0)
1571 significantBytes = 1;
1572 if (blob->pbData[significantBytes - 1] > 0x7f)
1576 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1578 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1579 bytesNeeded = 1 + lenBytes + significantBytes;
1584 *pcbEncoded = bytesNeeded;
1589 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1590 pcbEncoded, bytesNeeded)))
1592 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1593 pbEncoded = *(BYTE **)pbEncoded;
1594 *pbEncoded++ = ASN_INTEGER;
1597 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1598 pbEncoded += lenBytes;
1603 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1604 pbEncoded += lenBytes;
1606 for (; significantBytes > 0; significantBytes--)
1607 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1611 __EXCEPT(page_fault)
1613 SetLastError(STATUS_ACCESS_VIOLATION);
1620 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
1621 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1622 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1624 CRYPT_INTEGER_BLOB blob;
1627 /* Encode as an unsigned integer, then change the tag to enumerated */
1628 blob.cbData = sizeof(DWORD);
1629 blob.pbData = (BYTE *)pvStructInfo;
1630 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
1631 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1632 if (ret && pbEncoded)
1634 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1635 pbEncoded = *(BYTE **)pbEncoded;
1636 pbEncoded[0] = ASN_ENUMERATED;
1641 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
1642 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1643 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1650 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
1651 * temporary buffer because the output buffer is not NULL-terminated.
1654 static const DWORD bytesNeeded = sizeof(buf) - 1;
1658 *pcbEncoded = bytesNeeded;
1663 /* Sanity check the year, this is a two-digit year format */
1664 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1666 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
1668 SetLastError(CRYPT_E_BAD_ENCODE);
1673 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1674 pbEncoded, pcbEncoded, bytesNeeded)))
1676 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1677 pbEncoded = *(BYTE **)pbEncoded;
1678 buf[0] = ASN_UTCTIME;
1679 buf[1] = bytesNeeded - 2;
1680 snprintf(buf + 2, sizeof(buf) - 2,
1681 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
1682 sysTime.wYear - 2000 : sysTime.wYear - 1900,
1683 sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1684 sysTime.wMinute, sysTime.wSecond);
1685 memcpy(pbEncoded, buf, bytesNeeded);
1690 __EXCEPT(page_fault)
1692 SetLastError(STATUS_ACCESS_VIOLATION);
1699 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
1700 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1701 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1708 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
1709 * temporary buffer because the output buffer is not NULL-terminated.
1712 static const DWORD bytesNeeded = sizeof(buf) - 1;
1716 *pcbEncoded = bytesNeeded;
1721 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1724 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1725 pcbEncoded, bytesNeeded);
1728 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1729 pbEncoded = *(BYTE **)pbEncoded;
1730 buf[0] = ASN_GENERALTIME;
1731 buf[1] = bytesNeeded - 2;
1732 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
1733 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1734 sysTime.wMinute, sysTime.wSecond);
1735 memcpy(pbEncoded, buf, bytesNeeded);
1739 __EXCEPT(page_fault)
1741 SetLastError(STATUS_ACCESS_VIOLATION);
1748 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
1749 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1750 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1758 /* Check the year, if it's in the UTCTime range call that encode func */
1759 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1761 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
1762 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
1763 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1765 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
1766 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1769 __EXCEPT(page_fault)
1771 SetLastError(STATUS_ACCESS_VIOLATION);
1778 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
1779 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1780 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1786 DWORD bytesNeeded, dataLen, lenBytes, i;
1787 const CRYPT_SEQUENCE_OF_ANY *seq =
1788 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
1790 for (i = 0, dataLen = 0; i < seq->cValue; i++)
1791 dataLen += seq->rgValue[i].cbData;
1792 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1793 bytesNeeded = 1 + lenBytes + dataLen;
1796 *pcbEncoded = bytesNeeded;
1801 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1802 pcbEncoded, bytesNeeded)))
1804 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1805 pbEncoded = *(BYTE **)pbEncoded;
1806 *pbEncoded++ = ASN_SEQUENCEOF;
1807 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1808 pbEncoded += lenBytes;
1809 for (i = 0; i < seq->cValue; i++)
1811 memcpy(pbEncoded, seq->rgValue[i].pbData,
1812 seq->rgValue[i].cbData);
1813 pbEncoded += seq->rgValue[i].cbData;
1818 __EXCEPT(page_fault)
1820 SetLastError(STATUS_ACCESS_VIOLATION);
1827 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1828 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
1829 void *pvEncoded, DWORD *pcbEncoded)
1833 CryptEncodeObjectExFunc encodeFunc = NULL;
1835 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n",
1836 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1837 "(integer value)", pvStructInfo, dwFlags, pEncodePara, pvEncoded,
1840 if (!pvEncoded && !pcbEncoded)
1842 SetLastError(ERROR_INVALID_PARAMETER);
1845 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
1846 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
1848 SetLastError(ERROR_FILE_NOT_FOUND);
1852 SetLastError(NOERROR);
1853 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
1854 *(BYTE **)pvEncoded = NULL;
1855 if (!HIWORD(lpszStructType))
1857 switch (LOWORD(lpszStructType))
1859 case (WORD)X509_CERT_TO_BE_SIGNED:
1860 encodeFunc = CRYPT_AsnEncodeCertInfo;
1862 case (WORD)X509_EXTENSIONS:
1863 encodeFunc = CRYPT_AsnEncodeExtensions;
1865 case (WORD)X509_NAME:
1866 encodeFunc = CRYPT_AsnEncodeName;
1868 case (WORD)X509_PUBLIC_KEY_INFO:
1869 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
1871 case (WORD)X509_BASIC_CONSTRAINTS2:
1872 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
1874 case (WORD)X509_OCTET_STRING:
1875 encodeFunc = CRYPT_AsnEncodeOctets;
1877 case (WORD)X509_BITS:
1878 case (WORD)X509_KEY_USAGE:
1879 encodeFunc = CRYPT_AsnEncodeBits;
1881 case (WORD)X509_INTEGER:
1882 encodeFunc = CRYPT_AsnEncodeInt;
1884 case (WORD)X509_MULTI_BYTE_INTEGER:
1885 encodeFunc = CRYPT_AsnEncodeInteger;
1887 case (WORD)X509_MULTI_BYTE_UINT:
1888 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
1890 case (WORD)X509_ENUMERATED:
1891 encodeFunc = CRYPT_AsnEncodeEnumerated;
1893 case (WORD)X509_CHOICE_OF_TIME:
1894 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
1896 case (WORD)X509_SEQUENCE_OF_ANY:
1897 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
1899 case (WORD)PKCS_UTC_TIME:
1900 encodeFunc = CRYPT_AsnEncodeUtcTime;
1903 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1906 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
1907 encodeFunc = CRYPT_AsnEncodeExtensions;
1908 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1909 encodeFunc = CRYPT_AsnEncodeUtcTime;
1910 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
1911 encodeFunc = CRYPT_AsnEncodeEnumerated;
1912 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
1913 encodeFunc = CRYPT_AsnEncodeBits;
1914 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
1915 encodeFunc = CRYPT_AsnEncodeOctets;
1916 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
1917 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
1919 TRACE("OID %s not found or unimplemented, looking for DLL\n",
1920 debugstr_a(lpszStructType));
1922 encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1923 lpszStructType, "CryptEncodeObjectEx", &lib);
1925 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
1926 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
1928 SetLastError(ERROR_FILE_NOT_FOUND);
1934 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1935 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
1936 DWORD *pcbStructInfo)
1940 CryptDecodeObjectFunc pCryptDecodeObject;
1942 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
1943 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1944 "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1947 if (!pvStructInfo && !pcbStructInfo)
1949 SetLastError(ERROR_INVALID_PARAMETER);
1953 /* Try registered DLL first.. */
1954 pCryptDecodeObject =
1955 (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
1956 lpszStructType, "CryptDecodeObject", &lib);
1957 if (pCryptDecodeObject)
1959 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
1960 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1965 /* If not, use CryptDecodeObjectEx */
1966 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
1967 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
1972 /* Gets the number of length bytes from the given (leading) length byte */
1973 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
1975 /* Helper function to get the encoded length of the data starting at pbEncoded,
1976 * where pbEncoded[0] is the tag. If the data are too short to contain a
1977 * length or if the length is too large for cbEncoded, sets an appropriate
1978 * error code and returns FALSE.
1980 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
1987 SetLastError(CRYPT_E_ASN1_CORRUPT);
1990 else if (pbEncoded[1] <= 0x7f)
1992 *len = pbEncoded[1];
1997 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
1999 if (lenLen > sizeof(DWORD) + 1)
2001 SetLastError(CRYPT_E_ASN1_LARGE);
2004 else if (lenLen + 2 > cbEncoded)
2006 SetLastError(CRYPT_E_ASN1_CORRUPT);
2017 out |= *pbEncoded++;
2019 if (out + lenLen + 1 > cbEncoded)
2021 SetLastError(CRYPT_E_ASN1_EOD);
2034 /* Helper function to check *pcbStructInfo, set it to the required size, and
2035 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
2036 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
2037 * pointer to the newly allocated memory.
2039 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
2040 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2045 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2047 if (pDecodePara && pDecodePara->pfnAlloc)
2048 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
2050 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
2051 if (!*(BYTE **)pvStructInfo)
2054 *pcbStructInfo = bytesNeeded;
2056 else if (*pcbStructInfo < bytesNeeded)
2058 *pcbStructInfo = bytesNeeded;
2059 SetLastError(ERROR_MORE_DATA);
2065 /* A few of the members need explanation:
2067 * A sequence is decoded into a struct. The offset member is the
2068 * offset of this item within that struct.
2070 * The minimum amount of space occupied after decoding. You must set this.
2071 * hasPointer, pointerOffset, minSize:
2072 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
2073 * the offset within the (outer) struct of the data pointer (or to the
2074 * first data pointer, if more than one exist).
2076 * Used by CRYPT_AsnDecodeSequence, not for your use.
2078 struct AsnDecodeSequenceItem
2081 CryptDecodeObjectExFunc decodeFunc;
2085 DWORD pointerOffset;
2089 /* This decodes an arbitrary sequence into a contiguous block of memory
2090 * (basically, a struct.) Each element being decoded is described by a struct
2091 * AsnDecodeSequenceItem, see above.
2092 * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
2093 * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
2094 * FIXME: use to decode more sequences.
2096 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
2097 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2098 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
2099 void *pvStructInfo, DWORD *pcbStructInfo)
2103 if (pbEncoded[0] == ASN_SEQUENCE)
2107 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2109 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2110 DWORD i, bytesNeeded = 0, minSize = 0;
2113 ptr = pbEncoded + 1 + lenBytes;
2114 for (i = 0; ret && i < cItem; i++)
2118 minSize += items[i].minSize;
2119 if (cbEncoded - (ptr - pbEncoded) != 0)
2121 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2124 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2126 ret = items[i].decodeFunc(dwCertEncodingType, NULL,
2127 ptr, 1 + nextItemLenBytes + nextItemLen,
2128 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
2132 /* FIXME: need to ensure alignment for sizes greater
2133 * than the minimum size
2135 bytesNeeded += items[i].size;
2136 ptr += 1 + nextItemLenBytes + nextItemLen;
2138 else if (items[i].optional &&
2139 GetLastError() == CRYPT_E_ASN1_BADTAG)
2141 bytesNeeded += items[i].minSize;
2142 SetLastError(NOERROR);
2147 else if (items[i].optional)
2148 bytesNeeded += items[i].minSize;
2151 SetLastError(CRYPT_E_ASN1_CORRUPT);
2158 *pcbStructInfo = bytesNeeded;
2159 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2160 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2164 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2165 pvStructInfo = *(BYTE **)pvStructInfo;
2166 nextData = (BYTE *)pvStructInfo + minSize;
2167 memset(pvStructInfo, 0, minSize);
2168 ptr = pbEncoded + 1 + lenBytes;
2169 for (i = 0; ret && i < cItem; i++)
2171 if (cbEncoded - (ptr - pbEncoded) != 0)
2174 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2176 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2178 if (items[i].hasPointer)
2179 *(BYTE **)((BYTE *)pvStructInfo +
2180 items[i].pointerOffset) = nextData;
2181 ret = items[i].decodeFunc(dwCertEncodingType, NULL,
2182 ptr, 1 + nextItemLenBytes + nextItemLen,
2183 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2184 (BYTE *)pvStructInfo + items[i].offset,
2188 if (items[i].hasPointer &&
2189 items[i].size > items[i].minSize)
2190 nextData += items[i].size -
2192 ptr += 1 + nextItemLenBytes + nextItemLen;
2194 else if (items[i].optional &&
2195 GetLastError() == CRYPT_E_ASN1_BADTAG)
2197 SetLastError(NOERROR);
2201 else if (!items[i].optional)
2203 SetLastError(CRYPT_E_ASN1_CORRUPT);
2213 SetLastError(CRYPT_E_ASN1_BADTAG);
2219 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
2220 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2221 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2225 if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR))
2229 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2231 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2233 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
2234 pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
2235 pvStructInfo, pcbStructInfo);
2240 SetLastError(CRYPT_E_ASN1_BADTAG);
2246 /* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
2247 * pvStructInfo. The BLOB must be non-empty, otherwise the last error is set
2248 * to CRYPT_E_ASN1_CORRUPT.
2249 * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
2252 static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
2253 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2254 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2259 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2261 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2262 DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
2264 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2265 bytesNeeded += 1 + lenBytes + dataLen;
2268 *pcbStructInfo = bytesNeeded;
2269 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2270 pvStructInfo, pcbStructInfo, bytesNeeded)))
2272 CRYPT_DER_BLOB *blob = (CRYPT_DER_BLOB *)pvStructInfo;
2274 blob->cbData = 1 + lenBytes + dataLen;
2277 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2278 blob->pbData = (BYTE *)pbEncoded;
2281 assert(blob->pbData);
2282 memcpy(blob->pbData, pbEncoded, blob->cbData);
2287 SetLastError(CRYPT_E_ASN1_CORRUPT);
2295 static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
2296 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2297 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2301 struct AsnDecodeSequenceItem items[] = {
2302 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
2303 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2304 { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
2305 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2308 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2309 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2310 pDecodePara, pvStructInfo, pcbStructInfo);
2314 static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
2315 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2316 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2322 struct AsnDecodeSequenceItem items[] = {
2323 { offsetof(CERT_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
2324 sizeof(DWORD), TRUE, FALSE, 0, 0 },
2325 { offsetof(CERT_INFO, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2326 sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2327 SerialNumber.pbData), 0 },
2328 { offsetof(CERT_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
2329 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CERT_INFO,
2330 SignatureAlgorithm.Parameters.pbData), 0 },
2331 { offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
2332 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2334 { offsetof(CERT_INFO, NotBefore), CRYPT_AsnDecodeValidity,
2335 sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, FALSE, 0 },
2336 { offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
2337 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2339 { offsetof(CERT_INFO, SubjectPublicKeyInfo), CRYPT_AsnDecodePubKeyInfo,
2340 sizeof(CERT_PUBLIC_KEY_INFO), FALSE, TRUE, offsetof(CERT_INFO,
2341 SubjectPublicKeyInfo.Algorithm.Parameters.pbData) },
2342 { offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal,
2343 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2344 IssuerUniqueId.pbData) },
2345 { offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal,
2346 sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2347 SubjectUniqueId.pbData) },
2348 { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeExtensions,
2349 sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CERT_INFO,
2353 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2354 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2355 pDecodePara, pvStructInfo, pcbStructInfo);
2357 __EXCEPT(page_fault)
2359 SetLastError(STATUS_ACCESS_VIOLATION);
2366 /* Warning: assumes ext->Value.pbData is set ahead of time! */
2367 static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
2368 DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
2372 if (pbEncoded[0] == ASN_SEQUENCE)
2374 DWORD dataLen, bytesNeeded;
2376 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2378 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]), oidLenBytes = 0;
2380 bytesNeeded = sizeof(CERT_EXTENSION);
2383 const BYTE *ptr = pbEncoded + 1 + lenBytes;
2384 DWORD encodedOidLen, oidLen;
2386 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2388 oidLenBytes = GET_LEN_BYTES(ptr[1]);
2389 ret = CRYPT_AsnDecodeOid(ptr, cbEncoded - (ptr - pbEncoded),
2390 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &oidLen);
2393 bytesNeeded += oidLen;
2394 ptr += 1 + encodedOidLen + oidLenBytes;
2395 if (*ptr == ASN_BOOL)
2397 ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
2398 X509_OCTET_STRING, ptr, cbEncoded - (ptr - pbEncoded),
2399 0, NULL, NULL, &dataLen);
2400 bytesNeeded += dataLen;
2404 *pcbExt = bytesNeeded;
2405 else if (*pcbExt < bytesNeeded)
2407 SetLastError(ERROR_MORE_DATA);
2412 ptr = pbEncoded + 2 + lenBytes + encodedOidLen +
2414 if (*ptr == ASN_BOOL)
2416 DWORD size = sizeof(BOOL);
2418 CRYPT_AsnDecodeBool(X509_ASN_ENCODING, NULL,
2419 ptr, cbEncoded - (ptr - pbEncoded),
2420 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2421 &ext->fCritical, &size);
2425 ext->fCritical = FALSE;
2426 ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
2427 X509_OCTET_STRING, ptr,
2428 cbEncoded - (ptr - pbEncoded),
2429 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2430 &ext->Value, &dataLen);
2433 ext->pszObjId = ext->Value.pbData +
2435 ptr = pbEncoded + 1 + lenBytes;
2436 ret = CRYPT_AsnDecodeOid(ptr,
2437 cbEncoded - (ptr - pbEncoded),
2438 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
2439 ext->pszObjId, &oidLen);
2447 SetLastError(CRYPT_E_ASN1_EOD);
2454 SetLastError(CRYPT_E_ASN1_BADTAG);
2460 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
2461 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2462 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2468 if (pbEncoded[0] == ASN_SEQUENCEOF)
2470 DWORD dataLen, bytesNeeded;
2472 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2474 DWORD cExtension = 0;
2475 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2477 bytesNeeded = sizeof(CERT_EXTENSIONS);
2483 for (ptr = pbEncoded + 1 + lenBytes; ret &&
2484 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2486 ret = CRYPT_AsnDecodeExtension(ptr,
2487 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
2493 bytesNeeded += size;
2494 ret = CRYPT_GetLen(ptr,
2495 cbEncoded - (ptr - pbEncoded), &nextLen);
2497 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2504 *pcbStructInfo = bytesNeeded;
2505 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2506 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2511 CERT_EXTENSIONS *exts;
2513 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2514 pvStructInfo = *(BYTE **)pvStructInfo;
2515 *pcbStructInfo = bytesNeeded;
2516 exts = (CERT_EXTENSIONS *)pvStructInfo;
2517 exts->cExtension = cExtension;
2518 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
2519 sizeof(CERT_EXTENSIONS));
2520 nextData = (BYTE *)exts->rgExtension +
2521 exts->cExtension * sizeof(CERT_EXTENSION);
2522 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
2523 i < cExtension && ptr - pbEncoded - 1 - lenBytes <
2526 exts->rgExtension[i].Value.pbData = nextData;
2528 ret = CRYPT_AsnDecodeExtension(ptr,
2529 cbEncoded - (ptr - pbEncoded), dwFlags,
2530 &exts->rgExtension[i], &size);
2535 bytesNeeded -= size;
2536 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
2537 * data may not have been copied.
2539 if (exts->rgExtension[i].Value.pbData ==
2542 exts->rgExtension[i].Value.cbData;
2543 /* Ugly: the OID, if copied, is stored in
2544 * memory after the value, so increment by its
2545 * string length if it's set and points here.
2547 if ((const BYTE *)exts->rgExtension[i].pszObjId
2550 exts->rgExtension[i].pszObjId) + 1;
2551 ret = CRYPT_GetLen(ptr,
2552 cbEncoded - (ptr - pbEncoded), &nextLen);
2554 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2563 SetLastError(CRYPT_E_ASN1_BADTAG);
2567 __EXCEPT(page_fault)
2569 SetLastError(STATUS_ACCESS_VIOLATION);
2576 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
2577 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
2578 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
2584 if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
2588 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2590 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2595 /* The largest possible string for the first two components
2596 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
2601 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
2602 pbEncoded[1 + lenBytes] / 40,
2603 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
2605 bytesNeeded = strlen(firstTwo) + 1;
2606 for (ptr = pbEncoded + 2 + lenBytes; ret &&
2607 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2609 /* large enough for ".4000000" */
2613 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
2620 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
2623 SetLastError(CRYPT_E_ASN1_CORRUPT);
2630 snprintf(str, sizeof(str), ".%d", val);
2631 bytesNeeded += strlen(str);
2635 *pcbObjId = bytesNeeded;
2636 else if (*pcbObjId < bytesNeeded)
2638 *pcbObjId = bytesNeeded;
2639 SetLastError(ERROR_MORE_DATA);
2644 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
2645 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
2647 pszObjId += strlen(pszObjId);
2648 for (ptr = pbEncoded + 2 + lenBytes; ret &&
2649 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2653 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
2662 sprintf(pszObjId, ".%d", val);
2663 pszObjId += strlen(pszObjId);
2669 *pcbObjId = bytesNeeded;
2674 SetLastError(CRYPT_E_ASN1_BADTAG);
2678 __EXCEPT(page_fault)
2680 SetLastError(STATUS_ACCESS_VIOLATION);
2687 /* Warning: this assumes the address of value->Value.pbData is already set, in
2688 * order to avoid overwriting memory. (In some cases, it may change it, if it
2689 * doesn't copy anything to memory.) Be sure to set it correctly!
2691 static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
2692 DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD *pcbValue)
2700 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2702 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2704 switch (pbEncoded[0])
2706 case ASN_NUMERICSTRING:
2707 case ASN_PRINTABLESTRING:
2711 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
2712 SetLastError(OSS_UNIMPLEMENTED);
2717 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
2719 switch (pbEncoded[0])
2721 case ASN_NUMERICSTRING:
2722 case ASN_PRINTABLESTRING:
2724 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2725 bytesNeeded += dataLen;
2729 *pcbValue = bytesNeeded;
2730 else if (*pcbValue < bytesNeeded)
2732 *pcbValue = bytesNeeded;
2733 SetLastError(ERROR_MORE_DATA);
2738 *pcbValue = bytesNeeded;
2739 switch (pbEncoded[0])
2741 case ASN_NUMERICSTRING:
2742 value->dwValueType = CERT_RDN_NUMERIC_STRING;
2744 case ASN_PRINTABLESTRING:
2745 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
2748 value->dwValueType = CERT_RDN_IA5_STRING;
2753 switch (pbEncoded[0])
2755 case ASN_NUMERICSTRING:
2756 case ASN_PRINTABLESTRING:
2758 value->Value.cbData = dataLen;
2759 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2760 value->Value.pbData = (BYTE *)pbEncoded + 1 +
2764 assert(value->Value.pbData);
2765 memcpy(value->Value.pbData,
2766 pbEncoded + 1 + lenBytes, dataLen);
2773 value->Value.cbData = 0;
2774 value->Value.pbData = NULL;
2780 __EXCEPT(page_fault)
2782 SetLastError(STATUS_ACCESS_VIOLATION);
2789 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded,
2790 DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD *pcbAttr)
2796 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCE))
2798 DWORD bytesNeeded, dataLen, size;
2801 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2803 /* The data length must be at least 4, two for the tag and
2804 * length for the OID, and two for the string (assuming both
2805 * have short-form lengths.)
2809 SetLastError(CRYPT_E_ASN1_EOD);
2814 bytesNeeded = sizeof(CERT_RDN_ATTR);
2815 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2816 ret = CRYPT_AsnDecodeOid(pbEncoded + 1 + lenBytes,
2817 cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
2820 /* ugly: need to know the size of the next element of
2821 * the sequence, so get it directly
2823 DWORD objIdOfset = 1 + lenBytes, objIdLen,
2824 nameValueOffset = 0;
2826 ret = CRYPT_GetLen(pbEncoded + objIdOfset,
2827 cbEncoded - objIdOfset, &objIdLen);
2828 bytesNeeded += size;
2829 /* hack: like encoding, this takes advantage of the
2830 * fact that the rest of the structure is identical to
2831 * a CERT_NAME_VALUE.
2835 nameValueOffset = objIdOfset + objIdLen + 1 +
2836 GET_LEN_BYTES(pbEncoded[objIdOfset]);
2837 ret = CRYPT_AsnDecodeNameValue(
2838 pbEncoded + nameValueOffset,
2839 cbEncoded - nameValueOffset, dwFlags, NULL, &size);
2843 bytesNeeded += size;
2845 *pcbAttr = bytesNeeded;
2846 else if (*pcbAttr < bytesNeeded)
2848 *pcbAttr = bytesNeeded;
2849 SetLastError(ERROR_MORE_DATA);
2854 BYTE *originalData = attr->Value.pbData;
2856 *pcbAttr = bytesNeeded;
2857 /* strange: decode the value first, because it
2858 * has a counted size, and we can store the OID
2859 * after it. Keep track of the original data
2860 * pointer, we'll need to know whether it was
2864 ret = CRYPT_AsnDecodeNameValue(
2865 pbEncoded + nameValueOffset,
2866 cbEncoded - nameValueOffset, dwFlags,
2867 (CERT_NAME_VALUE *)&attr->dwValueType, &size);
2872 /* if the data were copied to the
2873 * original location, the OID goes
2874 * after. Otherwise it goes in the
2875 * spot originally reserved for the
2878 if (attr->Value.pbData == originalData)
2880 (LPSTR)(attr->Value.pbData +
2881 attr->Value.cbData);
2883 attr->pszObjId = originalData;
2884 size = bytesNeeded - size;
2885 ret = CRYPT_AsnDecodeOid(
2886 pbEncoded + objIdOfset,
2887 cbEncoded - objIdOfset,
2888 dwFlags, attr->pszObjId, &size);
2891 attr->pszObjId = NULL;
2901 SetLastError(CRYPT_E_ASN1_BADTAG);
2905 __EXCEPT(page_fault)
2907 SetLastError(STATUS_ACCESS_VIOLATION);
2914 static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
2915 DWORD dwFlags, CERT_RDN *rdn, DWORD *pcbRdn)
2921 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SETOF))
2925 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2927 DWORD bytesNeeded, cRDNAttr = 0;
2928 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2930 bytesNeeded = sizeof(CERT_RDN);
2936 for (ptr = pbEncoded + 1 + lenBytes; ret &&
2937 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2939 ret = CRYPT_AsnDecodeRdnAttr(ptr,
2940 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
2946 bytesNeeded += size;
2947 ret = CRYPT_GetLen(ptr,
2948 cbEncoded - (ptr - pbEncoded), &nextLen);
2950 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2957 *pcbRdn = bytesNeeded;
2958 else if (*pcbRdn < bytesNeeded)
2960 *pcbRdn = bytesNeeded;
2961 SetLastError(ERROR_MORE_DATA);
2970 *pcbRdn = bytesNeeded;
2971 rdn->cRDNAttr = cRDNAttr;
2972 rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn +
2974 nextData = (BYTE *)rdn->rgRDNAttr +
2975 rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
2976 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
2977 i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
2980 rdn->rgRDNAttr[i].Value.pbData = nextData;
2982 ret = CRYPT_AsnDecodeRdnAttr(ptr,
2983 cbEncoded - (ptr - pbEncoded), dwFlags,
2984 &rdn->rgRDNAttr[i], &size);
2989 bytesNeeded -= size;
2990 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
2991 * data may not have been copied.
2993 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
2995 rdn->rgRDNAttr[i].Value.cbData;
2996 /* Ugly: the OID, if copied, is stored in
2997 * memory after the value, so increment by its
2998 * string length if it's set and points here.
3000 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId
3003 rdn->rgRDNAttr[i].pszObjId) + 1;
3004 ret = CRYPT_GetLen(ptr,
3005 cbEncoded - (ptr - pbEncoded), &nextLen);
3007 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3016 SetLastError(CRYPT_E_ASN1_BADTAG);
3020 __EXCEPT(page_fault)
3022 SetLastError(STATUS_ACCESS_VIOLATION);
3029 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
3030 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3031 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3037 if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
3041 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3043 DWORD bytesNeeded, cRDN = 0;
3044 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3046 bytesNeeded = sizeof(CERT_NAME_INFO);
3051 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3052 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3056 ret = CRYPT_AsnDecodeRdn(ptr,
3057 cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3063 bytesNeeded += size;
3064 ret = CRYPT_GetLen(ptr,
3065 cbEncoded - (ptr - pbEncoded), &nextLen);
3067 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3074 *pcbStructInfo = bytesNeeded;
3075 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3076 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3078 CERT_NAME_INFO *info;
3080 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3081 pvStructInfo = *(BYTE **)pvStructInfo;
3082 info = (CERT_NAME_INFO *)pvStructInfo;
3084 if (info->cRDN == 0)
3092 info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
3093 sizeof(CERT_NAME_INFO));
3094 nextData = (BYTE *)info->rgRDN +
3095 info->cRDN * sizeof(CERT_RDN);
3096 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3097 i < cRDN && ptr - pbEncoded - 1 - lenBytes <
3100 info->rgRDN[i].rgRDNAttr =
3101 (CERT_RDN_ATTR *)nextData;
3103 ret = CRYPT_AsnDecodeRdn(ptr,
3104 cbEncoded - (ptr - pbEncoded), dwFlags,
3105 &info->rgRDN[i], &size);
3111 bytesNeeded -= size;
3112 ret = CRYPT_GetLen(ptr,
3113 cbEncoded - (ptr - pbEncoded), &nextLen);
3115 ptr += nextLen + 1 +
3116 GET_LEN_BYTES(ptr[1]);
3126 SetLastError(CRYPT_E_ASN1_BADTAG);
3130 __EXCEPT(page_fault)
3132 SetLastError(STATUS_ACCESS_VIOLATION);
3139 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
3140 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3141 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3143 CRYPT_ALGORITHM_IDENTIFIER *algo =
3144 (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
3147 if (pbEncoded[0] == ASN_SEQUENCE)
3149 DWORD dataLen, bytesNeeded;
3151 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3153 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3155 bytesNeeded = sizeof(CRYPT_ALGORITHM_IDENTIFIER);
3158 const BYTE *ptr = pbEncoded + 1 + lenBytes;
3160 DWORD encodedOidLen, oidLen;
3162 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
3164 oidLenBytes = GET_LEN_BYTES(ptr[1]);
3165 ret = CRYPT_AsnDecodeOid(ptr, cbEncoded - (ptr - pbEncoded),
3166 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &oidLen);
3169 bytesNeeded += oidLen;
3170 ptr += 1 + encodedOidLen + oidLenBytes;
3171 /* The remaining bytes are just copied as-is, no decoding
3174 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3175 bytesNeeded += cbEncoded - (ptr - pbEncoded);
3177 *pcbStructInfo = bytesNeeded;
3178 else if (*pcbStructInfo < bytesNeeded)
3180 SetLastError(ERROR_MORE_DATA);
3185 /* Get and sanity-check parameter length first */
3186 if (dataLen - 1 - oidLenBytes - encodedOidLen != 0)
3190 if ((ret = CRYPT_GetLen(ptr, cbEncoded -
3191 (ptr - pbEncoded), ¶msLen)))
3193 BYTE paramsLenBytes = GET_LEN_BYTES(ptr[1]);
3195 if (paramsLen != dataLen - encodedOidLen - 1 -
3196 oidLenBytes - 1 - paramsLenBytes)
3198 SetLastError(CRYPT_E_ASN1_CORRUPT);
3205 *pcbStructInfo = bytesNeeded;
3206 algo->Parameters.cbData = dataLen - 1 -
3207 oidLenBytes - encodedOidLen;
3208 if (algo->Parameters.cbData)
3210 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3212 memcpy(algo->Parameters.pbData, ptr,
3213 algo->Parameters.cbData);
3214 algo->pszObjId = algo->Parameters.pbData +
3215 algo->Parameters.cbData;
3219 algo->Parameters.pbData = (BYTE *)ptr;
3220 algo->pszObjId = algo->Parameters.pbData;
3224 algo->pszObjId = algo->Parameters.pbData;
3225 ptr = pbEncoded + 1 + lenBytes;
3226 ret = CRYPT_AsnDecodeOid(ptr,
3227 cbEncoded - (ptr - pbEncoded),
3228 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
3229 algo->pszObjId, &oidLen);
3236 SetLastError(CRYPT_E_ASN1_EOD);
3243 SetLastError(CRYPT_E_ASN1_BADTAG);
3249 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
3250 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3251 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3257 struct AsnDecodeSequenceItem items[] = {
3258 { offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
3259 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3260 FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO,
3261 Algorithm.Parameters.pbData) },
3262 { offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
3263 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
3264 offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) },
3267 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3268 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3269 pDecodePara, pvStructInfo, pcbStructInfo);
3271 __EXCEPT(page_fault)
3273 SetLastError(STATUS_ACCESS_VIOLATION);
3280 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
3281 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3282 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3288 SetLastError(CRYPT_E_ASN1_CORRUPT);
3291 if (pbEncoded[0] != ASN_BOOL)
3293 SetLastError(CRYPT_E_ASN1_BADTAG);
3296 if (GET_LEN_BYTES(pbEncoded[1]) > 1)
3298 SetLastError(CRYPT_E_ASN1_CORRUPT);
3301 if (pbEncoded[1] > 1)
3303 SetLastError(CRYPT_E_ASN1_CORRUPT);
3308 *pcbStructInfo = sizeof(BOOL);
3311 else if (*pcbStructInfo < sizeof(BOOL))
3313 *pcbStructInfo = sizeof(BOOL);
3314 SetLastError(ERROR_MORE_DATA);
3319 *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
3325 static BOOL WINAPI CRYPT_AsnDecodePathConstraint(DWORD dwCertEncodingType,
3326 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3327 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3330 DWORD bytesNeeded = sizeof(BOOL) + sizeof(DWORD);
3333 *pcbStructInfo = bytesNeeded;
3334 else if (*pcbStructInfo < bytesNeeded)
3336 *pcbStructInfo = bytesNeeded;
3337 SetLastError(ERROR_MORE_DATA);
3344 if (pbEncoded[0] == ASN_INTEGER)
3346 DWORD size = sizeof(DWORD);
3348 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
3349 pbEncoded, cbEncoded, 0, NULL,
3350 (BYTE *)pvStructInfo + sizeof(BOOL), &size);
3353 cbEncoded -= 2 + pbEncoded[1];
3354 pbEncoded += 2 + pbEncoded[1];
3357 SetLastError(CRYPT_E_ASN1_CORRUPT);
3361 *(BOOL *)pvStructInfo = TRUE;
3366 SetLastError(CRYPT_E_ASN1_BADTAG);
3371 *(BOOL *)pvStructInfo = FALSE;
3376 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
3377 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3378 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3384 if (pbEncoded[0] == ASN_SEQUENCE)
3388 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3390 /* sanity-check length, space enough for 7 bytes of integer and
3395 SetLastError(CRYPT_E_ASN1_CORRUPT);
3400 DWORD bytesNeeded = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
3403 *pcbStructInfo = bytesNeeded;
3407 CERT_BASIC_CONSTRAINTS2_INFO info = { 0 };
3409 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3410 pbEncoded += 1 + lenBytes;
3411 cbEncoded -= 1 + lenBytes;
3416 if (pbEncoded[0] == ASN_BOOL)
3418 size = sizeof(BOOL);
3419 ret = CRYPT_AsnDecodeBool(dwCertEncodingType,
3420 NULL, pbEncoded, cbEncoded,
3421 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
3425 cbEncoded -= 2 + pbEncoded[1];
3426 pbEncoded += 2 + pbEncoded[1];
3429 if (ret && cbEncoded && pbEncoded[0] == ASN_INTEGER)
3431 size = sizeof(info.dwPathLenConstraint);
3432 ret = CRYPT_AsnDecodeInt(dwCertEncodingType,
3433 X509_INTEGER, pbEncoded, cbEncoded, 0, NULL,
3434 &info.dwPathLenConstraint, &size);
3437 cbEncoded -= 2 + pbEncoded[1];
3438 pbEncoded += 2 + pbEncoded[1];
3441 SetLastError(CRYPT_E_ASN1_CORRUPT);
3445 info.fPathLenConstraint = TRUE;
3451 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3452 pDecodePara, pvStructInfo, pcbStructInfo,
3455 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3456 pvStructInfo = *(BYTE **)pvStructInfo;
3457 memcpy(pvStructInfo, &info,
3458 sizeof(CERT_BASIC_CONSTRAINTS2_INFO));
3467 SetLastError(CRYPT_E_ASN1_BADTAG);
3471 __EXCEPT(page_fault)
3473 SetLastError(STATUS_ACCESS_VIOLATION);
3480 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
3481 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3482 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3488 if (pbEncoded[0] == ASN_OCTETSTRING)
3490 DWORD bytesNeeded, dataLen;
3492 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3494 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3495 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
3497 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
3499 *pcbStructInfo = bytesNeeded;
3500 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3501 pvStructInfo, pcbStructInfo, bytesNeeded)))
3503 CRYPT_DATA_BLOB *blob;
3504 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3506 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3507 pvStructInfo = *(BYTE **)pvStructInfo;
3508 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
3509 blob->cbData = dataLen;
3510 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3511 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
3514 blob->pbData = (BYTE *)pvStructInfo +
3515 sizeof(CRYPT_DATA_BLOB);
3517 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
3525 SetLastError(CRYPT_E_ASN1_BADTAG);
3529 __EXCEPT(page_fault)
3531 SetLastError(STATUS_ACCESS_VIOLATION);
3538 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
3539 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3540 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3544 TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
3545 pDecodePara, pvStructInfo, pcbStructInfo);
3547 if (pbEncoded[0] == ASN_BITSTRING)
3549 DWORD bytesNeeded, dataLen;
3551 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3553 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3554 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
3556 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
3558 *pcbStructInfo = bytesNeeded;
3559 else if (*pcbStructInfo < bytesNeeded)
3561 *pcbStructInfo = bytesNeeded;
3562 SetLastError(ERROR_MORE_DATA);
3567 CRYPT_BIT_BLOB *blob;
3569 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
3570 blob->cbData = dataLen - 1;
3571 blob->cUnusedBits = *(pbEncoded + 1 +
3572 GET_LEN_BYTES(pbEncoded[1]));
3573 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3574 blob->pbData = (BYTE *)pbEncoded + 2 +
3575 GET_LEN_BYTES(pbEncoded[1]);
3578 assert(blob->pbData);
3581 BYTE mask = 0xff << blob->cUnusedBits;
3583 memcpy(blob->pbData, pbEncoded + 2 +
3584 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
3585 blob->pbData[blob->cbData - 1] &= mask;
3593 SetLastError(CRYPT_E_ASN1_BADTAG);
3599 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
3600 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3601 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3605 TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
3606 pDecodePara, pvStructInfo, pcbStructInfo);
3612 if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
3613 lpszStructType, pbEncoded, cbEncoded,
3614 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
3617 *pcbStructInfo = bytesNeeded;
3618 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3619 pvStructInfo, pcbStructInfo, bytesNeeded)))
3621 CRYPT_BIT_BLOB *blob;
3623 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3624 pvStructInfo = *(BYTE **)pvStructInfo;
3625 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
3626 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
3627 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
3628 lpszStructType, pbEncoded, cbEncoded,
3629 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3634 __EXCEPT(page_fault)
3636 SetLastError(STATUS_ACCESS_VIOLATION);
3643 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
3644 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3645 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3651 *pcbStructInfo = sizeof(int);
3656 BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
3657 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
3658 DWORD size = sizeof(buf);
3660 blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
3661 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
3662 X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
3665 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3666 pvStructInfo, pcbStructInfo, sizeof(int))))
3670 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3671 pvStructInfo = *(BYTE **)pvStructInfo;
3672 if (blob->pbData[blob->cbData - 1] & 0x80)
3674 /* initialize to a negative value to sign-extend */
3679 for (i = 0; i < blob->cbData; i++)
3682 val |= blob->pbData[blob->cbData - i - 1];
3684 memcpy(pvStructInfo, &val, sizeof(int));
3687 else if (GetLastError() == ERROR_MORE_DATA)
3688 SetLastError(CRYPT_E_ASN1_LARGE);
3690 __EXCEPT(page_fault)
3692 SetLastError(STATUS_ACCESS_VIOLATION);
3699 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
3700 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3701 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3705 if (pbEncoded[0] == ASN_INTEGER)
3707 DWORD bytesNeeded, dataLen;
3709 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3711 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3713 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
3715 *pcbStructInfo = bytesNeeded;
3716 else if (*pcbStructInfo < bytesNeeded)
3718 *pcbStructInfo = bytesNeeded;
3719 SetLastError(ERROR_MORE_DATA);
3724 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
3726 blob->cbData = dataLen;
3727 assert(blob->pbData);
3732 for (i = 0; i < blob->cbData; i++)
3733 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
3741 SetLastError(CRYPT_E_ASN1_BADTAG);
3747 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
3748 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3749 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3757 if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
3758 lpszStructType, pbEncoded, cbEncoded,
3759 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
3762 *pcbStructInfo = bytesNeeded;
3763 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3764 pvStructInfo, pcbStructInfo, bytesNeeded)))
3766 CRYPT_INTEGER_BLOB *blob;
3768 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3769 pvStructInfo = *(BYTE **)pvStructInfo;
3770 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
3771 blob->pbData = (BYTE *)pvStructInfo +
3772 sizeof(CRYPT_INTEGER_BLOB);
3773 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
3774 lpszStructType, pbEncoded, cbEncoded,
3775 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
3780 __EXCEPT(page_fault)
3782 SetLastError(STATUS_ACCESS_VIOLATION);
3789 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
3790 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3791 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3797 if (pbEncoded[0] == ASN_INTEGER)
3799 DWORD bytesNeeded, dataLen;
3800 CRYPT_INTEGER_BLOB *blob;
3802 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3804 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
3806 *pcbStructInfo = bytesNeeded;
3807 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3808 pvStructInfo, pcbStructInfo, bytesNeeded)))
3810 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3812 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3813 pvStructInfo = *(BYTE **)pvStructInfo;
3814 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
3815 blob->cbData = dataLen;
3816 blob->pbData = (BYTE *)pvStructInfo +
3817 sizeof(CRYPT_INTEGER_BLOB);
3818 /* remove leading zero byte if it exists */
3819 if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
3828 for (i = 0; i < blob->cbData; i++)
3829 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
3830 pbEncoded[1] - i - 1);
3837 SetLastError(CRYPT_E_ASN1_BADTAG);
3841 __EXCEPT(page_fault)
3843 SetLastError(STATUS_ACCESS_VIOLATION);
3850 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
3851 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3852 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3858 *pcbStructInfo = sizeof(int);
3863 if (pbEncoded[0] == ASN_ENUMERATED)
3865 unsigned int val = 0, i;
3869 SetLastError(CRYPT_E_ASN1_EOD);
3872 else if (pbEncoded[1] == 0)
3874 SetLastError(CRYPT_E_ASN1_CORRUPT);
3879 /* A little strange looking, but we have to accept a sign byte:
3880 * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff. Also,
3881 * assuming a small length is okay here, it has to be in short
3884 if (pbEncoded[1] > sizeof(unsigned int) + 1)
3886 SetLastError(CRYPT_E_ASN1_LARGE);
3889 for (i = 0; i < pbEncoded[1]; i++)
3892 val |= pbEncoded[2 + i];
3894 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3895 pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
3897 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3898 pvStructInfo = *(BYTE **)pvStructInfo;
3899 memcpy(pvStructInfo, &val, sizeof(unsigned int));
3905 SetLastError(CRYPT_E_ASN1_BADTAG);
3909 __EXCEPT(page_fault)
3911 SetLastError(STATUS_ACCESS_VIOLATION);
3918 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
3921 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
3926 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
3928 if (!isdigit(*(pbEncoded))) \
3930 SetLastError(CRYPT_E_ASN1_CORRUPT); \
3936 (word) += *(pbEncoded)++ - '0'; \
3941 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
3942 SYSTEMTIME *sysTime)
3948 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
3950 WORD hours, minutes = 0;
3951 BYTE sign = *pbEncoded++;
3954 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
3955 if (ret && hours >= 24)
3957 SetLastError(CRYPT_E_ASN1_CORRUPT);
3962 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
3963 if (ret && minutes >= 60)
3965 SetLastError(CRYPT_E_ASN1_CORRUPT);
3973 sysTime->wHour += hours;
3974 sysTime->wMinute += minutes;
3978 if (hours > sysTime->wHour)
3981 sysTime->wHour = 24 - (hours - sysTime->wHour);
3984 sysTime->wHour -= hours;
3985 if (minutes > sysTime->wMinute)
3988 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
3991 sysTime->wMinute -= minutes;
3996 __EXCEPT(page_fault)
3998 SetLastError(STATUS_ACCESS_VIOLATION);
4005 #define MIN_ENCODED_TIME_LENGTH 10
4007 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
4008 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4009 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4015 *pcbStructInfo = sizeof(FILETIME);
4020 if (pbEncoded[0] == ASN_UTCTIME)
4024 SetLastError(CRYPT_E_ASN1_EOD);
4027 else if (pbEncoded[1] > 0x7f)
4029 /* long-form date strings really can't be valid */
4030 SetLastError(CRYPT_E_ASN1_CORRUPT);
4035 SYSTEMTIME sysTime = { 0 };
4036 BYTE len = pbEncoded[1];
4038 if (len < MIN_ENCODED_TIME_LENGTH)
4040 SetLastError(CRYPT_E_ASN1_CORRUPT);
4046 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
4047 if (sysTime.wYear >= 50)
4048 sysTime.wYear += 1900;
4050 sysTime.wYear += 2000;
4051 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
4052 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
4053 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
4054 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
4057 if (len >= 2 && isdigit(*pbEncoded) &&
4058 isdigit(*(pbEncoded + 1)))
4059 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4061 else if (isdigit(*pbEncoded))
4062 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
4065 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
4068 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
4069 pDecodePara, pvStructInfo, pcbStructInfo,
4072 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4073 pvStructInfo = *(BYTE **)pvStructInfo;
4074 ret = SystemTimeToFileTime(&sysTime,
4075 (FILETIME *)pvStructInfo);
4082 SetLastError(CRYPT_E_ASN1_BADTAG);
4086 __EXCEPT(page_fault)
4088 SetLastError(STATUS_ACCESS_VIOLATION);
4095 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
4096 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4097 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4103 *pcbStructInfo = sizeof(FILETIME);
4108 if (pbEncoded[0] == ASN_GENERALTIME)
4112 SetLastError(CRYPT_E_ASN1_EOD);
4115 else if (pbEncoded[1] > 0x7f)
4117 /* long-form date strings really can't be valid */
4118 SetLastError(CRYPT_E_ASN1_CORRUPT);
4123 BYTE len = pbEncoded[1];
4125 if (len < MIN_ENCODED_TIME_LENGTH)
4127 SetLastError(CRYPT_E_ASN1_CORRUPT);
4132 SYSTEMTIME sysTime = { 0 };
4135 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
4136 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
4137 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
4138 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
4141 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4144 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4146 if (ret && len > 0 && (*pbEncoded == '.' ||
4153 /* workaround macro weirdness */
4154 digits = min(len, 3);
4155 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
4156 sysTime.wMilliseconds);
4159 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
4162 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
4163 pDecodePara, pvStructInfo, pcbStructInfo,
4166 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4167 pvStructInfo = *(BYTE **)pvStructInfo;
4168 ret = SystemTimeToFileTime(&sysTime,
4169 (FILETIME *)pvStructInfo);
4176 SetLastError(CRYPT_E_ASN1_BADTAG);
4180 __EXCEPT(page_fault)
4182 SetLastError(STATUS_ACCESS_VIOLATION);
4189 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
4190 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4191 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4197 *pcbStructInfo = sizeof(FILETIME);
4203 if (pbEncoded[0] == ASN_UTCTIME)
4204 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
4205 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
4207 else if (pbEncoded[0] == ASN_GENERALTIME)
4208 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
4209 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
4210 pvStructInfo, pcbStructInfo);
4213 SetLastError(CRYPT_E_ASN1_BADTAG);
4217 __EXCEPT(page_fault)
4219 SetLastError(STATUS_ACCESS_VIOLATION);
4226 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
4227 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4228 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4234 if (pbEncoded[0] == ASN_SEQUENCEOF)
4236 DWORD bytesNeeded, dataLen, remainingLen, cValue;
4238 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4243 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4244 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
4246 ptr = pbEncoded + 1 + lenBytes;
4247 remainingLen = dataLen;
4248 while (ret && remainingLen)
4252 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
4255 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
4257 remainingLen -= 1 + nextLenBytes + nextLen;
4258 ptr += 1 + nextLenBytes + nextLen;
4259 bytesNeeded += sizeof(CRYPT_DER_BLOB);
4260 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
4261 bytesNeeded += 1 + nextLenBytes + nextLen;
4267 CRYPT_SEQUENCE_OF_ANY *seq;
4271 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4272 pvStructInfo, pcbStructInfo, bytesNeeded)))
4274 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4275 pvStructInfo = *(BYTE **)pvStructInfo;
4276 seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
4277 seq->cValue = cValue;
4278 seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
4280 nextPtr = (BYTE *)seq->rgValue +
4281 cValue * sizeof(CRYPT_DER_BLOB);
4282 ptr = pbEncoded + 1 + lenBytes;
4283 remainingLen = dataLen;
4285 while (ret && remainingLen)
4289 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
4292 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
4294 seq->rgValue[i].cbData = 1 + nextLenBytes +
4296 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4297 seq->rgValue[i].pbData = (BYTE *)ptr;
4300 seq->rgValue[i].pbData = nextPtr;
4301 memcpy(nextPtr, ptr, 1 + nextLenBytes +
4303 nextPtr += 1 + nextLenBytes + nextLen;
4305 remainingLen -= 1 + nextLenBytes + nextLen;
4306 ptr += 1 + nextLenBytes + nextLen;
4316 SetLastError(CRYPT_E_ASN1_BADTAG);
4320 __EXCEPT(page_fault)
4322 SetLastError(STATUS_ACCESS_VIOLATION);
4329 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
4330 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4331 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4335 CryptDecodeObjectExFunc decodeFunc = NULL;
4337 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
4338 dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
4339 "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
4340 pvStructInfo, pcbStructInfo);
4342 if (!pvStructInfo && !pcbStructInfo)
4344 SetLastError(ERROR_INVALID_PARAMETER);
4347 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
4348 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
4350 SetLastError(ERROR_FILE_NOT_FOUND);
4355 SetLastError(CRYPT_E_ASN1_EOD);
4358 if (cbEncoded > MAX_ENCODED_LEN)
4360 SetLastError(CRYPT_E_ASN1_LARGE);
4364 SetLastError(NOERROR);
4365 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
4366 *(BYTE **)pvStructInfo = NULL;
4367 if (!HIWORD(lpszStructType))
4369 switch (LOWORD(lpszStructType))
4371 case (WORD)X509_CERT_TO_BE_SIGNED:
4372 decodeFunc = CRYPT_AsnDecodeCertInfo;
4374 case (WORD)X509_EXTENSIONS:
4375 decodeFunc = CRYPT_AsnDecodeExtensions;
4377 case (WORD)X509_NAME:
4378 decodeFunc = CRYPT_AsnDecodeName;
4380 case (WORD)X509_PUBLIC_KEY_INFO:
4381 decodeFunc = CRYPT_AsnDecodePubKeyInfo;
4383 case (WORD)X509_BASIC_CONSTRAINTS2:
4384 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
4386 case (WORD)X509_OCTET_STRING:
4387 decodeFunc = CRYPT_AsnDecodeOctets;
4389 case (WORD)X509_BITS:
4390 case (WORD)X509_KEY_USAGE:
4391 decodeFunc = CRYPT_AsnDecodeBits;
4393 case (WORD)X509_INTEGER:
4394 decodeFunc = CRYPT_AsnDecodeInt;
4396 case (WORD)X509_MULTI_BYTE_INTEGER:
4397 decodeFunc = CRYPT_AsnDecodeInteger;
4399 case (WORD)X509_MULTI_BYTE_UINT:
4400 decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
4402 case (WORD)X509_ENUMERATED:
4403 decodeFunc = CRYPT_AsnDecodeEnumerated;
4405 case (WORD)X509_CHOICE_OF_TIME:
4406 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
4408 case (WORD)X509_SEQUENCE_OF_ANY:
4409 decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
4411 case (WORD)PKCS_UTC_TIME:
4412 decodeFunc = CRYPT_AsnDecodeUtcTime;
4415 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
4418 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
4419 decodeFunc = CRYPT_AsnDecodeExtensions;
4420 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
4421 decodeFunc = CRYPT_AsnDecodeUtcTime;
4422 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
4423 decodeFunc = CRYPT_AsnDecodeEnumerated;
4424 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
4425 decodeFunc = CRYPT_AsnDecodeBits;
4426 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
4427 decodeFunc = CRYPT_AsnDecodeOctets;
4428 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
4429 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
4431 TRACE("OID %s not found or unimplemented, looking for DLL\n",
4432 debugstr_a(lpszStructType));
4434 decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
4435 lpszStructType, "CryptDecodeObjectEx", &lib);
4437 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
4438 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
4440 SetLastError(ERROR_FILE_NOT_FOUND);