Use a more portable scheme for storing the name of a critical
[wine] / dlls / crypt32 / encode.c
1 /*
2  * Copyright 2002 Mike McCormack for CodeWeavers
3  * Copyright 2005 Juan Lang
4  *
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.
9  *
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.
14  *
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
18  *
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.
23  *
24  * References:
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.)
28  *
29  * RFC3280, http://www.faqs.org/rfcs/rfc3280.html
30  *
31  * MSDN, especially:
32  * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
33  */
34 #include <assert.h>
35 #include <stdarg.h>
36 #include <stdio.h>
37 #include <stdlib.h>
38
39 #define NONAMELESSUNION
40
41 #include "windef.h"
42 #include "winbase.h"
43 #include "excpt.h"
44 #include "wincrypt.h"
45 #include "winreg.h"
46 #include "snmp.h"
47 #include "wine/debug.h"
48 #include "wine/exception.h"
49
50 /* This is a bit arbitrary, but to set some limit: */
51 #define MAX_ENCODED_LEN 0x02000000
52
53 /* a few asn.1 tags we need */
54 #define ASN_BOOL            (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
55 #define ASN_BITSTRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
56 #define ASN_OCTETSTRING     (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
57 #define ASN_ENUMERATED      (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
58 #define ASN_SETOF           (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
59 #define ASN_NUMERICSTRING   (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
60 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
61 #define ASN_IA5STRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
62 #define ASN_UTCTIME         (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
63 #define ASN_GENERALTIME     (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
64
65 #define ASN_FLAGS_MASK 0xf0
66 #define ASN_TYPE_MASK  0x0f
67
68 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
69
70 static const WCHAR szDllName[] = { 'D','l','l',0 };
71
72 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
73  BYTE *, DWORD *);
74 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
75  DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
76 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
77  DWORD, DWORD, void *, DWORD *);
78 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
79  DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
80
81 /* Prototypes for built-in encoders/decoders.  They follow the Ex style
82  * prototypes.  The dwCertEncodingType and lpszStructType are ignored by the
83  * built-in functions, but the parameters are retained to simplify
84  * CryptEncodeObjectEx/CryptDecodeObjectEx, since they must call functions in
85  * external DLLs that follow these signatures.
86  * FIXME: some built-in functions are suitable to be called directly by
87  * CryptEncodeObjectEx/CryptDecodeObjectEx (they implement exception handling
88  * and memory allocation if requested), others are only suitable to be called
89  * internally.  Comment which are which.
90  */
91 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
92  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
93  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
94 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
95  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
96  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
97 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
98  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
99  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
100 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
101  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
102  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
103 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
104  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
105  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
106 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
107  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
108  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
109 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
110  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
111  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
112 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
113  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
114  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
115 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
116  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
117  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
118 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
119  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
120  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
121
122 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
123  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
124  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
125 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
126  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
127  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
128 /* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of
129  * time, doesn't do memory allocation, and doesn't do exception handling.
130  * (This isn't intended to be the externally-called one.)
131  */
132 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
133  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
134  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
135 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
136  DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
137 /* Assumes algo->Parameters.pbData is set ahead of time */
138 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
139  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
140  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
141 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
142  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
143  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
144 /* Assumes the CRYPT_DATA_BLOB's pbData member has been initialized */
145 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
146  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
147  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
148 /* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
149  * member has been initialized, doesn't do exception handling, and doesn't do
150  * memory allocation.
151  */
152 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
153  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
154  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
155 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
156  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
157  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
158 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
159  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
160  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
161 /* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
162  * member has been initialized, doesn't do exception handling, and doesn't do
163  * memory allocation.
164  */
165 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
166  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
167  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
168
169 /* filter for page-fault exceptions */
170 static WINE_EXCEPTION_FILTER(page_fault)
171 {
172     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
173         return EXCEPTION_EXECUTE_HANDLER;
174     return EXCEPTION_CONTINUE_SEARCH;
175 }
176
177 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
178  LPCSTR pszOID)
179 {
180     static const char szEncodingTypeFmt[] =
181      "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
182     UINT len;
183     char numericOID[7]; /* enough for "#65535" */
184     const char *oid;
185     LPSTR szKey;
186
187     /* MSDN says the encoding type is a mask, but it isn't treated that way.
188      * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
189      * "EncodingType 2" would be expected if it were a mask.  Instead native
190      * stores values in "EncodingType 3".
191      */
192     if (!HIWORD(pszOID))
193     {
194         snprintf(numericOID, sizeof(numericOID), "#%d", LOWORD(pszOID));
195         oid = numericOID;
196     }
197     else
198         oid = pszOID;
199
200     /* This is enough: the lengths of the two string parameters are explicitly
201      * counted, and we need up to five additional characters for the encoding
202      * type.  These are covered by the "%d", "%s", and "%s" characters in the
203      * format specifier that are removed by sprintf.
204      */
205     len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
206     szKey = HeapAlloc(GetProcessHeap(), 0, len);
207     if (szKey)
208         sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
209     return szKey;
210 }
211
212 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
213                   LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
214 {
215     LONG r;
216     HKEY hKey;
217     LPSTR szKey;
218
219     TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
220           debugstr_w(pwszDll), pszOverrideFuncName);
221
222     /* This only registers functions for encoding certs, not messages */
223     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
224         return TRUE;
225
226     /* Native does nothing pwszDll is NULL */
227     if (!pwszDll)
228         return TRUE;
229
230     /* I'm not matching MS bug for bug here, because I doubt any app depends on
231      * it:
232      * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
233      *   it creates would never be used
234      * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
235      * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
236      */
237     if (!pszFuncName || !pszOID)
238     {
239         SetLastError(ERROR_INVALID_PARAMETER);
240         return FALSE;
241     }
242
243     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
244     TRACE("Key name is %s\n", debugstr_a(szKey));
245
246     if (!szKey)
247         return FALSE;
248
249     r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
250     HeapFree(GetProcessHeap(), 0, szKey);
251     if(r != ERROR_SUCCESS)
252         return FALSE;
253
254     /* write the values */
255     if (pszOverrideFuncName)
256         RegSetValueExA(hKey, "FuncName", 0, REG_SZ, (const BYTE*)pszOverrideFuncName,
257          lstrlenA(pszOverrideFuncName) + 1);
258     RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
259                     (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
260
261     RegCloseKey(hKey);
262     return TRUE;
263 }
264
265 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
266  LPCSTR pszOID)
267 {
268     LPSTR szKey;
269     LONG rc;
270
271     TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
272
273     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
274         return TRUE;
275
276     if (!pszFuncName || !pszOID)
277     {
278         SetLastError(ERROR_INVALID_PARAMETER);
279         return FALSE;
280     }
281
282     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
283     rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
284     HeapFree(GetProcessHeap(), 0, szKey);
285     if (rc)
286         SetLastError(rc);
287     return rc ? FALSE : TRUE;
288 }
289
290 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
291  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
292  DWORD *pcbValueData)
293 {
294     LPSTR szKey;
295     LONG rc;
296     HKEY hKey;
297
298     TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
299      debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
300      pcbValueData);
301
302     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
303         return TRUE;
304
305     if (!pszFuncName || !pszOID || !pwszValueName)
306     {
307         SetLastError(ERROR_INVALID_PARAMETER);
308         return FALSE;
309     }
310
311     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
312     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
313     HeapFree(GetProcessHeap(), 0, szKey);
314     if (rc)
315         SetLastError(rc);
316     else
317     {
318         rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
319          pbValueData, pcbValueData);
320         if (rc)
321             SetLastError(rc);
322         RegCloseKey(hKey);
323     }
324     return rc ? FALSE : TRUE;
325 }
326
327 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
328  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
329  const BYTE *pbValueData, DWORD cbValueData)
330 {
331     LPSTR szKey;
332     LONG rc;
333     HKEY hKey;
334
335     TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
336      debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
337      cbValueData);
338
339     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
340         return TRUE;
341
342     if (!pszFuncName || !pszOID || !pwszValueName)
343     {
344         SetLastError(ERROR_INVALID_PARAMETER);
345         return FALSE;
346     }
347
348     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
349     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
350     HeapFree(GetProcessHeap(), 0, szKey);
351     if (rc)
352         SetLastError(rc);
353     else
354     {
355         rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
356          cbValueData);
357         if (rc)
358             SetLastError(rc);
359         RegCloseKey(hKey);
360     }
361     return rc ? FALSE : TRUE;
362 }
363
364 /* Gets the registered function named szFuncName for dwCertEncodingType and
365  * lpszStructType, or NULL if one could not be found.  *lib will be set to the
366  * handle of the module it's in, or NULL if no module was loaded.  If the
367  * return value is NULL, *lib will also be NULL, to simplify error handling.
368  */
369 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
370  LPCSTR szFuncName, HMODULE *lib)
371 {
372     void *ret = NULL;
373     char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
374      lpszStructType);
375     const char *funcName;
376     long r;
377     HKEY hKey;
378     DWORD type, size = 0;
379
380     TRACE("(%08lx %s %s %p)\n", dwCertEncodingType, debugstr_a(lpszStructType),
381      debugstr_a(szFuncName), lib);
382
383     *lib = NULL;
384     r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
385     HeapFree(GetProcessHeap(), 0, szKey);
386     if(r != ERROR_SUCCESS)
387         return NULL;
388
389     RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
390     if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
391     {
392         funcName = HeapAlloc(GetProcessHeap(), 0, size);
393         RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
394          &size);
395     }
396     else
397         funcName = szFuncName;
398     RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
399     if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
400     {
401         LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
402
403         RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
404          &size);
405         *lib = LoadLibraryW(dllName);
406         if (*lib)
407         {
408              ret = GetProcAddress(*lib, funcName);
409              if (!ret)
410              {
411                  /* Unload the library, the caller doesn't want to unload it
412                   * when the return value is NULL.
413                   */
414                  FreeLibrary(*lib);
415                  *lib = NULL;
416              }
417         }
418         HeapFree(GetProcessHeap(), 0, dllName);
419     }
420     if (funcName != szFuncName)
421         HeapFree(GetProcessHeap(), 0, (char *)funcName);
422     TRACE("returning %p\n", ret);
423     return ret;
424 }
425
426 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
427  const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
428 {
429     BOOL ret = FALSE;
430     HMODULE lib;
431     CryptEncodeObjectFunc pCryptEncodeObject;
432
433     TRACE("(0x%08lx, %s, %p, %p, %p)\n", dwCertEncodingType,
434      debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
435      pcbEncoded);
436
437     if (!pbEncoded && !pcbEncoded)
438     {
439         SetLastError(ERROR_INVALID_PARAMETER);
440         return FALSE;
441     }
442
443     /* Try registered DLL first.. */
444     pCryptEncodeObject =
445      (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
446      lpszStructType, "CryptEncodeObject", &lib);
447     if (pCryptEncodeObject)
448     {
449         ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
450          pvStructInfo, pbEncoded, pcbEncoded);
451         FreeLibrary(lib);
452     }
453     else
454     {
455         /* If not, use CryptEncodeObjectEx */
456         ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
457          pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
458     }
459     return ret;
460 }
461
462 /* Helper function to check *pcbEncoded, set it to the required size, and
463  * optionally to allocate memory.  Assumes pbEncoded is not NULL.
464  * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
465  * pointer to the newly allocated memory.
466  */
467 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
468  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
469  DWORD bytesNeeded)
470 {
471     BOOL ret = TRUE;
472
473     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
474     {
475         if (pEncodePara && pEncodePara->pfnAlloc)
476             *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
477         else
478             *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
479         if (!*(BYTE **)pbEncoded)
480             ret = FALSE;
481         else
482             *pcbEncoded = bytesNeeded;
483     }
484     else if (bytesNeeded > *pcbEncoded)
485     {
486         *pcbEncoded = bytesNeeded;
487         SetLastError(ERROR_MORE_DATA);
488         ret = FALSE;
489     }
490     return ret;
491 }
492
493 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
494 {
495     DWORD bytesNeeded, significantBytes = 0;
496
497     if (len <= 0x7f)
498         bytesNeeded = 1;
499     else
500     {
501         DWORD temp;
502
503         for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
504          temp <<= 8, significantBytes--)
505             ;
506         bytesNeeded = significantBytes + 1;
507     }
508     if (!pbEncoded)
509     {
510         *pcbEncoded = bytesNeeded;
511         return TRUE;
512     }
513     if (*pcbEncoded < bytesNeeded)
514     {
515         SetLastError(ERROR_MORE_DATA);
516         return FALSE;
517     }
518     if (len <= 0x7f)
519         *pbEncoded = (BYTE)len;
520     else
521     {
522         DWORD i;
523
524         *pbEncoded++ = significantBytes | 0x80;
525         for (i = 0; i < significantBytes; i++)
526         {
527             *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
528             len >>= 8;
529         }
530     }
531     *pcbEncoded = bytesNeeded;
532     return TRUE;
533 }
534
535 struct AsnEncodeSequenceItem
536 {
537     const void             *pvStructInfo;
538     CryptEncodeObjectExFunc encodeFunc;
539     DWORD                   size; /* used during encoding, not for your use */
540 };
541
542 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
543  struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
544  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
545 {
546     BOOL ret;
547     DWORD i, dataLen = 0;
548
549     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", items, cItem, dwFlags, pEncodePara,
550      pbEncoded, *pcbEncoded);
551     for (i = 0, ret = TRUE; ret && i < cItem; i++)
552     {
553         ret = items[i].encodeFunc(dwCertEncodingType, NULL,
554          items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
555          NULL, &items[i].size);
556         dataLen += items[i].size;
557     }
558     if (ret)
559     {
560         DWORD lenBytes, bytesNeeded;
561
562         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
563         bytesNeeded = 1 + lenBytes + dataLen;
564         if (!pbEncoded)
565             *pcbEncoded = bytesNeeded;
566         else
567         {
568             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
569              pcbEncoded, bytesNeeded)))
570             {
571                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
572                     pbEncoded = *(BYTE **)pbEncoded;
573                 *pbEncoded++ = ASN_SEQUENCE;
574                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
575                 pbEncoded += lenBytes;
576                 for (i = 0; ret && i < cItem; i++)
577                 {
578                     ret = items[i].encodeFunc(dwCertEncodingType, NULL,
579                      items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
580                      NULL, pbEncoded, &items[i].size);
581                     pbEncoded += items[i].size;
582                 }
583             }
584         }
585     }
586     TRACE("returning %d (%08lx)\n", ret, GetLastError());
587     return ret;
588 }
589
590 struct AsnConstructedItem
591 {
592     BYTE                    tag;
593     const void             *pvStructInfo;
594     CryptEncodeObjectExFunc encodeFunc;
595 };
596
597 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
598  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
599  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
600 {
601     BOOL ret;
602     const struct AsnConstructedItem *item =
603      (const struct AsnConstructedItem *)pvStructInfo;
604     DWORD len;
605
606     if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
607      item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
608     {
609         DWORD dataLen, bytesNeeded;
610
611         CRYPT_EncodeLen(len, NULL, &dataLen);
612         bytesNeeded = 1 + dataLen + len;
613         if (!pbEncoded)
614             *pcbEncoded = bytesNeeded;
615         else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
616          pbEncoded, pcbEncoded, bytesNeeded)))
617         {
618             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
619                 pbEncoded = *(BYTE **)pbEncoded;
620             *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
621             CRYPT_EncodeLen(len, pbEncoded, &dataLen);
622             pbEncoded += dataLen;
623             ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
624              item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
625              pbEncoded, &len);
626         }
627     }
628     return ret;
629 }
630
631 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
632  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
633  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
634 {
635     const DWORD *ver = (const DWORD *)pvStructInfo;
636     BOOL ret;
637
638     /* CERT_V1 is not encoded */
639     if (*ver == CERT_V1)
640     {
641         *pcbEncoded = 0;
642         ret = TRUE;
643     }
644     else
645     {
646         struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
647
648         ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
649          &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
650     }
651     return ret;
652 }
653
654 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
655  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
656  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
657 {
658     const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
659     BOOL ret;
660
661     if (!pbEncoded)
662     {
663         *pcbEncoded = blob->cbData;
664         ret = TRUE;
665     }
666     else if (*pcbEncoded < blob->cbData)
667     {
668         *pcbEncoded = blob->cbData;
669         SetLastError(ERROR_MORE_DATA);
670         ret = FALSE;
671     }
672     else
673     {
674         if (blob->cbData)
675             memcpy(pbEncoded, blob->pbData, blob->cbData);
676         *pcbEncoded = blob->cbData;
677         ret = TRUE;
678     }
679     return ret;
680 }
681
682 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
683  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
684  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
685 {
686     BOOL ret;
687     /* This has two filetimes in a row, a NotBefore and a NotAfter */
688     const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
689     struct AsnEncodeSequenceItem items[] = {
690      { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
691      { timePtr,   CRYPT_AsnEncodeChoiceOfTime, 0 },
692     };
693
694     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, 
695      sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
696      pcbEncoded);
697     return ret;
698 }
699
700 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
701  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
702  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
703  DWORD *pcbEncoded)
704 {
705     const CRYPT_ALGORITHM_IDENTIFIER *algo =
706      (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
707     BOOL ret;
708     struct AsnEncodeSequenceItem items[] = {
709      { algo->pszObjId,    CRYPT_AsnEncodeOid, 0 },
710      { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
711     };
712
713     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
714      sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
715      pcbEncoded);
716     return ret;
717 }
718
719 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
720  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
721  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
722 {
723     BOOL ret;
724
725     __TRY
726     {
727         const CERT_PUBLIC_KEY_INFO *info =
728          (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
729         struct AsnEncodeSequenceItem items[] = {
730          { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
731          { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
732         };
733
734         TRACE("Encoding public key with OID %s\n",
735          debugstr_a(info->Algorithm.pszObjId));
736         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
737          sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
738          pcbEncoded);
739     }
740     __EXCEPT(page_fault)
741     {
742         SetLastError(STATUS_ACCESS_VIOLATION);
743         ret = FALSE;
744     }
745     __ENDTRY
746     return ret;
747 }
748
749 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
750  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
751  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
752 {
753     BOOL ret;
754
755     __TRY
756     {
757         const CERT_SIGNED_CONTENT_INFO *info =
758          (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
759         struct AsnEncodeSequenceItem items[] = {
760          { &info->ToBeSigned,         CRYPT_CopyEncodedBlob, 0 },
761          { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
762          { &info->Signature,          CRYPT_AsnEncodeBitsSwapBytes, 0 },
763         };
764
765         if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
766             items[2].encodeFunc = CRYPT_AsnEncodeBits;
767         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, 
768          sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
769          pcbEncoded);
770     }
771     __EXCEPT(page_fault)
772     {
773         SetLastError(STATUS_ACCESS_VIOLATION);
774         ret = FALSE;
775     }
776     __ENDTRY
777     return ret;
778 }
779
780 /* Like in Windows, this blithely ignores the validity of the passed-in
781  * CERT_INFO, and just encodes it as-is.  The resulting encoded data may not
782  * decode properly, see CRYPT_AsnDecodeCertInfo.
783  */
784 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
785  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
786  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
787 {
788     BOOL ret;
789
790     __TRY
791     {
792         const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
793         struct AsnEncodeSequenceItem items[10] = {
794          { &info->dwVersion,            CRYPT_AsnEncodeCertVersion, 0 },
795          { &info->SerialNumber,         CRYPT_AsnEncodeInteger, 0 },
796          { &info->SignatureAlgorithm,   CRYPT_AsnEncodeAlgorithmId, 0 },
797          { &info->Issuer,               CRYPT_CopyEncodedBlob, 0 },
798          { &info->NotBefore,            CRYPT_AsnEncodeValidity, 0 },
799          { &info->Subject,              CRYPT_CopyEncodedBlob, 0 },
800          { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
801          { 0 }
802         };
803         struct AsnConstructedItem constructed[3] = { { 0 } };
804         DWORD cItem = 7, cConstructed = 0;
805
806         if (info->IssuerUniqueId.cbData)
807         {
808             constructed[cConstructed].tag = 1;
809             constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
810             constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
811             items[cItem].pvStructInfo = &constructed[cConstructed];
812             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
813             cConstructed++;
814             cItem++;
815         }
816         if (info->SubjectUniqueId.cbData)
817         {
818             constructed[cConstructed].tag = 2;
819             constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
820             constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
821             items[cItem].pvStructInfo = &constructed[cConstructed];
822             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
823             cConstructed++;
824             cItem++;
825         }
826         if (info->cExtension)
827         {
828             constructed[cConstructed].tag = 3;
829             constructed[cConstructed].pvStructInfo = &info->cExtension;
830             constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
831             items[cItem].pvStructInfo = &constructed[cConstructed];
832             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
833             cConstructed++;
834             cItem++;
835         }
836
837         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
838          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
839     }
840     __EXCEPT(page_fault)
841     {
842         SetLastError(STATUS_ACCESS_VIOLATION);
843         ret = FALSE;
844     }
845     __ENDTRY
846     return ret;
847 }
848
849 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
850  BYTE *pbEncoded, DWORD *pcbEncoded)
851 {
852     struct AsnEncodeSequenceItem items[3] = {
853      { &entry->SerialNumber,   CRYPT_AsnEncodeInteger, 0 },
854      { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
855      { 0 }
856     };
857     DWORD cItem = 2;
858     BOOL ret;
859
860     TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
861
862     if (entry->cExtension)
863     {
864         items[cItem].pvStructInfo = &entry->cExtension;
865         items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
866         cItem++;
867     }
868
869     ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
870      pbEncoded, pcbEncoded);
871
872     TRACE("returning %d (%08lx)\n", ret, GetLastError());
873     return ret;
874 }
875
876 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
877  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
878  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
879 {
880     DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
881     DWORD bytesNeeded, dataLen, lenBytes, i;
882     const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY **)
883      ((const BYTE *)pvStructInfo + sizeof(DWORD));
884     BOOL ret = TRUE;
885
886     for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
887     {
888         DWORD size;
889
890         ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
891         if (ret)
892             dataLen += size;
893     }
894     CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
895     bytesNeeded = 1 + lenBytes + dataLen;
896     if (!pbEncoded)
897         *pcbEncoded = bytesNeeded;
898     else
899     {
900         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
901          pcbEncoded, bytesNeeded)))
902         {
903             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
904                 pbEncoded = *(BYTE **)pbEncoded;
905             *pbEncoded++ = ASN_SEQUENCEOF;
906             CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
907             pbEncoded += lenBytes;
908             for (i = 0; i < cCRLEntry; i++)
909             {
910                 DWORD size = dataLen;
911
912                 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
913                 pbEncoded += size;
914                 dataLen -= size;
915             }
916         }
917     }
918     return ret;
919 }
920
921 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
922  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
923  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
924 {
925     const DWORD *ver = (const DWORD *)pvStructInfo;
926     BOOL ret;
927
928     /* CRL_V1 is not encoded */
929     if (*ver == CRL_V1)
930     {
931         *pcbEncoded = 0;
932         ret = TRUE;
933     }
934     else
935         ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
936          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
937     return ret;
938 }
939
940 /* Like in Windows, this blithely ignores the validity of the passed-in
941  * CRL_INFO, and just encodes it as-is.  The resulting encoded data may not
942  * decode properly, see CRYPT_AsnDecodeCRLInfo.
943  */
944 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
945  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
946  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
947 {
948     BOOL ret;
949
950     __TRY
951     {
952         const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
953         struct AsnEncodeSequenceItem items[7] = {
954          { &info->dwVersion,          CRYPT_AsnEncodeCRLVersion, 0 },
955          { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
956          { &info->Issuer,             CRYPT_CopyEncodedBlob, 0 },
957          { &info->ThisUpdate,         CRYPT_AsnEncodeChoiceOfTime, 0 },
958          { 0 }
959         };
960         DWORD cItem = 4;
961
962         if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
963         {
964             items[cItem].pvStructInfo = &info->NextUpdate;
965             items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
966             cItem++;
967         }
968         if (info->cCRLEntry)
969         {
970             items[cItem].pvStructInfo = &info->cCRLEntry;
971             items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
972             cItem++;
973         }
974         if (info->cExtension)
975         {
976             items[cItem].pvStructInfo = &info->cExtension;
977             items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
978             cItem++;
979         }
980
981         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
982          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
983     }
984     __EXCEPT(page_fault)
985     {
986         SetLastError(STATUS_ACCESS_VIOLATION);
987         ret = FALSE;
988     }
989     __ENDTRY
990     return ret;
991 }
992
993 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
994  DWORD *pcbEncoded)
995 {
996     BOOL ret;
997     struct AsnEncodeSequenceItem items[3] = {
998      { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
999      { NULL, NULL, 0 },
1000      { NULL, NULL, 0 },
1001     };
1002     DWORD cItem = 1;
1003
1004     TRACE("%p, %p, %ld\n", ext, pbEncoded, *pcbEncoded);
1005
1006     if (ext->fCritical)
1007     {
1008         items[cItem].pvStructInfo = &ext->fCritical;
1009         items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1010         cItem++;
1011     }
1012     items[cItem].pvStructInfo = &ext->Value;
1013     items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
1014     cItem++;
1015
1016     ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
1017      pbEncoded, pcbEncoded);
1018     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1019     return ret;
1020 }
1021
1022 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
1023  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1024  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1025 {
1026     BOOL ret;
1027
1028     __TRY
1029     {
1030         DWORD bytesNeeded, dataLen, lenBytes, i;
1031         const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
1032
1033         ret = TRUE;
1034         for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
1035         {
1036             DWORD size;
1037
1038             ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
1039             if (ret)
1040                 dataLen += size;
1041         }
1042         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1043         bytesNeeded = 1 + lenBytes + dataLen;
1044         if (!pbEncoded)
1045             *pcbEncoded = bytesNeeded;
1046         else
1047         {
1048             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1049              pcbEncoded, bytesNeeded)))
1050             {
1051                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1052                     pbEncoded = *(BYTE **)pbEncoded;
1053                 *pbEncoded++ = ASN_SEQUENCEOF;
1054                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1055                 pbEncoded += lenBytes;
1056                 for (i = 0; i < exts->cExtension; i++)
1057                 {
1058                     DWORD size = dataLen;
1059
1060                     ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
1061                      pbEncoded, &size);
1062                     pbEncoded += size;
1063                     dataLen -= size;
1064                 }
1065             }
1066         }
1067     }
1068     __EXCEPT(page_fault)
1069     {
1070         SetLastError(STATUS_ACCESS_VIOLATION);
1071         ret = FALSE;
1072     }
1073     __ENDTRY
1074     return ret;
1075 }
1076
1077 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
1078  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1079  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1080 {
1081     LPCSTR pszObjId = (LPCSTR)pvStructInfo;
1082     DWORD bytesNeeded = 0, lenBytes;
1083     BOOL ret = TRUE;
1084     int firstPos = 0;
1085     BYTE firstByte = 0;
1086
1087     TRACE("%s\n", debugstr_a(pszObjId));
1088
1089     if (pszObjId)
1090     {
1091         const char *ptr;
1092         int val1, val2;
1093
1094         if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
1095         {
1096             SetLastError(CRYPT_E_ASN1_ERROR);
1097             return FALSE;
1098         }
1099         bytesNeeded++;
1100         firstByte = val1 * 40 + val2;
1101         ptr = pszObjId + firstPos;
1102         while (ret && *ptr)
1103         {
1104             int pos;
1105
1106             /* note I assume each component is at most 32-bits long in base 2 */
1107             if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
1108             {
1109                 if (val1 >= 0x10000000)
1110                     bytesNeeded += 5;
1111                 else if (val1 >= 0x200000)
1112                     bytesNeeded += 4;
1113                 else if (val1 >= 0x4000)
1114                     bytesNeeded += 3;
1115                 else if (val1 >= 0x80)
1116                     bytesNeeded += 2;
1117                 else
1118                     bytesNeeded += 1;
1119                 ptr += pos;
1120                 if (*ptr == '.')
1121                     ptr++;
1122             }
1123             else
1124             {
1125                 SetLastError(CRYPT_E_ASN1_ERROR);
1126                 return FALSE;
1127             }
1128         }
1129         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1130     }
1131     else
1132         lenBytes = 1;
1133     bytesNeeded += 1 + lenBytes;
1134     if (pbEncoded)
1135     {
1136         if (*pcbEncoded < bytesNeeded)
1137         {
1138             SetLastError(ERROR_MORE_DATA);
1139             ret = FALSE;
1140         }
1141         else
1142         {
1143             *pbEncoded++ = ASN_OBJECTIDENTIFIER;
1144             CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
1145             pbEncoded += lenBytes;
1146             if (pszObjId)
1147             {
1148                 const char *ptr;
1149                 int val, pos;
1150
1151                 *pbEncoded++ = firstByte;
1152                 ptr = pszObjId + firstPos;
1153                 while (ret && *ptr)
1154                 {
1155                     sscanf(ptr, "%d%n", &val, &pos);
1156                     {
1157                         unsigned char outBytes[5];
1158                         int numBytes, i;
1159
1160                         if (val >= 0x10000000)
1161                             numBytes = 5;
1162                         else if (val >= 0x200000)
1163                             numBytes = 4;
1164                         else if (val >= 0x4000)
1165                             numBytes = 3;
1166                         else if (val >= 0x80)
1167                             numBytes = 2;
1168                         else
1169                             numBytes = 1;
1170                         for (i = numBytes; i > 0; i--)
1171                         {
1172                             outBytes[i - 1] = val & 0x7f;
1173                             val >>= 7;
1174                         }
1175                         for (i = 0; i < numBytes - 1; i++)
1176                             *pbEncoded++ = outBytes[i] | 0x80;
1177                         *pbEncoded++ = outBytes[i];
1178                         ptr += pos;
1179                         if (*ptr == '.')
1180                             ptr++;
1181                     }
1182                 }
1183             }
1184         }
1185     }
1186     *pcbEncoded = bytesNeeded;
1187     return ret;
1188 }
1189
1190 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
1191  CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
1192 {
1193     BYTE tag;
1194     DWORD bytesNeeded, lenBytes, encodedLen;
1195     BOOL ret = TRUE;
1196
1197     switch (value->dwValueType)
1198     {
1199     case CERT_RDN_NUMERIC_STRING:
1200         tag = ASN_NUMERICSTRING;
1201         encodedLen = value->Value.cbData;
1202         break;
1203     case CERT_RDN_PRINTABLE_STRING:
1204         tag = ASN_PRINTABLESTRING;
1205         encodedLen = value->Value.cbData;
1206         break;
1207     case CERT_RDN_IA5_STRING:
1208         tag = ASN_IA5STRING;
1209         encodedLen = value->Value.cbData;
1210         break;
1211     case CERT_RDN_ANY_TYPE:
1212         /* explicitly disallowed */
1213         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1214         return FALSE;
1215     default:
1216         FIXME("String type %ld unimplemented\n", value->dwValueType);
1217         return FALSE;
1218     }
1219     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1220     bytesNeeded = 1 + lenBytes + encodedLen;
1221     if (pbEncoded)
1222     {
1223         if (*pcbEncoded < bytesNeeded)
1224         {
1225             SetLastError(ERROR_MORE_DATA);
1226             ret = FALSE;
1227         }
1228         else
1229         {
1230             *pbEncoded++ = tag;
1231             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1232             pbEncoded += lenBytes;
1233             switch (value->dwValueType)
1234             {
1235             case CERT_RDN_NUMERIC_STRING:
1236             case CERT_RDN_PRINTABLE_STRING:
1237             case CERT_RDN_IA5_STRING:
1238                 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
1239             }
1240         }
1241     }
1242     *pcbEncoded = bytesNeeded;
1243     return ret;
1244 }
1245
1246 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1247  CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
1248 {
1249     DWORD bytesNeeded = 0, lenBytes, size;
1250     BOOL ret;
1251
1252     ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1253      0, NULL, NULL, &size);
1254     if (ret)
1255     {
1256         bytesNeeded += size;
1257         /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1258          * with dwValueType, so "cast" it to get its encoded size
1259          */
1260         ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1261          (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
1262         if (ret)
1263         {
1264             bytesNeeded += size;
1265             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1266             bytesNeeded += 1 + lenBytes;
1267             if (pbEncoded)
1268             {
1269                 if (*pcbEncoded < bytesNeeded)
1270                 {
1271                     SetLastError(ERROR_MORE_DATA);
1272                     ret = FALSE;
1273                 }
1274                 else
1275                 {
1276                     *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
1277                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1278                      &lenBytes);
1279                     pbEncoded += lenBytes;
1280                     size = bytesNeeded - 1 - lenBytes;
1281                     ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1282                      attr->pszObjId, 0, NULL, pbEncoded, &size);
1283                     if (ret)
1284                     {
1285                         pbEncoded += size;
1286                         size = bytesNeeded - 1 - lenBytes - size;
1287                         ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1288                          (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
1289                          &size);
1290                     }
1291                 }
1292             }
1293             *pcbEncoded = bytesNeeded;
1294         }
1295     }
1296     return ret;
1297 }
1298
1299 static int BLOBComp(const void *l, const void *r)
1300 {
1301     CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
1302     int ret;
1303
1304     if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1305         ret = a->cbData - b->cbData;
1306     return ret;
1307 }
1308
1309 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1310  */
1311 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1312  BYTE *pbEncoded, DWORD *pcbEncoded)
1313 {
1314     BOOL ret;
1315     CRYPT_DER_BLOB *blobs = NULL;
1316
1317     __TRY
1318     {
1319         DWORD bytesNeeded = 0, lenBytes, i;
1320
1321         blobs = NULL;
1322         ret = TRUE;
1323         if (rdn->cRDNAttr)
1324         {
1325             blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1326              rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1327             if (!blobs)
1328                 ret = FALSE;
1329         }
1330         for (i = 0; ret && i < rdn->cRDNAttr; i++)
1331         {
1332             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1333              NULL, &blobs[i].cbData);
1334             if (ret)
1335                 bytesNeeded += blobs[i].cbData;
1336         }
1337         if (ret)
1338         {
1339             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1340             bytesNeeded += 1 + lenBytes;
1341             if (pbEncoded)
1342             {
1343                 if (*pcbEncoded < bytesNeeded)
1344                 {
1345                     SetLastError(ERROR_MORE_DATA);
1346                     ret = FALSE;
1347                 }
1348                 else
1349                 {
1350                     for (i = 0; ret && i < rdn->cRDNAttr; i++)
1351                     {
1352                         blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
1353                          blobs[i].cbData);
1354                         if (!blobs[i].pbData)
1355                             ret = FALSE;
1356                         else
1357                             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1358                              &rdn->rgRDNAttr[i], blobs[i].pbData,
1359                              &blobs[i].cbData);
1360                     }
1361                     if (ret)
1362                     {
1363                         qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1364                          BLOBComp);
1365                         *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1366                         CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1367                          &lenBytes);
1368                         pbEncoded += lenBytes;
1369                         for (i = 0; ret && i < rdn->cRDNAttr; i++)
1370                         {
1371                             memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1372                             pbEncoded += blobs[i].cbData;
1373                         }
1374                     }
1375                 }
1376             }
1377             *pcbEncoded = bytesNeeded;
1378         }
1379         if (blobs)
1380         {
1381             for (i = 0; i < rdn->cRDNAttr; i++)
1382                 HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
1383         }
1384     }
1385     __EXCEPT(page_fault)
1386     {
1387         SetLastError(STATUS_ACCESS_VIOLATION);
1388         return FALSE;
1389     }
1390     __ENDTRY
1391     HeapFree(GetProcessHeap(), 0, blobs);
1392     return ret;
1393 }
1394
1395 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1396  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1397  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1398 {
1399     BOOL ret;
1400
1401     __TRY
1402     {
1403         const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1404         DWORD bytesNeeded = 0, lenBytes, size, i;
1405
1406         TRACE("encoding name with %ld RDNs\n", info->cRDN);
1407         ret = TRUE;
1408         for (i = 0; ret && i < info->cRDN; i++)
1409         {
1410             ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1411              &size);
1412             if (ret)
1413                 bytesNeeded += size;
1414         }
1415         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1416         bytesNeeded += 1 + lenBytes;
1417         if (ret)
1418         {
1419             if (!pbEncoded)
1420                 *pcbEncoded = bytesNeeded;
1421             else
1422             {
1423                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1424                  pbEncoded, pcbEncoded, bytesNeeded)))
1425                 {
1426                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1427                         pbEncoded = *(BYTE **)pbEncoded;
1428                     *pbEncoded++ = ASN_SEQUENCEOF;
1429                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1430                      &lenBytes);
1431                     pbEncoded += lenBytes;
1432                     for (i = 0; ret && i < info->cRDN; i++)
1433                     {
1434                         size = bytesNeeded;
1435                         ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1436                          &info->rgRDN[i], pbEncoded, &size);
1437                         if (ret)
1438                         {
1439                             pbEncoded += size;
1440                             bytesNeeded -= size;
1441                         }
1442                     }
1443                 }
1444             }
1445         }
1446     }
1447     __EXCEPT(page_fault)
1448     {
1449         SetLastError(STATUS_ACCESS_VIOLATION);
1450         ret = FALSE;
1451     }
1452     __ENDTRY
1453     return ret;
1454 }
1455
1456 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1457  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1458  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1459 {
1460     BOOL val = *(const BOOL *)pvStructInfo, ret;
1461
1462     TRACE("%d\n", val);
1463
1464     if (!pbEncoded)
1465     {
1466         *pcbEncoded = 3;
1467         ret = TRUE;
1468     }
1469     else if (*pcbEncoded < 3)
1470     {
1471         *pcbEncoded = 3;
1472         SetLastError(ERROR_MORE_DATA);
1473         ret = FALSE;
1474     }
1475     else
1476     {
1477         *pcbEncoded = 3;
1478         *pbEncoded++ = ASN_BOOL;
1479         *pbEncoded++ = 1;
1480         *pbEncoded++ = val ? 0xff : 0;
1481         ret = TRUE;
1482     }
1483     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1484     return ret;
1485 }
1486
1487 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1488  BYTE *pbEncoded, DWORD *pcbEncoded)
1489 {
1490     BOOL ret;
1491     DWORD dataLen;
1492
1493     ret = TRUE;
1494     switch (entry->dwAltNameChoice)
1495     {
1496     case CERT_ALT_NAME_RFC822_NAME:
1497     case CERT_ALT_NAME_DNS_NAME:
1498     case CERT_ALT_NAME_URL:
1499         if (entry->u.pwszURL)
1500         {
1501             DWORD i;
1502
1503             /* Not + 1: don't encode the NULL-terminator */
1504             dataLen = lstrlenW(entry->u.pwszURL);
1505             for (i = 0; ret && i < dataLen; i++)
1506             {
1507                 if (entry->u.pwszURL[i] > 0x7f)
1508                 {
1509                     SetLastError(CRYPT_E_INVALID_IA5_STRING);
1510                     ret = FALSE;
1511                     *pcbEncoded = i;
1512                 }
1513             }
1514         }
1515         else
1516             dataLen = 0;
1517         break;
1518     case CERT_ALT_NAME_IP_ADDRESS:
1519         dataLen = entry->u.IPAddress.cbData;
1520         break;
1521     case CERT_ALT_NAME_REGISTERED_ID:
1522         /* FIXME: encode OID */
1523     case CERT_ALT_NAME_OTHER_NAME:
1524     case CERT_ALT_NAME_DIRECTORY_NAME:
1525         FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice);
1526         return FALSE;
1527     default:
1528         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1529         return FALSE;
1530     }
1531     if (ret)
1532     {
1533         DWORD bytesNeeded, lenBytes;
1534
1535         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1536         bytesNeeded = 1 + dataLen + lenBytes;
1537         if (!pbEncoded)
1538             *pcbEncoded = bytesNeeded;
1539         else if (*pcbEncoded < bytesNeeded)
1540         {
1541             SetLastError(ERROR_MORE_DATA);
1542             *pcbEncoded = bytesNeeded;
1543             ret = FALSE;
1544         }
1545         else
1546         {
1547             *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1548             CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1549             pbEncoded += lenBytes;
1550             switch (entry->dwAltNameChoice)
1551             {
1552             case CERT_ALT_NAME_RFC822_NAME:
1553             case CERT_ALT_NAME_DNS_NAME:
1554             case CERT_ALT_NAME_URL:
1555             {
1556                 DWORD i;
1557
1558                 for (i = 0; i < dataLen; i++)
1559                     *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1560                 break;
1561             }
1562             case CERT_ALT_NAME_IP_ADDRESS:
1563                 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1564                 break;
1565             }
1566             if (ret)
1567                 *pcbEncoded = bytesNeeded;
1568         }
1569     }
1570     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1571     return ret;
1572 }
1573
1574 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1575  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1576  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1577 {
1578     BOOL ret;
1579
1580     __TRY
1581     {
1582         const CERT_ALT_NAME_INFO *info =
1583          (const CERT_ALT_NAME_INFO *)pvStructInfo;
1584
1585         DWORD bytesNeeded, dataLen, lenBytes, i;
1586
1587         ret = TRUE;
1588         /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1589          * can't encode an erroneous entry index if it's bigger than this.
1590          */
1591         for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1592         {
1593             DWORD len;
1594
1595             ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1596              &len);
1597             if (ret)
1598                 dataLen += len;
1599             else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1600             {
1601                 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1602                  * the bad character, now set the index of the bad
1603                  * entry
1604                  */
1605                 *pcbEncoded = (BYTE)i <<
1606                  CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1607             }
1608         }
1609         if (ret)
1610         {
1611             CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1612             bytesNeeded = 1 + lenBytes + dataLen;
1613             if (!pbEncoded)
1614             {
1615                 *pcbEncoded = bytesNeeded;
1616                 ret = TRUE;
1617             }
1618             else
1619             {
1620                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1621                  pbEncoded, pcbEncoded, bytesNeeded)))
1622                 {
1623                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1624                         pbEncoded = *(BYTE **)pbEncoded;
1625                     *pbEncoded++ = ASN_SEQUENCEOF;
1626                     CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1627                     pbEncoded += lenBytes;
1628                     for (i = 0; ret && i < info->cAltEntry; i++)
1629                     {
1630                         DWORD len = dataLen;
1631
1632                         ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1633                          pbEncoded, &len);
1634                         if (ret)
1635                         {
1636                             pbEncoded += len;
1637                             dataLen -= len;
1638                         }
1639                     }
1640                 }
1641             }
1642         }
1643     }
1644     __EXCEPT(page_fault)
1645     {
1646         SetLastError(STATUS_ACCESS_VIOLATION);
1647         ret = FALSE;
1648     }
1649     __ENDTRY
1650     return ret;
1651 }
1652
1653 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1654  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1655  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1656 {
1657     BOOL ret;
1658
1659     __TRY
1660     {
1661         const CERT_BASIC_CONSTRAINTS2_INFO *info =
1662          (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1663         struct AsnEncodeSequenceItem items[2] = { { 0 } };
1664         DWORD cItem = 0;
1665
1666         if (info->fCA)
1667         {
1668             items[cItem].pvStructInfo = &info->fCA;
1669             items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1670             cItem++;
1671         }
1672         if (info->fPathLenConstraint)
1673         {
1674             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1675             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1676             cItem++;
1677         }
1678         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1679          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1680     }
1681     __EXCEPT(page_fault)
1682     {
1683         SetLastError(STATUS_ACCESS_VIOLATION);
1684         ret = FALSE;
1685     }
1686     __ENDTRY
1687     return ret;
1688 }
1689
1690 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
1691  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1692  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1693 {
1694     BOOL ret;
1695
1696     __TRY
1697     {
1698         const BLOBHEADER *hdr =
1699          (const BLOBHEADER *)pvStructInfo;
1700
1701         if (hdr->bType != PUBLICKEYBLOB)
1702         {
1703             SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1704             ret = FALSE;
1705         }
1706         else
1707         {
1708             const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
1709              ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
1710             CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
1711              (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
1712             struct AsnEncodeSequenceItem items[] = { 
1713              { &blob, CRYPT_AsnEncodeInteger, 0 },
1714              { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
1715             };
1716
1717             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1718              sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1719              pcbEncoded);
1720         }
1721     }
1722     __EXCEPT(page_fault)
1723     {
1724         SetLastError(STATUS_ACCESS_VIOLATION);
1725         ret = FALSE;
1726     }
1727     __ENDTRY
1728     return ret;
1729 }
1730
1731 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1732  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1733  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1734 {
1735     BOOL ret;
1736
1737     __TRY
1738     {
1739         const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1740         DWORD bytesNeeded, lenBytes;
1741
1742         TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1743          dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1744
1745         CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1746         bytesNeeded = 1 + lenBytes + blob->cbData;
1747         if (!pbEncoded)
1748         {
1749             *pcbEncoded = bytesNeeded;
1750             ret = TRUE;
1751         }
1752         else
1753         {
1754             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1755              pcbEncoded, bytesNeeded)))
1756             {
1757                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1758                     pbEncoded = *(BYTE **)pbEncoded;
1759                 *pbEncoded++ = ASN_OCTETSTRING;
1760                 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1761                 pbEncoded += lenBytes;
1762                 if (blob->cbData)
1763                     memcpy(pbEncoded, blob->pbData, blob->cbData);
1764             }
1765         }
1766     }
1767     __EXCEPT(page_fault)
1768     {
1769         SetLastError(STATUS_ACCESS_VIOLATION);
1770         ret = FALSE;
1771     }
1772     __ENDTRY
1773     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1774     return ret;
1775 }
1776
1777 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1778  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1779  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1780 {
1781     BOOL ret;
1782
1783     __TRY
1784     {
1785         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1786         DWORD bytesNeeded, lenBytes, dataBytes;
1787         BYTE unusedBits;
1788
1789         /* yep, MS allows cUnusedBits to be >= 8 */
1790         if (!blob->cUnusedBits)
1791         {
1792             dataBytes = blob->cbData;
1793             unusedBits = 0;
1794         }
1795         else if (blob->cbData * 8 > blob->cUnusedBits)
1796         {
1797             dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1798             unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1799              blob->cUnusedBits;
1800         }
1801         else
1802         {
1803             dataBytes = 0;
1804             unusedBits = 0;
1805         }
1806         CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1807         bytesNeeded = 1 + lenBytes + dataBytes + 1;
1808         if (!pbEncoded)
1809         {
1810             *pcbEncoded = bytesNeeded;
1811             ret = TRUE;
1812         }
1813         else
1814         {
1815             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1816              pcbEncoded, bytesNeeded)))
1817             {
1818                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1819                     pbEncoded = *(BYTE **)pbEncoded;
1820                 *pbEncoded++ = ASN_BITSTRING;
1821                 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1822                 pbEncoded += lenBytes;
1823                 *pbEncoded++ = unusedBits;
1824                 if (dataBytes)
1825                 {
1826                     BYTE mask = 0xff << unusedBits;
1827
1828                     if (dataBytes > 1)
1829                     {
1830                         memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1831                         pbEncoded += dataBytes - 1;
1832                     }
1833                     *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1834                 }
1835             }
1836         }
1837     }
1838     __EXCEPT(page_fault)
1839     {
1840         SetLastError(STATUS_ACCESS_VIOLATION);
1841         ret = FALSE;
1842     }
1843     __ENDTRY
1844     return ret;
1845 }
1846
1847 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
1848  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1849  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1850 {
1851     BOOL ret;
1852
1853     __TRY
1854     {
1855         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1856         CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
1857
1858         ret = TRUE;
1859         if (newBlob.cbData)
1860         {
1861             newBlob.pbData = HeapAlloc(GetProcessHeap(), 0, newBlob.cbData);
1862             if (newBlob.pbData)
1863             {
1864                 DWORD i;
1865
1866                 for (i = 0; i < newBlob.cbData; i++)
1867                     newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
1868             }
1869             else
1870                 ret = FALSE;
1871         }
1872         if (ret)
1873             ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
1874              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1875         HeapFree(GetProcessHeap(), 0, newBlob.pbData);
1876     }
1877     __EXCEPT(page_fault)
1878     {
1879         SetLastError(STATUS_ACCESS_VIOLATION);
1880         ret = FALSE;
1881     }
1882     __ENDTRY
1883     return ret;
1884 }
1885
1886 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1887  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1888  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1889 {
1890     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1891
1892     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1893      &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1894 }
1895
1896 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1897  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1898  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1899 {
1900     BOOL ret;
1901
1902     __TRY
1903     {
1904         DWORD significantBytes, lenBytes;
1905         BYTE padByte = 0, bytesNeeded;
1906         BOOL pad = FALSE;
1907         const CRYPT_INTEGER_BLOB *blob =
1908          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1909
1910         significantBytes = blob->cbData;
1911         if (significantBytes)
1912         {
1913             if (blob->pbData[significantBytes - 1] & 0x80)
1914             {
1915                 /* negative, lop off leading (little-endian) 0xffs */
1916                 for (; significantBytes > 0 &&
1917                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1918                     ;
1919                 if (blob->pbData[significantBytes - 1] < 0x80)
1920                 {
1921                     padByte = 0xff;
1922                     pad = TRUE;
1923                 }
1924             }
1925             else
1926             {
1927                 /* positive, lop off leading (little-endian) zeroes */
1928                 for (; significantBytes > 0 &&
1929                  !blob->pbData[significantBytes - 1]; significantBytes--)
1930                     ;
1931                 if (significantBytes == 0)
1932                     significantBytes = 1;
1933                 if (blob->pbData[significantBytes - 1] > 0x7f)
1934                 {
1935                     padByte = 0;
1936                     pad = TRUE;
1937                 }
1938             }
1939         }
1940         if (pad)
1941             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1942         else
1943             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1944         bytesNeeded = 1 + lenBytes + significantBytes;
1945         if (pad)
1946             bytesNeeded++;
1947         if (!pbEncoded)
1948         {
1949             *pcbEncoded = bytesNeeded;
1950             ret = TRUE;
1951         }
1952         else
1953         {
1954             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1955              pcbEncoded, bytesNeeded)))
1956             {
1957                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1958                     pbEncoded = *(BYTE **)pbEncoded;
1959                 *pbEncoded++ = ASN_INTEGER;
1960                 if (pad)
1961                 {
1962                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1963                     pbEncoded += lenBytes;
1964                     *pbEncoded++ = padByte;
1965                 }
1966                 else
1967                 {
1968                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1969                     pbEncoded += lenBytes;
1970                 }
1971                 for (; significantBytes > 0; significantBytes--)
1972                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
1973             }
1974         }
1975     }
1976     __EXCEPT(page_fault)
1977     {
1978         SetLastError(STATUS_ACCESS_VIOLATION);
1979         ret = FALSE;
1980     }
1981     __ENDTRY
1982     return ret;
1983 }
1984
1985 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1986  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1987  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1988 {
1989     BOOL ret;
1990
1991     __TRY
1992     {
1993         DWORD significantBytes, lenBytes;
1994         BYTE bytesNeeded;
1995         BOOL pad = FALSE;
1996         const CRYPT_INTEGER_BLOB *blob =
1997          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1998
1999         significantBytes = blob->cbData;
2000         if (significantBytes)
2001         {
2002             /* positive, lop off leading (little-endian) zeroes */
2003             for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2004              significantBytes--)
2005                 ;
2006             if (significantBytes == 0)
2007                 significantBytes = 1;
2008             if (blob->pbData[significantBytes - 1] > 0x7f)
2009                 pad = TRUE;
2010         }
2011         if (pad)
2012             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2013         else
2014             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2015         bytesNeeded = 1 + lenBytes + significantBytes;
2016         if (pad)
2017             bytesNeeded++;
2018         if (!pbEncoded)
2019         {
2020             *pcbEncoded = bytesNeeded;
2021             ret = TRUE;
2022         }
2023         else
2024         {
2025             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2026              pcbEncoded, bytesNeeded)))
2027             {
2028                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2029                     pbEncoded = *(BYTE **)pbEncoded;
2030                 *pbEncoded++ = ASN_INTEGER;
2031                 if (pad)
2032                 {
2033                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2034                     pbEncoded += lenBytes;
2035                     *pbEncoded++ = 0;
2036                 }
2037                 else
2038                 {
2039                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2040                     pbEncoded += lenBytes;
2041                 }
2042                 for (; significantBytes > 0; significantBytes--)
2043                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
2044             }
2045         }
2046     }
2047     __EXCEPT(page_fault)
2048     {
2049         SetLastError(STATUS_ACCESS_VIOLATION);
2050         ret = FALSE;
2051     }
2052     __ENDTRY
2053     return ret;
2054 }
2055
2056 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2057  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2058  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2059 {
2060     CRYPT_INTEGER_BLOB blob;
2061     BOOL ret;
2062
2063     /* Encode as an unsigned integer, then change the tag to enumerated */
2064     blob.cbData = sizeof(DWORD);
2065     blob.pbData = (BYTE *)pvStructInfo;
2066     ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2067      X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2068     if (ret && pbEncoded)
2069     {
2070         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2071             pbEncoded = *(BYTE **)pbEncoded;
2072         pbEncoded[0] = ASN_ENUMERATED;
2073     }
2074     return ret;
2075 }
2076
2077 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2078  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2079  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2080 {
2081     BOOL ret;
2082
2083     __TRY
2084     {
2085         SYSTEMTIME sysTime;
2086         /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
2087          * temporary buffer because the output buffer is not NULL-terminated.
2088          */
2089         char buf[16];
2090         static const DWORD bytesNeeded = sizeof(buf) - 1;
2091
2092         if (!pbEncoded)
2093         {
2094             *pcbEncoded = bytesNeeded;
2095             ret = TRUE;
2096         }
2097         else
2098         {
2099             /* Sanity check the year, this is a two-digit year format */
2100             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2101              &sysTime);
2102             if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2103             {
2104                 SetLastError(CRYPT_E_BAD_ENCODE);
2105                 ret = FALSE;
2106             }
2107             if (ret)
2108             {
2109                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2110                  pbEncoded, pcbEncoded, bytesNeeded)))
2111                 {
2112                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2113                         pbEncoded = *(BYTE **)pbEncoded;
2114                     buf[0] = ASN_UTCTIME;
2115                     buf[1] = bytesNeeded - 2;
2116                     snprintf(buf + 2, sizeof(buf) - 2,
2117                      "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2118                      sysTime.wYear - 2000 : sysTime.wYear - 1900,
2119                      sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2120                      sysTime.wMinute, sysTime.wSecond);
2121                     memcpy(pbEncoded, buf, bytesNeeded);
2122                 }
2123             }
2124         }
2125     }
2126     __EXCEPT(page_fault)
2127     {
2128         SetLastError(STATUS_ACCESS_VIOLATION);
2129         ret = FALSE;
2130     }
2131     __ENDTRY
2132     return ret;
2133 }
2134
2135 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2136  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2137  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2138 {
2139     BOOL ret;
2140
2141     __TRY
2142     {
2143         SYSTEMTIME sysTime;
2144         /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
2145          * temporary buffer because the output buffer is not NULL-terminated.
2146          */
2147         char buf[18];
2148         static const DWORD bytesNeeded = sizeof(buf) - 1;
2149
2150         if (!pbEncoded)
2151         {
2152             *pcbEncoded = bytesNeeded;
2153             ret = TRUE;
2154         }
2155         else
2156         {
2157             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2158              &sysTime);
2159             if (ret)
2160                 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2161                  pcbEncoded, bytesNeeded);
2162             if (ret)
2163             {
2164                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2165                     pbEncoded = *(BYTE **)pbEncoded;
2166                 buf[0] = ASN_GENERALTIME;
2167                 buf[1] = bytesNeeded - 2;
2168                 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2169                  sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2170                  sysTime.wMinute, sysTime.wSecond);
2171                 memcpy(pbEncoded, buf, bytesNeeded);
2172             }
2173         }
2174     }
2175     __EXCEPT(page_fault)
2176     {
2177         SetLastError(STATUS_ACCESS_VIOLATION);
2178         ret = FALSE;
2179     }
2180     __ENDTRY
2181     return ret;
2182 }
2183
2184 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2185  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2186  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2187 {
2188     BOOL ret;
2189
2190     __TRY
2191     {
2192         SYSTEMTIME sysTime;
2193
2194         /* Check the year, if it's in the UTCTime range call that encode func */
2195         if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2196             return FALSE;
2197         if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2198             ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2199              pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2200         else
2201             ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2202              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2203              pcbEncoded);
2204     }
2205     __EXCEPT(page_fault)
2206     {
2207         SetLastError(STATUS_ACCESS_VIOLATION);
2208         ret = FALSE;
2209     }
2210     __ENDTRY
2211     return ret;
2212 }
2213
2214 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2215  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2216  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2217 {
2218     BOOL ret;
2219
2220     __TRY
2221     {
2222         DWORD bytesNeeded, dataLen, lenBytes, i;
2223         const CRYPT_SEQUENCE_OF_ANY *seq =
2224          (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2225
2226         for (i = 0, dataLen = 0; i < seq->cValue; i++)
2227             dataLen += seq->rgValue[i].cbData;
2228         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2229         bytesNeeded = 1 + lenBytes + dataLen;
2230         if (!pbEncoded)
2231         {
2232             *pcbEncoded = bytesNeeded;
2233             ret = TRUE;
2234         }
2235         else
2236         {
2237             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2238              pcbEncoded, bytesNeeded)))
2239             {
2240                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2241                     pbEncoded = *(BYTE **)pbEncoded;
2242                 *pbEncoded++ = ASN_SEQUENCEOF;
2243                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2244                 pbEncoded += lenBytes;
2245                 for (i = 0; i < seq->cValue; i++)
2246                 {
2247                     memcpy(pbEncoded, seq->rgValue[i].pbData,
2248                      seq->rgValue[i].cbData);
2249                     pbEncoded += seq->rgValue[i].cbData;
2250                 }
2251             }
2252         }
2253     }
2254     __EXCEPT(page_fault)
2255     {
2256         SetLastError(STATUS_ACCESS_VIOLATION);
2257         ret = FALSE;
2258     }
2259     __ENDTRY
2260     return ret;
2261 }
2262
2263 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2264  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2265  void *pvEncoded, DWORD *pcbEncoded)
2266 {
2267     BOOL ret = FALSE;
2268     HMODULE lib = NULL;
2269     CryptEncodeObjectExFunc encodeFunc = NULL;
2270
2271     TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2272      debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2273      pvEncoded, pcbEncoded);
2274
2275     if (!pvEncoded && !pcbEncoded)
2276     {
2277         SetLastError(ERROR_INVALID_PARAMETER);
2278         return FALSE;
2279     }
2280     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2281      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2282     {
2283         SetLastError(ERROR_FILE_NOT_FOUND);
2284         return FALSE;
2285     }
2286
2287     SetLastError(NOERROR);
2288     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2289         *(BYTE **)pvEncoded = NULL;
2290     if (!HIWORD(lpszStructType))
2291     {
2292         switch (LOWORD(lpszStructType))
2293         {
2294         case (WORD)X509_CERT:
2295             encodeFunc = CRYPT_AsnEncodeCert;
2296             break;
2297         case (WORD)X509_CERT_TO_BE_SIGNED:
2298             encodeFunc = CRYPT_AsnEncodeCertInfo;
2299             break;
2300         case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2301             encodeFunc = CRYPT_AsnEncodeCRLInfo;
2302             break;
2303         case (WORD)X509_EXTENSIONS:
2304             encodeFunc = CRYPT_AsnEncodeExtensions;
2305             break;
2306         case (WORD)X509_NAME:
2307             encodeFunc = CRYPT_AsnEncodeName;
2308             break;
2309         case (WORD)X509_PUBLIC_KEY_INFO:
2310             encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2311             break;
2312         case (WORD)X509_ALTERNATE_NAME:
2313             encodeFunc = CRYPT_AsnEncodeAltName;
2314             break;
2315         case (WORD)X509_BASIC_CONSTRAINTS2:
2316             encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2317             break;
2318         case (WORD)RSA_CSP_PUBLICKEYBLOB:
2319             encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2320             break;
2321         case (WORD)X509_OCTET_STRING:
2322             encodeFunc = CRYPT_AsnEncodeOctets;
2323             break;
2324         case (WORD)X509_BITS:
2325         case (WORD)X509_KEY_USAGE:
2326             encodeFunc = CRYPT_AsnEncodeBits;
2327             break;
2328         case (WORD)X509_INTEGER:
2329             encodeFunc = CRYPT_AsnEncodeInt;
2330             break;
2331         case (WORD)X509_MULTI_BYTE_INTEGER:
2332             encodeFunc = CRYPT_AsnEncodeInteger;
2333             break;
2334         case (WORD)X509_MULTI_BYTE_UINT:
2335             encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2336             break;
2337         case (WORD)X509_ENUMERATED:
2338             encodeFunc = CRYPT_AsnEncodeEnumerated;
2339             break;
2340         case (WORD)X509_CHOICE_OF_TIME:
2341             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2342             break;
2343         case (WORD)X509_SEQUENCE_OF_ANY:
2344             encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2345             break;
2346         case (WORD)PKCS_UTC_TIME:
2347             encodeFunc = CRYPT_AsnEncodeUtcTime;
2348             break;
2349         default:
2350             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2351         }
2352     }
2353     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2354         encodeFunc = CRYPT_AsnEncodeExtensions;
2355     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2356         encodeFunc = CRYPT_AsnEncodeUtcTime;
2357     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2358         encodeFunc = CRYPT_AsnEncodeEnumerated;
2359     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2360         encodeFunc = CRYPT_AsnEncodeBits;
2361     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2362         encodeFunc = CRYPT_AsnEncodeOctets;
2363     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2364         encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2365     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2366         encodeFunc = CRYPT_AsnEncodeAltName;
2367     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2368         encodeFunc = CRYPT_AsnEncodeAltName;
2369     else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2370         encodeFunc = CRYPT_AsnEncodeAltName;
2371     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2372         encodeFunc = CRYPT_AsnEncodeAltName;
2373     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2374         encodeFunc = CRYPT_AsnEncodeAltName;
2375     else
2376         TRACE("OID %s not found or unimplemented, looking for DLL\n",
2377          debugstr_a(lpszStructType));
2378     if (!encodeFunc)
2379         encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
2380          lpszStructType, "CryptEncodeObjectEx", &lib);
2381     if (encodeFunc)
2382         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2383          dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2384     else
2385         SetLastError(ERROR_FILE_NOT_FOUND);
2386     if (lib)
2387         FreeLibrary(lib);
2388     return ret;
2389 }
2390
2391 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2392  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
2393  DWORD *pcbStructInfo)
2394 {
2395     BOOL ret = FALSE;
2396     HMODULE lib;
2397     CryptDecodeObjectFunc pCryptDecodeObject;
2398
2399     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType,
2400      debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
2401      pvStructInfo, pcbStructInfo);
2402
2403     if (!pvStructInfo && !pcbStructInfo)
2404     {
2405         SetLastError(ERROR_INVALID_PARAMETER);
2406         return FALSE;
2407     }
2408
2409     /* Try registered DLL first.. */
2410     pCryptDecodeObject =
2411      (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
2412      lpszStructType, "CryptDecodeObject", &lib);
2413     if (pCryptDecodeObject)
2414     {
2415         ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
2416          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
2417         FreeLibrary(lib);
2418     }
2419     else
2420     {
2421         /* If not, use CryptDecodeObjectEx */
2422         ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
2423          cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
2424     }
2425     return ret;
2426 }
2427
2428 /* Gets the number of length bytes from the given (leading) length byte */
2429 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
2430
2431 /* Helper function to get the encoded length of the data starting at pbEncoded,
2432  * where pbEncoded[0] is the tag.  If the data are too short to contain a
2433  * length or if the length is too large for cbEncoded, sets an appropriate
2434  * error code and returns FALSE.
2435  */
2436 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
2437  DWORD *len)
2438 {
2439     BOOL ret;
2440
2441     if (cbEncoded <= 1)
2442     {
2443         SetLastError(CRYPT_E_ASN1_CORRUPT);
2444         ret = FALSE;
2445     }
2446     else if (pbEncoded[1] <= 0x7f)
2447     {
2448         if (pbEncoded[1] + 1 > cbEncoded)
2449         {
2450             SetLastError(CRYPT_E_ASN1_EOD);
2451             ret = FALSE;
2452         }
2453         else
2454         {
2455             *len = pbEncoded[1];
2456             ret = TRUE;
2457         }
2458     }
2459     else
2460     {
2461         BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
2462
2463         if (lenLen > sizeof(DWORD) + 1)
2464         {
2465             SetLastError(CRYPT_E_ASN1_LARGE);
2466             ret = FALSE;
2467         }
2468         else if (lenLen + 2 > cbEncoded)
2469         {
2470             SetLastError(CRYPT_E_ASN1_CORRUPT);
2471             ret = FALSE;
2472         }
2473         else
2474         {
2475             DWORD out = 0;
2476
2477             pbEncoded += 2;
2478             while (--lenLen)
2479             {
2480                 out <<= 8;
2481                 out |= *pbEncoded++;
2482             }
2483             if (out + lenLen + 1 > cbEncoded)
2484             {
2485                 SetLastError(CRYPT_E_ASN1_EOD);
2486                 ret = FALSE;
2487             }
2488             else
2489             {
2490                 *len = out;
2491                 ret = TRUE;
2492             }
2493         }
2494     }
2495     return ret;
2496 }
2497
2498 /* Helper function to check *pcbStructInfo, set it to the required size, and
2499  * optionally to allocate memory.  Assumes pvStructInfo is not NULL.
2500  * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
2501  * pointer to the newly allocated memory.
2502  */
2503 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
2504  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2505  DWORD bytesNeeded)
2506 {
2507     BOOL ret = TRUE;
2508
2509     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2510     {
2511         if (pDecodePara && pDecodePara->pfnAlloc)
2512             *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
2513         else
2514             *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
2515         if (!*(BYTE **)pvStructInfo)
2516             ret = FALSE;
2517         else
2518             *pcbStructInfo = bytesNeeded;
2519     }
2520     else if (*pcbStructInfo < bytesNeeded)
2521     {
2522         *pcbStructInfo = bytesNeeded;
2523         SetLastError(ERROR_MORE_DATA);
2524         ret = FALSE;
2525     }
2526     return ret;
2527 }
2528
2529 /* A few of the members need explanation:
2530  * offset:
2531  *     A sequence is decoded into a struct.  The offset member is the
2532  *     offset of this item within that struct.
2533  * decodeFunc:
2534  *     The decoder function to use.  If this is NULL, then the member isn't
2535  *     decoded, but minSize space is reserved for it.
2536  * minSize:
2537  *     The minimum amount of space occupied after decoding.  You must set this.
2538  * optional:
2539  *     If true, and a decoding function fails with CRYPT_E_ASN1_BADTAG, then
2540  *     minSize space is filled with 0 for this member.  (Any other failure
2541  *     results in CRYPT_AsnDecodeSequence failing.)
2542  * hasPointer, pointerOffset, minSize:
2543  *     If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
2544  *     the offset within the (outer) struct of the data pointer (or to the
2545  *     first data pointer, if more than one exist).
2546  * size:
2547  *     Used by CRYPT_AsnDecodeSequence, not for your use.
2548  */
2549 struct AsnDecodeSequenceItem
2550 {
2551     DWORD                   offset;
2552     CryptDecodeObjectExFunc decodeFunc;
2553     DWORD                   minSize;
2554     BOOL                    optional;
2555     BOOL                    hasPointer;
2556     DWORD                   pointerOffset;
2557     DWORD                   size;
2558 };
2559
2560 /* This decodes an arbitrary sequence into a contiguous block of memory
2561  * (basically, a struct.)  Each element being decoded is described by a struct
2562  * AsnDecodeSequenceItem, see above.
2563  * startingPointer is an optional pointer to the first place where dynamic
2564  * data will be stored.  If you know the starting offset, you may pass it
2565  * here.  Otherwise, pass NULL, and one will be inferred from the items.
2566  * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
2567  * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
2568  */
2569 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
2570  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2571  DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
2572  void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer)
2573 {
2574     BOOL ret;
2575
2576     TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld, %p\n", items, cItem, pbEncoded,
2577      cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
2578      startingPointer);
2579
2580     if (pbEncoded[0] == ASN_SEQUENCE)
2581     {
2582         DWORD dataLen;
2583
2584         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2585         {
2586             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2587             DWORD i, bytesNeeded = 0, minSize = 0;
2588             const BYTE *ptr;
2589
2590             ptr = pbEncoded + 1 + lenBytes;
2591             for (i = 0; ret && i < cItem; i++)
2592             {
2593                 DWORD nextItemLen;
2594
2595                 minSize += items[i].minSize;
2596                 if (cbEncoded - (ptr - pbEncoded) != 0)
2597                 {
2598                     if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2599                      &nextItemLen)))
2600                     {
2601                         BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2602
2603                         if (items[i].decodeFunc)
2604                         {
2605                             TRACE("sizing item %ld\n", i);
2606                             ret = items[i].decodeFunc(dwCertEncodingType, NULL,
2607                              ptr, 1 + nextItemLenBytes + nextItemLen,
2608                              dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
2609                              &items[i].size);
2610                             if (ret)
2611                             {
2612                                 /* Account for alignment padding */
2613                                 bytesNeeded += items[i].size;
2614                                 if (items[i].size % sizeof(DWORD))
2615                                     bytesNeeded += sizeof(DWORD) -
2616                                      items[i].size % sizeof(DWORD);
2617                                 ptr += 1 + nextItemLenBytes + nextItemLen;
2618                             }
2619                             else if (items[i].optional &&
2620                              GetLastError() == CRYPT_E_ASN1_BADTAG)
2621                             {
2622                                 TRACE("skipping optional item %ld\n", i);
2623                                 bytesNeeded += items[i].minSize;
2624                                 SetLastError(NOERROR);
2625                                 ret = TRUE;
2626                             }
2627                             else
2628                                 TRACE("item %ld failed: %08lx\n", i,
2629                                  GetLastError());
2630                         }
2631                         else
2632                             bytesNeeded += items[i].minSize;
2633                     }
2634                 }
2635                 else if (items[i].optional)
2636                     bytesNeeded += items[i].minSize;
2637                 else
2638                 {
2639                     SetLastError(CRYPT_E_ASN1_CORRUPT);
2640                     ret = FALSE;
2641                 }
2642             }
2643             if (cbEncoded - (ptr - pbEncoded) != 0)
2644             {
2645                 TRACE("%ld remaining bytes, failing\n", cbEncoded -
2646                  (ptr - pbEncoded));
2647                 SetLastError(CRYPT_E_ASN1_CORRUPT);
2648                 ret = FALSE;
2649             }
2650             if (ret)
2651             {
2652                 if (!pvStructInfo)
2653                     *pcbStructInfo = bytesNeeded;
2654                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2655                  pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2656                 {
2657                     BYTE *nextData;
2658
2659                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2660                         pvStructInfo = *(BYTE **)pvStructInfo;
2661                     if (startingPointer)
2662                         nextData = (BYTE *)startingPointer;
2663                     else
2664                         nextData = (BYTE *)pvStructInfo + minSize;
2665                     memset(pvStructInfo, 0, minSize);
2666                     ptr = pbEncoded + 1 + lenBytes;
2667                     for (i = 0; ret && i < cItem; i++)
2668                     {
2669                         if (cbEncoded - (ptr - pbEncoded) != 0)
2670                         {
2671                             DWORD nextItemLen;
2672                             BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2673
2674                             CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2675                              &nextItemLen);
2676                             if (items[i].hasPointer)
2677                             {
2678                                 *(BYTE **)((BYTE *)pvStructInfo +
2679                                  items[i].pointerOffset) = nextData;
2680                             }
2681                             if (items[i].decodeFunc)
2682                             {
2683                                 TRACE("decoding item %ld\n", i);
2684                                 ret = items[i].decodeFunc(dwCertEncodingType,
2685                                  NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
2686                                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2687                                  (BYTE *)pvStructInfo + items[i].offset,
2688                                  &items[i].size);
2689                                 if (!ret)
2690                                     TRACE("item %ld failed: %08lx\n", i,
2691                                      GetLastError());
2692                             }
2693                             else
2694                                 items[i].size = items[i].minSize;
2695                             if (ret)
2696                             {
2697                                 if (items[i].hasPointer &&
2698                                  items[i].size > items[i].minSize)
2699                                 {
2700                                     nextData += items[i].size -
2701                                      items[i].minSize;
2702                                     /* align nextData to DWORD boundaries */
2703                                     if (items[i].size % sizeof(DWORD))
2704                                     {
2705                                         nextData += sizeof(DWORD) -
2706                                          items[i].size % sizeof(DWORD);
2707                                     }
2708                                 }
2709                                 ptr += 1 + nextItemLenBytes + nextItemLen;
2710                             }
2711                             else if (items[i].optional &&
2712                              GetLastError() == CRYPT_E_ASN1_BADTAG)
2713                             {
2714                                 SetLastError(NOERROR);
2715                                 ret = TRUE;
2716                             }
2717                         }
2718                         else if (!items[i].optional)
2719                         {
2720                             SetLastError(CRYPT_E_ASN1_CORRUPT);
2721                             ret = FALSE;
2722                         }
2723                     }
2724                 }
2725             }
2726         }
2727     }
2728     else
2729     {
2730         SetLastError(CRYPT_E_ASN1_BADTAG);
2731         ret = FALSE;
2732     }
2733     TRACE("returning %d (%08lx)\n", ret, GetLastError());
2734     return ret;
2735 }
2736
2737 /* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
2738  * pvStructInfo.  The BLOB must be non-empty, otherwise the last error is set
2739  * to CRYPT_E_ASN1_CORRUPT.
2740  * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
2741  * set!
2742  */
2743 static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
2744  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2745  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2746 {
2747     BOOL ret;
2748     DWORD dataLen;
2749
2750     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2751     {
2752         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2753         DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
2754        
2755         if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2756             bytesNeeded += 1 + lenBytes + dataLen;
2757
2758         if (!pvStructInfo)
2759             *pcbStructInfo = bytesNeeded;
2760         else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, 
2761          pvStructInfo, pcbStructInfo, bytesNeeded)))
2762         {
2763             CRYPT_DER_BLOB *blob = (CRYPT_DER_BLOB *)pvStructInfo;
2764
2765             blob->cbData = 1 + lenBytes + dataLen;
2766             if (blob->cbData)
2767             {
2768                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2769                     blob->pbData = (BYTE *)pbEncoded;
2770                 else
2771                 {
2772                     assert(blob->pbData);
2773                     memcpy(blob->pbData, pbEncoded, blob->cbData);
2774                 }
2775             }
2776             else
2777             {
2778                 SetLastError(CRYPT_E_ASN1_CORRUPT);
2779                 ret = FALSE;
2780             }
2781         }
2782     }
2783     return ret;
2784 }
2785
2786 /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */
2787 static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType,
2788  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2789  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2790 {
2791     BOOL ret;
2792
2793     TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
2794      pDecodePara, pvStructInfo, *pcbStructInfo);
2795
2796     /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in-
2797      * place.
2798      */
2799     ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType,
2800      pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pDecodePara,
2801      pvStructInfo, pcbStructInfo);
2802     if (ret && pvStructInfo)
2803     {
2804         CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
2805
2806         if (blob->cbData)
2807         {
2808             DWORD i;
2809             BYTE temp;
2810
2811             for (i = 0; i < blob->cbData / 2; i++)
2812             {
2813                 temp = blob->pbData[i];
2814                 blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
2815                 blob->pbData[blob->cbData - i - 1] = temp;
2816             }
2817         }
2818     }
2819     TRACE("returning %d (%08lx)\n", ret, GetLastError());
2820     return ret;
2821 }
2822
2823 static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
2824  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2825  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2826 {
2827     BOOL ret = TRUE;
2828
2829     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2830      pDecodePara, pvStructInfo, *pcbStructInfo);
2831
2832     __TRY
2833     {
2834         struct AsnDecodeSequenceItem items[] = {
2835          { offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
2836            CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2837            offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 },
2838          { offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm),
2839            CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2840            FALSE, TRUE, offsetof(CERT_SIGNED_CONTENT_INFO,
2841            SignatureAlgorithm.pszObjId), 0 },
2842          { offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
2843            CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
2844            offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 },
2845         };
2846
2847         if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
2848             items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
2849         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2850          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2851          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2852     }
2853     __EXCEPT(page_fault)
2854     {
2855         SetLastError(STATUS_ACCESS_VIOLATION);
2856         ret = FALSE;
2857     }
2858     __ENDTRY
2859     return ret;
2860 }
2861
2862 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
2863  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2864  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2865 {
2866     BOOL ret;
2867
2868     if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR))
2869     {
2870         DWORD dataLen;
2871
2872         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2873         {
2874             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2875
2876             ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
2877              pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
2878              pvStructInfo, pcbStructInfo);
2879         }
2880     }
2881     else
2882     {
2883         SetLastError(CRYPT_E_ASN1_BADTAG);
2884         ret = FALSE;
2885     }
2886     return ret;
2887 }
2888
2889 static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
2890  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2891  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2892 {
2893     BOOL ret;
2894
2895     struct AsnDecodeSequenceItem items[] = {
2896      { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
2897        CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2898      { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
2899        CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2900     };
2901
2902     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2903      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2904      pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2905     return ret;
2906 }
2907
2908 static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType,
2909  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2910  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2911 {
2912     BOOL ret;
2913
2914     if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR | 3))
2915     {
2916         DWORD dataLen;
2917
2918         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2919         {
2920             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2921
2922             ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
2923              X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
2924              pDecodePara, pvStructInfo, pcbStructInfo);
2925         }
2926     }
2927     else
2928     {
2929         SetLastError(CRYPT_E_ASN1_BADTAG);
2930         ret = FALSE;
2931     }
2932     return ret;
2933 }
2934
2935 static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
2936  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2937  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2938 {
2939     BOOL ret = TRUE;
2940
2941     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2942      pDecodePara, pvStructInfo, *pcbStructInfo);
2943
2944     __TRY
2945     {
2946         struct AsnDecodeSequenceItem items[] = {
2947          { offsetof(CERT_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
2948            sizeof(DWORD), TRUE, FALSE, 0, 0 },
2949          { offsetof(CERT_INFO, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2950            sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2951            SerialNumber.pbData), 0 },
2952          { offsetof(CERT_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
2953            sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CERT_INFO,
2954            SignatureAlgorithm.pszObjId), 0 },
2955          { offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
2956            sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2957            Issuer.pbData) },
2958          { offsetof(CERT_INFO, NotBefore), CRYPT_AsnDecodeValidity,
2959            sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, FALSE, 0 },
2960          { offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
2961            sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2962            Subject.pbData) },
2963          { offsetof(CERT_INFO, SubjectPublicKeyInfo), CRYPT_AsnDecodePubKeyInfo,
2964            sizeof(CERT_PUBLIC_KEY_INFO), FALSE, TRUE, offsetof(CERT_INFO,
2965            SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
2966          { offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal,
2967            sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2968            IssuerUniqueId.pbData), 0 },
2969          { offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal,
2970            sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2971            SubjectUniqueId.pbData), 0 },
2972          { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeCertExtensions,
2973            sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CERT_INFO,
2974            rgExtension), 0 },
2975         };
2976
2977         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2978          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2979          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2980     }
2981     __EXCEPT(page_fault)
2982     {
2983         SetLastError(STATUS_ACCESS_VIOLATION);
2984         ret = FALSE;
2985     }
2986     __ENDTRY
2987     return ret;
2988 }
2989
2990 static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded,
2991  DWORD dwFlags, PCRL_ENTRY entry, DWORD *pcbEntry)
2992 {
2993     BOOL ret;
2994     struct AsnDecodeSequenceItem items[] = {
2995      { offsetof(CRL_ENTRY, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2996        sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CRL_ENTRY,
2997        SerialNumber.pbData), 0 },
2998      { offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
2999        sizeof(FILETIME), FALSE, FALSE, 0 },
3000      { offsetof(CRL_ENTRY, cExtension), CRYPT_AsnDecodeExtensionsInternal,
3001        sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CRL_ENTRY,
3002        rgExtension), 0 },
3003     };
3004
3005     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry,
3006      *pcbEntry);
3007
3008     ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3009      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3010      NULL, entry, pcbEntry, entry ? entry->SerialNumber.pbData : NULL);
3011     TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3012     return ret;
3013 }
3014
3015 typedef struct _WINE_CRL_ENTRIES {
3016     DWORD      cCRLEntry;
3017     PCRL_ENTRY rgCRLEntry;
3018 } WINE_CRL_ENTRIES, *PWINE_CRL_ENTRIES;
3019
3020 /* Warning: assumes pvStructInfo is a WINE_CRL_ENTRIES whose rgCRLEntry has
3021  * been set prior to calling.
3022  */
3023 static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
3024  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3025  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3026 {
3027     BOOL ret;
3028
3029     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3030      pDecodePara, pvStructInfo, *pcbStructInfo);
3031
3032     if (pbEncoded[0] == ASN_SEQUENCEOF)
3033     {
3034         DWORD dataLen, bytesNeeded;
3035
3036         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3037         {
3038             DWORD cCRLEntry = 0;
3039             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3040
3041             bytesNeeded = sizeof(WINE_CRL_ENTRIES);
3042             if (dataLen)
3043             {
3044                 const BYTE *ptr;
3045                 DWORD size;
3046
3047                 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3048                  ptr - pbEncoded - 1 - lenBytes < dataLen; )
3049                 {
3050                     size = 0;
3051                     ret = CRYPT_AsnDecodeCRLEntry(ptr,
3052                      cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3053                     if (ret)
3054                     {
3055                         DWORD nextLen;
3056
3057                         cCRLEntry++;
3058                         bytesNeeded += size;
3059                         ret = CRYPT_GetLen(ptr,
3060                          cbEncoded - (ptr - pbEncoded), &nextLen);
3061                         if (ret)
3062                             ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3063                     }
3064                 }
3065             }
3066             if (ret)
3067             {
3068                 if (!pvStructInfo)
3069                     *pcbStructInfo = bytesNeeded;
3070                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3071                  pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3072                 {
3073                     DWORD size, i;
3074                     BYTE *nextData;
3075                     const BYTE *ptr;
3076                     PWINE_CRL_ENTRIES entries;
3077
3078                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3079                         pvStructInfo = *(BYTE **)pvStructInfo;
3080                     *pcbStructInfo = bytesNeeded;
3081                     entries = (PWINE_CRL_ENTRIES)pvStructInfo;
3082                     entries->cCRLEntry = cCRLEntry;
3083                     assert(entries->rgCRLEntry);
3084                     nextData = (BYTE *)entries->rgCRLEntry +
3085                      entries->cCRLEntry * sizeof(CRL_ENTRY);
3086                     for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3087                      i < cCRLEntry && ptr - pbEncoded - 1 - lenBytes <
3088                      dataLen; i++)
3089                     {
3090                         entries->rgCRLEntry[i].SerialNumber.pbData = nextData;
3091                         size = bytesNeeded;
3092                         ret = CRYPT_AsnDecodeCRLEntry(ptr,
3093                          cbEncoded - (ptr - pbEncoded), dwFlags,
3094                          &entries->rgCRLEntry[i], &size);
3095                         if (ret)
3096                         {
3097                             DWORD nextLen;
3098
3099                             bytesNeeded -= size;
3100                             /* Increment nextData by the difference of the
3101                              * minimum size and the actual size.
3102                              */
3103                             if (size > sizeof(CRL_ENTRY))
3104                                 nextData += size - sizeof(CRL_ENTRY);
3105                             ret = CRYPT_GetLen(ptr,
3106                              cbEncoded - (ptr - pbEncoded), &nextLen);
3107                             if (ret)
3108                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3109                         }
3110                     }
3111                 }
3112             }
3113         }
3114     }
3115     else
3116     {
3117         SetLastError(CRYPT_E_ASN1_BADTAG);
3118         ret = FALSE;
3119     }
3120     TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3121     return ret;
3122 }
3123
3124 static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
3125  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3126  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3127 {
3128     BOOL ret = TRUE;
3129
3130     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3131      pDecodePara, pvStructInfo, *pcbStructInfo);
3132
3133     __TRY
3134     {
3135         struct AsnDecodeSequenceItem items[] = {
3136          { offsetof(CRL_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
3137            sizeof(DWORD), TRUE, FALSE, 0, 0 },
3138          { offsetof(CRL_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
3139            sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CRL_INFO,
3140            SignatureAlgorithm.pszObjId), 0 },
3141          { offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
3142            sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO,
3143            Issuer.pbData) },
3144          { offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
3145            sizeof(FILETIME), FALSE, FALSE, 0 },
3146          { offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
3147            sizeof(FILETIME), TRUE, FALSE, 0 },
3148          { offsetof(CRL_INFO, cCRLEntry), CRYPT_AsnDecodeCRLEntries,
3149            sizeof(WINE_CRL_ENTRIES), TRUE, TRUE, offsetof(CRL_INFO,
3150            rgCRLEntry), 0 },
3151          /* Note that the extensions are ignored by MS, so I'll ignore them too
3152           */
3153          { offsetof(CRL_INFO, cExtension), NULL,
3154            sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 },
3155         };
3156
3157         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3158          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3159          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3160     }
3161     __EXCEPT(page_fault)
3162     {
3163         SetLastError(STATUS_ACCESS_VIOLATION);
3164         ret = FALSE;
3165     }
3166     __ENDTRY
3167
3168     TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3169     return ret;
3170 }
3171
3172 /* Differences between this and CRYPT_AsnDecodeOid:
3173  * - pvStructInfo is a LPSTR *, not an LPSTR
3174  * - CRYPT_AsnDecodeOid doesn't account for the size of an LPSTR in its byte
3175  *   count, whereas our callers (typically CRYPT_AsnDecodeSequence) expect this
3176  *   to
3177  */
3178 static BOOL WINAPI CRYPT_AsnDecodeOidWrapper(DWORD dwCertEncodingType,
3179  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3180  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3181 {
3182     BOOL ret;
3183
3184     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3185      pDecodePara, pvStructInfo, *pcbStructInfo);
3186
3187     ret = CRYPT_AsnDecodeOid(pbEncoded, cbEncoded, dwFlags,
3188      pvStructInfo ? *(LPSTR *)pvStructInfo : NULL, pcbStructInfo);
3189     if (ret || GetLastError() == ERROR_MORE_DATA)
3190         *pcbStructInfo += sizeof(LPSTR);
3191     if (ret && pvStructInfo)
3192         TRACE("returning %s\n", debugstr_a(*(LPSTR *)pvStructInfo));
3193     return ret;
3194 }
3195
3196 /* Warning:  assumes ext->pszObjId is set ahead of time! */
3197 static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
3198  DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
3199 {
3200     struct AsnDecodeSequenceItem items[] = {
3201      { offsetof(CERT_EXTENSION, pszObjId), CRYPT_AsnDecodeOidWrapper,
3202        sizeof(LPSTR), FALSE, TRUE, offsetof(CERT_EXTENSION, pszObjId), 0 },
3203      { offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool,
3204        sizeof(BOOL), TRUE, FALSE, 0, 0 },
3205      { offsetof(CERT_EXTENSION, Value), CRYPT_AsnDecodeOctetsInternal,
3206        sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE, offsetof(CERT_EXTENSION,
3207        Value.pbData) },
3208     };
3209     BOOL ret = TRUE;
3210
3211     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, ext,
3212      *pcbExt);
3213
3214     if (ext)
3215         TRACE("ext->pszObjId is %p\n", ext->pszObjId);
3216     ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3217      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
3218      ext, pcbExt, ext ? ext->pszObjId : NULL);
3219     if (ext)
3220         TRACE("ext->pszObjId is %p (%s)\n", ext->pszObjId,
3221          debugstr_a(ext->pszObjId));
3222     TRACE("returning %d (%08lx)\n", ret, GetLastError());
3223     return ret;
3224 }
3225
3226 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
3227  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3228  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3229 {
3230     BOOL ret = TRUE;
3231
3232     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3233      pDecodePara, pvStructInfo, *pcbStructInfo);
3234
3235     if (pbEncoded[0] == ASN_SEQUENCEOF)
3236     {
3237         DWORD dataLen, bytesNeeded;
3238
3239         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3240         {
3241             DWORD cExtension = 0;
3242             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3243
3244             bytesNeeded = sizeof(CERT_EXTENSIONS);
3245             if (dataLen)
3246             {
3247                 const BYTE *ptr;
3248                 DWORD size;
3249
3250                 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3251                  ptr - pbEncoded - 1 - lenBytes < dataLen; )
3252                 {
3253                     size = 0;
3254                     ret = CRYPT_AsnDecodeExtension(ptr,
3255                      cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3256                     if (ret)
3257                     {
3258                         DWORD nextLen;
3259
3260                         cExtension++;
3261                         bytesNeeded += size;
3262                         ret = CRYPT_GetLen(ptr,
3263                          cbEncoded - (ptr - pbEncoded), &nextLen);
3264                         if (ret)
3265                             ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3266                     }
3267                 }
3268             }
3269             if (ret)
3270             {
3271                 if (!pvStructInfo)
3272                     *pcbStructInfo = bytesNeeded;
3273                 else if (*pcbStructInfo < bytesNeeded)
3274                 {
3275                     SetLastError(ERROR_MORE_DATA);
3276                     *pcbStructInfo = bytesNeeded;
3277                     ret = FALSE;
3278                 }
3279                 else
3280                 {
3281                     DWORD size, i;
3282                     BYTE *nextData;
3283                     const BYTE *ptr;
3284                     CERT_EXTENSIONS *exts;
3285
3286                     *pcbStructInfo = bytesNeeded;
3287                     exts = (CERT_EXTENSIONS *)pvStructInfo;
3288                     exts->cExtension = cExtension;
3289                     assert(exts->rgExtension);
3290                     nextData = (BYTE *)exts->rgExtension +
3291                      exts->cExtension * sizeof(CERT_EXTENSION);
3292                     for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3293                      i < cExtension && ptr - pbEncoded - 1 - lenBytes <
3294                      dataLen; i++)
3295                     {
3296                         exts->rgExtension[i].pszObjId = (LPSTR)nextData;
3297                         size = bytesNeeded;
3298                         ret = CRYPT_AsnDecodeExtension(ptr,
3299                          cbEncoded - (ptr - pbEncoded), dwFlags,
3300                          &exts->rgExtension[i], &size);
3301                         if (ret)
3302                         {
3303                             DWORD nextLen;
3304
3305                             bytesNeeded -= size;
3306                             if (size > sizeof(CERT_EXTENSION))
3307                                 nextData += size - sizeof(CERT_EXTENSION);
3308                             ret = CRYPT_GetLen(ptr,
3309                              cbEncoded - (ptr - pbEncoded), &nextLen);
3310                             if (ret)
3311                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3312                         }
3313                     }
3314                 }
3315             }
3316         }
3317     }
3318     else
3319     {
3320         SetLastError(CRYPT_E_ASN1_BADTAG);
3321         ret = FALSE;
3322     }
3323     return ret;
3324 }
3325
3326 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
3327  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3328  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3329 {
3330     BOOL ret = TRUE;
3331
3332     __TRY
3333     {
3334         ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3335          lpszStructType, pbEncoded, cbEncoded,
3336          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
3337         if (ret && pvStructInfo)
3338         {
3339             ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
3340              pcbStructInfo, *pcbStructInfo);
3341             if (ret)
3342             {
3343                 CERT_EXTENSIONS *exts;
3344
3345                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3346                     pvStructInfo = *(BYTE **)pvStructInfo;
3347                 exts = (CERT_EXTENSIONS *)pvStructInfo;
3348                 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
3349                  sizeof(CERT_EXTENSIONS));
3350                 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3351                  lpszStructType, pbEncoded, cbEncoded,
3352                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3353                  pcbStructInfo);
3354             }
3355         }
3356     }
3357     __EXCEPT(page_fault)
3358     {
3359         SetLastError(STATUS_ACCESS_VIOLATION);
3360         ret = FALSE;
3361     }
3362     __ENDTRY
3363     return ret;
3364 }
3365
3366 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
3367 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
3368  DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
3369 {
3370     BOOL ret = TRUE;
3371
3372     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, pszObjId,
3373      *pcbObjId);
3374
3375     __TRY
3376     {
3377         if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
3378         {
3379             DWORD dataLen;
3380
3381             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3382             {
3383                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3384                 DWORD bytesNeeded;
3385
3386                 if (dataLen)
3387                 {
3388                     /* The largest possible string for the first two components
3389                      * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
3390                      */
3391                     char firstTwo[6];
3392                     const BYTE *ptr;
3393
3394                     snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
3395                      pbEncoded[1 + lenBytes] / 40,
3396                      pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
3397                      * 40);
3398                     bytesNeeded = strlen(firstTwo) + 1;
3399                     for (ptr = pbEncoded + 2 + lenBytes; ret &&
3400                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
3401                     {
3402                         /* large enough for ".4000000" */
3403                         char str[9];
3404                         int val = 0;
3405
3406                         while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3407                          (*ptr & 0x80))
3408                         {
3409                             val <<= 7;
3410                             val |= *ptr & 0x7f;
3411                             ptr++;
3412                         }
3413                         if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
3414                          (*ptr & 0x80))
3415                         {
3416                             SetLastError(CRYPT_E_ASN1_CORRUPT);
3417                             ret = FALSE;
3418                         }
3419                         else
3420                         {
3421                             val <<= 7;
3422                             val |= *ptr++;
3423                             snprintf(str, sizeof(str), ".%d", val);
3424                             bytesNeeded += strlen(str);
3425                         }
3426                     }
3427                     if (!pszObjId)
3428                         *pcbObjId = bytesNeeded;
3429                     else if (*pcbObjId < bytesNeeded)
3430                     {
3431                         *pcbObjId = bytesNeeded;
3432                         SetLastError(ERROR_MORE_DATA);
3433                         ret = FALSE;
3434                     }
3435                     else
3436                     {
3437                         *pszObjId = 0;
3438                         sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
3439                          pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
3440                          40) * 40);
3441                         pszObjId += strlen(pszObjId);
3442                         for (ptr = pbEncoded + 2 + lenBytes; ret &&
3443                          ptr - pbEncoded - 1 - lenBytes < dataLen; )
3444                         {
3445                             int val = 0;
3446
3447                             while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3448                              (*ptr & 0x80))
3449                             {
3450                                 val <<= 7;
3451                                 val |= *ptr & 0x7f;
3452                                 ptr++;
3453                             }
3454                             val <<= 7;
3455                             val |= *ptr++;
3456                             sprintf(pszObjId, ".%d", val);
3457                             pszObjId += strlen(pszObjId);
3458                         }
3459                     }
3460                 }
3461                 else
3462                     bytesNeeded = 0;
3463                 *pcbObjId = bytesNeeded;
3464             }
3465         }
3466         else
3467         {
3468             SetLastError(CRYPT_E_ASN1_BADTAG);
3469             ret = FALSE;
3470         }
3471     }
3472     __EXCEPT(page_fault)
3473     {
3474         SetLastError(STATUS_ACCESS_VIOLATION);
3475         ret = FALSE;
3476     }
3477     __ENDTRY
3478     return ret;
3479 }
3480
3481 /* Warning: this assumes the address of value->Value.pbData is already set, in
3482  * order to avoid overwriting memory.  (In some cases, it may change it, if it
3483  * doesn't copy anything to memory.)  Be sure to set it correctly!
3484  */
3485 static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
3486  DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD *pcbValue)
3487 {
3488     BOOL ret = TRUE;
3489
3490     __TRY
3491     {
3492         DWORD dataLen;
3493
3494         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3495         {
3496             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3497
3498             switch (pbEncoded[0])
3499             {
3500             case ASN_NUMERICSTRING:
3501             case ASN_PRINTABLESTRING:
3502             case ASN_IA5STRING:
3503                 break;
3504             default:
3505                 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
3506                 SetLastError(OSS_UNIMPLEMENTED);
3507                 ret = FALSE;
3508             }
3509             if (ret)
3510             {
3511                 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
3512
3513                 switch (pbEncoded[0])
3514                 {
3515                 case ASN_NUMERICSTRING:
3516                 case ASN_PRINTABLESTRING:
3517                 case ASN_IA5STRING:
3518                     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3519                         bytesNeeded += dataLen;
3520                     break;
3521                 }
3522                 if (!value)
3523                     *pcbValue = bytesNeeded;
3524                 else if (*pcbValue < bytesNeeded)
3525                 {
3526                     *pcbValue = bytesNeeded;
3527                     SetLastError(ERROR_MORE_DATA);
3528                     ret = FALSE;
3529                 }
3530                 else
3531                 {
3532                     *pcbValue = bytesNeeded;
3533                     switch (pbEncoded[0])
3534                     {
3535                     case ASN_NUMERICSTRING:
3536                         value->dwValueType = CERT_RDN_NUMERIC_STRING;
3537                         break;
3538                     case ASN_PRINTABLESTRING:
3539                         value->dwValueType = CERT_RDN_PRINTABLE_STRING;
3540                         break;
3541                     case ASN_IA5STRING:
3542                         value->dwValueType = CERT_RDN_IA5_STRING;
3543                         break;
3544                     }
3545                     if (dataLen)
3546                     {
3547                         switch (pbEncoded[0])
3548                         {
3549                         case ASN_NUMERICSTRING:
3550                         case ASN_PRINTABLESTRING:
3551                         case ASN_IA5STRING:
3552                             value->Value.cbData = dataLen;
3553                             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3554                                 value->Value.pbData = (BYTE *)pbEncoded + 1 +
3555                                  lenBytes;
3556                             else
3557                             {
3558                                 assert(value->Value.pbData);
3559                                 memcpy(value->Value.pbData,
3560                                  pbEncoded + 1 + lenBytes, dataLen);
3561                             }
3562                             break;
3563                         }
3564                     }
3565                     else
3566                     {
3567                         value->Value.cbData = 0;
3568                         value->Value.pbData = NULL;
3569                     }
3570                 }
3571             }
3572         }
3573     }
3574     __EXCEPT(page_fault)
3575     {
3576         SetLastError(STATUS_ACCESS_VIOLATION);
3577         ret = FALSE;
3578     }
3579     __ENDTRY
3580     return ret;
3581 }
3582
3583 /* FIXME: this should use CRYPT_AsnDecodeSequence (though that won't accept it
3584  * at the moment because of the ASN_CONSTRUCTOR tag.)
3585  */
3586 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded,
3587  DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD *pcbAttr)
3588 {
3589     BOOL ret;
3590
3591     __TRY
3592     {
3593         if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCE))
3594         {
3595             DWORD bytesNeeded, dataLen, size;
3596             BYTE lenBytes;
3597
3598             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3599             {
3600                 /* The data length must be at least 4, two for the tag and
3601                  * length for the OID, and two for the string (assuming both
3602                  * have short-form lengths.)
3603                  */
3604                 if (dataLen < 4)
3605                 {
3606                     SetLastError(CRYPT_E_ASN1_EOD);
3607                     ret = FALSE;
3608                 }
3609                 else
3610                 {
3611                     bytesNeeded = sizeof(CERT_RDN_ATTR);
3612                     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3613                     ret = CRYPT_AsnDecodeOid(pbEncoded + 1 + lenBytes,
3614                      cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
3615                     if (ret)
3616                     {
3617                         /* ugly: need to know the size of the next element of
3618                          * the sequence, so get it directly
3619                          */
3620                         DWORD objIdOfset = 1 + lenBytes, objIdLen,
3621                          nameValueOffset = 0;
3622
3623                         ret = CRYPT_GetLen(pbEncoded + objIdOfset,
3624                          cbEncoded - objIdOfset, &objIdLen);
3625                         bytesNeeded += size;
3626                         /* hack: like encoding, this takes advantage of the
3627                          * fact that the rest of the structure is identical to
3628                          * a CERT_NAME_VALUE.
3629                          */
3630                         if (ret)
3631                         {
3632                             nameValueOffset = objIdOfset + objIdLen + 1 +
3633                              GET_LEN_BYTES(pbEncoded[objIdOfset]);
3634                             ret = CRYPT_AsnDecodeNameValue(
3635                              pbEncoded + nameValueOffset,
3636                              cbEncoded - nameValueOffset, dwFlags, NULL, &size);
3637                         }
3638                         if (ret)
3639                         {
3640                             bytesNeeded += size;
3641                             if (!attr)
3642                                 *pcbAttr = bytesNeeded;
3643                             else if (*pcbAttr < bytesNeeded)
3644                             {
3645                                 *pcbAttr = bytesNeeded;
3646                                 SetLastError(ERROR_MORE_DATA);
3647                                 ret = FALSE;
3648                             }
3649                             else
3650                             {
3651                                 BYTE *originalData = attr->Value.pbData;
3652
3653                                 *pcbAttr = bytesNeeded;
3654                                 /* strange: decode the value first, because it
3655                                  * has a counted size, and we can store the OID
3656                                  * after it.  Keep track of the original data
3657                                  * pointer, we'll need to know whether it was
3658                                  * changed.
3659                                  */
3660                                 size = bytesNeeded;
3661                                 ret = CRYPT_AsnDecodeNameValue(
3662                                  pbEncoded + nameValueOffset,
3663                                  cbEncoded - nameValueOffset, dwFlags,
3664                                  (CERT_NAME_VALUE *)&attr->dwValueType, &size);
3665                                 if (ret)
3666                                 {
3667                                     if (objIdLen)
3668                                     {
3669                                         /* if the data were copied to the
3670                                          * original location, the OID goes
3671                                          * after.  Otherwise it goes in the
3672                                          * spot originally reserved for the
3673                                          * data.
3674                                          */
3675                                         if (attr->Value.pbData == originalData)
3676                                             attr->pszObjId =
3677                                              (LPSTR)(attr->Value.pbData +
3678                                              attr->Value.cbData);
3679                                         else
3680                                             attr->pszObjId =
3681                                              (LPSTR)originalData;
3682                                         size = bytesNeeded - size;
3683                                         ret = CRYPT_AsnDecodeOid(
3684                                          pbEncoded + objIdOfset,
3685                                          cbEncoded - objIdOfset,
3686                                          dwFlags, attr->pszObjId, &size);
3687                                     }
3688                                     else
3689                                         attr->pszObjId = NULL;
3690                                 }
3691                             }
3692                         }
3693                     }
3694                 }
3695             }
3696         }
3697         else
3698         {
3699             SetLastError(CRYPT_E_ASN1_BADTAG);
3700             ret = FALSE;
3701         }
3702     }
3703     __EXCEPT(page_fault)
3704     {
3705         SetLastError(STATUS_ACCESS_VIOLATION);
3706         ret = FALSE;
3707     }
3708     __ENDTRY
3709     return ret;
3710 }
3711
3712 static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
3713  DWORD dwFlags, CERT_RDN *rdn, DWORD *pcbRdn)
3714 {
3715     BOOL ret = TRUE;
3716
3717     __TRY
3718     {
3719         if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SETOF))
3720         {
3721             DWORD dataLen;
3722
3723             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3724             {
3725                 DWORD bytesNeeded, cRDNAttr = 0;
3726                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3727
3728                 bytesNeeded = sizeof(CERT_RDN);
3729                 if (dataLen)
3730                 {
3731                     const BYTE *ptr;
3732                     DWORD size;
3733
3734                     for (ptr = pbEncoded + 1 + lenBytes; ret &&
3735                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
3736                     {
3737                         ret = CRYPT_AsnDecodeRdnAttr(ptr,
3738                          cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3739                         if (ret)
3740                         {
3741                             DWORD nextLen;
3742
3743                             cRDNAttr++;
3744                             bytesNeeded += size;
3745                             ret = CRYPT_GetLen(ptr,
3746                              cbEncoded - (ptr - pbEncoded), &nextLen);
3747                             if (ret)
3748                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3749                         }
3750                     }
3751                 }
3752                 if (ret)
3753                 {
3754                     if (!rdn)
3755                         *pcbRdn = bytesNeeded;
3756                     else if (*pcbRdn < bytesNeeded)
3757                     {
3758                         *pcbRdn = bytesNeeded;
3759                         SetLastError(ERROR_MORE_DATA);
3760                         ret = FALSE;
3761                     }
3762                     else
3763                     {
3764                         DWORD size, i;
3765                         BYTE *nextData;
3766                         const BYTE *ptr;
3767
3768                         *pcbRdn = bytesNeeded;
3769                         rdn->cRDNAttr = cRDNAttr;
3770                         rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn +
3771                          sizeof(CERT_RDN));
3772                         nextData = (BYTE *)rdn->rgRDNAttr +
3773                          rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
3774                         for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3775                          i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
3776                          dataLen; i++)
3777                         {
3778                             rdn->rgRDNAttr[i].Value.pbData = nextData;
3779                             size = bytesNeeded;
3780                             ret = CRYPT_AsnDecodeRdnAttr(ptr,
3781                              cbEncoded - (ptr - pbEncoded), dwFlags,
3782                              &rdn->rgRDNAttr[i], &size);
3783                             if (ret)
3784                             {
3785                                 DWORD nextLen;
3786
3787                                 bytesNeeded -= size;
3788                                 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
3789                                  * data may not have been copied.
3790                                  */
3791                                 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
3792                                     nextData +=
3793                                      rdn->rgRDNAttr[i].Value.cbData;
3794                                 /* Ugly: the OID, if copied, is stored in
3795                                  * memory after the value, so increment by its
3796                                  * string length if it's set and points here.
3797                                  */
3798                                 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId
3799                                  == nextData)
3800                                     nextData += strlen(
3801                                      rdn->rgRDNAttr[i].pszObjId) + 1;
3802                                 ret = CRYPT_GetLen(ptr,
3803                                  cbEncoded - (ptr - pbEncoded), &nextLen);
3804                                 if (ret)
3805                                     ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3806                             }
3807                         }
3808                     }
3809                 }
3810             }
3811         }
3812         else
3813         {
3814             SetLastError(CRYPT_E_ASN1_BADTAG);
3815             ret = FALSE;
3816         }
3817     }
3818     __EXCEPT(page_fault)
3819     {
3820         SetLastError(STATUS_ACCESS_VIOLATION);
3821         ret = FALSE;
3822     }
3823     __ENDTRY
3824     return ret;
3825 }
3826
3827 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
3828  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3829  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3830 {
3831     BOOL ret = TRUE;
3832
3833     __TRY
3834     {
3835         if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
3836         {
3837             DWORD dataLen;
3838
3839             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3840             {
3841                 DWORD bytesNeeded, cRDN = 0;
3842                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3843
3844                 bytesNeeded = sizeof(CERT_NAME_INFO);
3845                 if (dataLen)
3846                 {
3847                     const BYTE *ptr;
3848
3849                     for (ptr = pbEncoded + 1 + lenBytes; ret &&
3850                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
3851                     {
3852                         DWORD size;
3853
3854                         ret = CRYPT_AsnDecodeRdn(ptr,
3855                          cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3856                         if (ret)
3857                         {
3858                             DWORD nextLen;
3859
3860                             cRDN++;
3861                             bytesNeeded += size;
3862                             ret = CRYPT_GetLen(ptr,
3863                              cbEncoded - (ptr - pbEncoded), &nextLen);
3864                             if (ret)
3865                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3866                         }
3867                     }
3868                 }
3869                 if (ret)
3870                 {
3871                     if (!pvStructInfo)
3872                         *pcbStructInfo = bytesNeeded;
3873                     else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3874                      pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3875                     {
3876                         CERT_NAME_INFO *info;
3877
3878                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3879                             pvStructInfo = *(BYTE **)pvStructInfo;
3880                         info = (CERT_NAME_INFO *)pvStructInfo;
3881                         info->cRDN = cRDN;
3882                         if (info->cRDN == 0)
3883                             info->rgRDN = NULL;
3884                         else
3885                         {
3886                             DWORD size, i;
3887                             BYTE *nextData;
3888                             const BYTE *ptr;
3889
3890                             info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
3891                              sizeof(CERT_NAME_INFO));
3892                             nextData = (BYTE *)info->rgRDN +
3893                              info->cRDN * sizeof(CERT_RDN);
3894                             for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3895                              i < cRDN && ptr - pbEncoded - 1 - lenBytes <
3896                              dataLen; i++)
3897                             {
3898                                 info->rgRDN[i].rgRDNAttr =
3899                                  (CERT_RDN_ATTR *)nextData;
3900                                 size = bytesNeeded;
3901                                 ret = CRYPT_AsnDecodeRdn(ptr,
3902                                  cbEncoded - (ptr - pbEncoded), dwFlags,
3903                                  &info->rgRDN[i], &size);
3904                                 if (ret)
3905                                 {
3906                                     DWORD nextLen;
3907
3908                                     nextData += size;
3909                                     bytesNeeded -= size;
3910                                     ret = CRYPT_GetLen(ptr,
3911                                      cbEncoded - (ptr - pbEncoded), &nextLen);
3912                                     if (ret)
3913                                         ptr += nextLen + 1 +
3914                                          GET_LEN_BYTES(ptr[1]);
3915                                 }
3916                             }
3917                         }
3918                     }
3919                 }
3920             }
3921         }
3922         else
3923         {
3924             SetLastError(CRYPT_E_ASN1_BADTAG);
3925             ret = FALSE;
3926         }
3927     }
3928     __EXCEPT(page_fault)
3929     {
3930         SetLastError(STATUS_ACCESS_VIOLATION);
3931         ret = FALSE;
3932     }
3933     __ENDTRY
3934     return ret;
3935 }
3936
3937 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
3938  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3939  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3940 {
3941     BOOL ret = TRUE;
3942     DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
3943
3944     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3945      pDecodePara, pvStructInfo, *pcbStructInfo);
3946
3947     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3948         bytesNeeded += cbEncoded;
3949     if (!pvStructInfo)
3950         *pcbStructInfo = bytesNeeded;
3951     else if (*pcbStructInfo < bytesNeeded)
3952     {
3953         SetLastError(ERROR_MORE_DATA);
3954         *pcbStructInfo = bytesNeeded;
3955         ret = FALSE;
3956     }
3957     else
3958     {
3959         PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
3960
3961         *pcbStructInfo = bytesNeeded;
3962         blob->cbData = cbEncoded;
3963         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3964             blob->pbData = (LPBYTE)pbEncoded;
3965         else
3966         {
3967             assert(blob->pbData);
3968             memcpy(blob->pbData, pbEncoded, blob->cbData);
3969         }
3970     }
3971     return ret;
3972 }
3973
3974 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
3975  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3976  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3977 {
3978     CRYPT_ALGORITHM_IDENTIFIER *algo =
3979      (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
3980     BOOL ret = TRUE;
3981     struct AsnDecodeSequenceItem items[] = {
3982      { offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
3983        CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE, 
3984        offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
3985      { offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
3986        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE, 
3987        offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
3988     };
3989
3990     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3991      pDecodePara, pvStructInfo, *pcbStructInfo);
3992
3993     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3994      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3995      pDecodePara, pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
3996     if (ret && pvStructInfo)
3997     {
3998         TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
3999          debugstr_a(algo->pszObjId));
4000     }
4001     return ret;
4002 }
4003
4004 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
4005  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4006  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4007 {
4008     BOOL ret = TRUE;
4009
4010     __TRY
4011     {
4012         struct AsnDecodeSequenceItem items[] = {
4013          { offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
4014            CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
4015            FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO,
4016            Algorithm.pszObjId) },
4017          { offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
4018            CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
4019            offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) },
4020         };
4021
4022         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4023          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4024          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4025     }
4026     __EXCEPT(page_fault)
4027     {
4028         SetLastError(STATUS_ACCESS_VIOLATION);
4029         ret = FALSE;
4030     }
4031     __ENDTRY
4032     return ret;
4033 }
4034
4035 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
4036  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4037  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4038 {
4039     BOOL ret;
4040
4041     if (cbEncoded < 3)
4042     {
4043         SetLastError(CRYPT_E_ASN1_CORRUPT);
4044         return FALSE;
4045     }
4046     if (pbEncoded[0] != ASN_BOOL)
4047     {
4048         SetLastError(CRYPT_E_ASN1_BADTAG);
4049         return FALSE;
4050     }
4051     if (GET_LEN_BYTES(pbEncoded[1]) > 1)
4052     {
4053         SetLastError(CRYPT_E_ASN1_CORRUPT);
4054         return FALSE;
4055     }
4056     if (pbEncoded[1] > 1)
4057     {
4058         SetLastError(CRYPT_E_ASN1_CORRUPT);
4059         return FALSE;
4060     }
4061     if (!pvStructInfo)
4062     {
4063         *pcbStructInfo = sizeof(BOOL);
4064         ret = TRUE;
4065     }
4066     else if (*pcbStructInfo < sizeof(BOOL))
4067     {
4068         *pcbStructInfo = sizeof(BOOL);
4069         SetLastError(ERROR_MORE_DATA);
4070         ret = FALSE;
4071     }
4072     else
4073     {
4074         *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
4075         ret = TRUE;
4076     }
4077     TRACE("returning %d (%08lx)\n", ret, GetLastError());
4078     return ret;
4079 }
4080
4081 static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded,
4082  DWORD dwFlags, CERT_ALT_NAME_ENTRY *entry, DWORD *pcbEntry)
4083 {
4084     DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY);
4085     BOOL ret;
4086
4087     if (cbEncoded < 2)
4088     {
4089         SetLastError(CRYPT_E_ASN1_CORRUPT);
4090         return FALSE;
4091     }
4092     if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT)
4093     {
4094         SetLastError(CRYPT_E_ASN1_BADTAG);
4095         return FALSE;
4096     }
4097     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4098     if (1 + lenBytes > cbEncoded)
4099     {
4100         SetLastError(CRYPT_E_ASN1_CORRUPT);
4101         return FALSE;
4102     }
4103     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4104     {
4105         switch (pbEncoded[0] & ASN_TYPE_MASK)
4106         {
4107         case 1: /* rfc822Name */
4108         case 2: /* dNSName */
4109         case 6: /* uniformResourceIdentifier */
4110             bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
4111             break;
4112         case 7: /* iPAddress */
4113             bytesNeeded += dataLen;
4114             break;
4115         case 8: /* registeredID */
4116             /* FIXME: decode as OID */
4117         case 0: /* otherName */
4118         case 4: /* directoryName */
4119             FIXME("stub\n");
4120             SetLastError(CRYPT_E_ASN1_BADTAG);
4121             ret = FALSE;
4122             break;
4123         case 3: /* x400Address, unimplemented */
4124         case 5: /* ediPartyName, unimplemented */
4125             SetLastError(CRYPT_E_ASN1_BADTAG);
4126             ret = FALSE;
4127             break;
4128         default:
4129             SetLastError(CRYPT_E_ASN1_CORRUPT);
4130             ret = FALSE;
4131         }
4132         if (ret)
4133         {
4134             if (!entry)
4135                 *pcbEntry = bytesNeeded;
4136             else if (*pcbEntry < bytesNeeded)
4137             {
4138                 SetLastError(ERROR_MORE_DATA);
4139                 ret = FALSE;
4140             }
4141             else
4142             {
4143                 /* MS used values one greater than the asn1 ones.. sigh */
4144                 entry->dwAltNameChoice = (pbEncoded[0] & 0x7f) + 1;
4145                 switch (pbEncoded[0] & ASN_TYPE_MASK)
4146                 {
4147                 case 1: /* rfc822Name */
4148                 case 2: /* dNSName */
4149                 case 6: /* uniformResourceIdentifier */
4150                 {
4151                     DWORD i;
4152
4153                     for (i = 0; i < dataLen; i++)
4154                         entry->u.pwszURL[i] =
4155                          (WCHAR)pbEncoded[1 + lenBytes + i];
4156                     entry->u.pwszURL[i] = 0;
4157                     break;
4158                 }
4159                 case 7: /* iPAddress */
4160                     /* The next data pointer is in the pwszURL spot, that is,
4161                      * the first 4 bytes.  Need to move it to the next spot.
4162                      */
4163                     entry->u.IPAddress.pbData = (LPBYTE)entry->u.pwszURL;
4164                     entry->u.IPAddress.cbData = dataLen;
4165                     memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes,
4166                      dataLen);
4167                     break;
4168                 }
4169             }
4170         }
4171     }
4172     return ret;
4173 }
4174
4175 static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
4176  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4177  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4178 {
4179     BOOL ret = TRUE;
4180
4181     __TRY
4182     {
4183         if (pbEncoded[0] == ASN_SEQUENCEOF)
4184         {
4185             DWORD dataLen;
4186
4187             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4188             {
4189                 DWORD bytesNeeded, cEntry = 0;
4190                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4191
4192                 bytesNeeded = sizeof(CERT_ALT_NAME_INFO);
4193                 if (dataLen)
4194                 {
4195                     const BYTE *ptr;
4196
4197                     for (ptr = pbEncoded + 1 + lenBytes; ret &&
4198                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
4199                     {
4200                         DWORD size;
4201
4202                         ret = CRYPT_AsnDecodeAltNameEntry(ptr,
4203                          cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
4204                         if (ret)
4205                         {
4206                             DWORD nextLen;
4207
4208                             cEntry++;
4209                             bytesNeeded += size;
4210                             ret = CRYPT_GetLen(ptr,
4211                              cbEncoded - (ptr - pbEncoded), &nextLen);
4212                             if (ret)
4213                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
4214                         }
4215                     }
4216                 }
4217                 if (ret)
4218                 {
4219                     if (!pvStructInfo)
4220                         *pcbStructInfo = bytesNeeded;
4221                     else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
4222                      pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
4223                     {
4224                         CERT_ALT_NAME_INFO *info;
4225
4226                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4227                             pvStructInfo = *(BYTE **)pvStructInfo;
4228                         info = (CERT_ALT_NAME_INFO *)pvStructInfo;
4229                         info->cAltEntry = 0;
4230                         if (cEntry == 0)
4231                             info->rgAltEntry = NULL;
4232                         else
4233                         {
4234                             DWORD size, i;
4235                             BYTE *nextData;
4236                             const BYTE *ptr;
4237
4238                             info->rgAltEntry =
4239                              (CERT_ALT_NAME_ENTRY *)((BYTE *)pvStructInfo +
4240                              sizeof(CERT_ALT_NAME_INFO));
4241                             nextData = (BYTE *)info->rgAltEntry +
4242                              cEntry * sizeof(CERT_ALT_NAME_ENTRY);
4243                             for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
4244                              i < cEntry && ptr - pbEncoded - 1 - lenBytes <
4245                              dataLen; i++)
4246                             {
4247                                 info->rgAltEntry[i].u.pwszURL =
4248                                  (LPWSTR)nextData;
4249                                 size = bytesNeeded;
4250                                 ret = CRYPT_AsnDecodeAltNameEntry(ptr,
4251                                  cbEncoded - (ptr - pbEncoded), dwFlags,
4252                                  &info->rgAltEntry[i], &size);
4253                                 if (ret)
4254                                 {
4255                                     DWORD nextLen;
4256
4257                                     info->cAltEntry++;
4258                                     nextData += size -
4259                                      sizeof(CERT_ALT_NAME_ENTRY);
4260                                     bytesNeeded -= size;
4261                                     ret = CRYPT_GetLen(ptr,
4262                                      cbEncoded - (ptr - pbEncoded), &nextLen);
4263                                     if (ret)
4264                                         ptr += nextLen + 1 +
4265                                          GET_LEN_BYTES(ptr[1]);
4266                                 }
4267                             }
4268                         }
4269                     }
4270                 }
4271             }
4272         }
4273         else
4274         {
4275             SetLastError(CRYPT_E_ASN1_BADTAG);
4276             ret = FALSE;
4277         }
4278     }
4279     __EXCEPT(page_fault)
4280     {
4281         SetLastError(STATUS_ACCESS_VIOLATION);
4282         ret = FALSE;
4283     }
4284     __ENDTRY
4285     return ret;
4286 }
4287
4288 struct PATH_LEN_CONSTRAINT
4289 {
4290     BOOL  fPathLenConstraint;
4291     DWORD dwPathLenConstraint;
4292 };
4293
4294 static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType,
4295  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4296  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4297 {
4298     BOOL ret = TRUE;
4299
4300     if (cbEncoded)
4301     {
4302         if (pbEncoded[0] == ASN_INTEGER)
4303         {
4304             DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT);
4305
4306             if (!pvStructInfo)
4307                 *pcbStructInfo = bytesNeeded;
4308             else if (*pcbStructInfo < bytesNeeded)
4309             {
4310                 SetLastError(ERROR_MORE_DATA);
4311                 *pcbStructInfo = bytesNeeded;
4312                 ret = FALSE;
4313             }
4314             else
4315             {
4316                 struct PATH_LEN_CONSTRAINT *constraint =
4317                  (struct PATH_LEN_CONSTRAINT *)pvStructInfo;
4318                 DWORD size = sizeof(constraint->dwPathLenConstraint);
4319
4320                 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
4321                  pbEncoded, cbEncoded, 0, NULL,
4322                  &constraint->dwPathLenConstraint, &size);
4323                 if (ret)
4324                     constraint->fPathLenConstraint = TRUE;
4325                 TRACE("got an int, dwPathLenConstraint is %ld\n",
4326                  constraint->dwPathLenConstraint);
4327             }
4328         }
4329         else
4330         {
4331             SetLastError(CRYPT_E_ASN1_CORRUPT);
4332             ret = FALSE;
4333         }
4334     }
4335     TRACE("returning %d (%08lx)\n", ret, GetLastError());
4336     return ret;
4337 }
4338
4339 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
4340  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4341  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4342 {
4343     BOOL ret;
4344
4345     __TRY
4346     {
4347         struct AsnDecodeSequenceItem items[] = {
4348          { offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA), CRYPT_AsnDecodeBool,
4349            sizeof(BOOL), TRUE, FALSE, 0, 0 },
4350          { offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fPathLenConstraint),
4351            CRYPT_AsnDecodePathLenConstraint, sizeof(struct PATH_LEN_CONSTRAINT),
4352            TRUE, FALSE, 0, 0 },
4353         };
4354
4355         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4356          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4357          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4358     }
4359     __EXCEPT(page_fault)
4360     {
4361         SetLastError(STATUS_ACCESS_VIOLATION);
4362         ret = FALSE;
4363     }
4364     __ENDTRY
4365     return ret;
4366 }
4367
4368 #define RSA1_MAGIC 0x31415352
4369
4370 struct DECODED_RSA_PUB_KEY
4371 {
4372     DWORD              pubexp;
4373     CRYPT_INTEGER_BLOB modulus;
4374 };
4375
4376 static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
4377  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4378  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4379 {
4380     BOOL ret;
4381
4382     __TRY
4383     {
4384         struct AsnDecodeSequenceItem items[] = {
4385          { offsetof(struct DECODED_RSA_PUB_KEY, modulus),
4386            CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB),
4387            FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData),
4388            0 },
4389          { offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
4390            CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
4391         };
4392         struct DECODED_RSA_PUB_KEY *decodedKey = NULL;
4393         DWORD size = 0;
4394
4395         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4396          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
4397          CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL);
4398         if (ret)
4399         {
4400             DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
4401              decodedKey->modulus.cbData;
4402
4403             if (!pvStructInfo)
4404             {
4405                 *pcbStructInfo = bytesNeeded;
4406                 ret = TRUE;
4407             }
4408             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4409              pvStructInfo, pcbStructInfo, bytesNeeded)))
4410             {
4411                 BLOBHEADER *hdr;
4412                 RSAPUBKEY *rsaPubKey;
4413
4414                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4415                     pvStructInfo = *(BYTE **)pvStructInfo;
4416                 hdr = (BLOBHEADER *)pvStructInfo;
4417                 hdr->bType = PUBLICKEYBLOB;
4418                 hdr->bVersion = CUR_BLOB_VERSION;
4419                 hdr->reserved = 0;
4420                 hdr->aiKeyAlg = CALG_RSA_KEYX;
4421                 rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo +
4422                  sizeof(BLOBHEADER));
4423                 rsaPubKey->magic = RSA1_MAGIC;
4424                 rsaPubKey->pubexp = decodedKey->pubexp;
4425                 rsaPubKey->bitlen = decodedKey->modulus.cbData * 8;
4426                 memcpy((BYTE *)pvStructInfo + sizeof(BLOBHEADER) +
4427                  sizeof(RSAPUBKEY), decodedKey->modulus.pbData,
4428                  decodedKey->modulus.cbData);
4429             }
4430             LocalFree(decodedKey);
4431         }
4432     }
4433     __EXCEPT(page_fault)
4434     {
4435         SetLastError(STATUS_ACCESS_VIOLATION);
4436         ret = FALSE;
4437     }
4438     __ENDTRY
4439     return ret;
4440 }
4441
4442 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
4443  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4444  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4445 {
4446     BOOL ret;
4447
4448     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4449      pDecodePara, pvStructInfo, *pcbStructInfo);
4450
4451     if (pbEncoded[0] == ASN_OCTETSTRING)
4452     {
4453         DWORD bytesNeeded, dataLen;
4454
4455         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4456         {
4457             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4458                 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
4459             else
4460                 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
4461             if (!pvStructInfo)
4462                 *pcbStructInfo = bytesNeeded;
4463             else if (*pcbStructInfo < bytesNeeded)
4464             {
4465                 SetLastError(ERROR_MORE_DATA);
4466                 *pcbStructInfo = bytesNeeded;
4467                 ret = FALSE;
4468             }
4469             else
4470             {
4471                 CRYPT_DATA_BLOB *blob;
4472                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4473
4474                 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4475                 blob->cbData = dataLen;
4476                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4477                     blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
4478                 else
4479                 {
4480                     assert(blob->pbData);
4481                     if (blob->cbData)
4482                         memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
4483                          blob->cbData);
4484                 }
4485             }
4486         }
4487     }
4488     else
4489     {
4490         SetLastError(CRYPT_E_ASN1_BADTAG);
4491         ret = FALSE;
4492     }
4493     return ret;
4494 }
4495
4496 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
4497  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4498  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4499 {
4500     BOOL ret;
4501
4502     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4503      pDecodePara, pvStructInfo, *pcbStructInfo);
4504
4505     __TRY
4506     {
4507         DWORD bytesNeeded;
4508
4509         if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4510          lpszStructType, pbEncoded, cbEncoded,
4511          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4512         {
4513             if (!pvStructInfo)
4514                 *pcbStructInfo = bytesNeeded;
4515             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4516              pvStructInfo, pcbStructInfo, bytesNeeded)))
4517             {
4518                 CRYPT_DATA_BLOB *blob;
4519
4520                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4521                     pvStructInfo = *(BYTE **)pvStructInfo;
4522                 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4523                 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB);
4524                 ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4525                  lpszStructType, pbEncoded, cbEncoded,
4526                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4527                  &bytesNeeded);
4528             }
4529         }
4530         else
4531         {
4532             SetLastError(CRYPT_E_ASN1_BADTAG);
4533             ret = FALSE;
4534         }
4535     }
4536     __EXCEPT(page_fault)
4537     {
4538         SetLastError(STATUS_ACCESS_VIOLATION);
4539         ret = FALSE;
4540     }
4541     __ENDTRY
4542     return ret;
4543 }
4544
4545 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
4546  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4547  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4548 {
4549     BOOL ret;
4550
4551     TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
4552      pDecodePara, pvStructInfo, *pcbStructInfo);
4553
4554     if (pbEncoded[0] == ASN_BITSTRING)
4555     {
4556         DWORD bytesNeeded, dataLen;
4557
4558         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4559         {
4560             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4561                 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
4562             else
4563                 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
4564             if (!pvStructInfo)
4565                 *pcbStructInfo = bytesNeeded;
4566             else if (*pcbStructInfo < bytesNeeded)
4567             {
4568                 *pcbStructInfo = bytesNeeded;
4569                 SetLastError(ERROR_MORE_DATA);
4570                 ret = FALSE;
4571             }
4572             else
4573             {
4574                 CRYPT_BIT_BLOB *blob;
4575
4576                 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4577                 blob->cbData = dataLen - 1;
4578                 blob->cUnusedBits = *(pbEncoded + 1 +
4579                  GET_LEN_BYTES(pbEncoded[1]));
4580                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4581                 {
4582                     blob->pbData = (BYTE *)pbEncoded + 2 +
4583                      GET_LEN_BYTES(pbEncoded[1]);
4584                 }
4585                 else
4586                 {
4587                     assert(blob->pbData);
4588                     if (blob->cbData)
4589                     {
4590                         BYTE mask = 0xff << blob->cUnusedBits;
4591
4592                         memcpy(blob->pbData, pbEncoded + 2 +
4593                          GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
4594                         blob->pbData[blob->cbData - 1] &= mask;
4595                     }
4596                 }
4597             }
4598         }
4599     }
4600     else
4601     {
4602         SetLastError(CRYPT_E_ASN1_BADTAG);
4603         ret = FALSE;
4604     }
4605     TRACE("returning %d (%08lx)\n", ret, GetLastError());
4606     return ret;
4607 }
4608
4609 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
4610  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4611  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4612 {
4613     BOOL ret;
4614
4615     TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
4616      pDecodePara, pvStructInfo, pcbStructInfo);
4617
4618     __TRY
4619     {
4620         DWORD bytesNeeded;
4621
4622         if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4623          lpszStructType, pbEncoded, cbEncoded,
4624          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4625         {
4626             if (!pvStructInfo)
4627                 *pcbStructInfo = bytesNeeded;
4628             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4629              pvStructInfo, pcbStructInfo, bytesNeeded)))
4630             {
4631                 CRYPT_BIT_BLOB *blob;
4632
4633                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4634                     pvStructInfo = *(BYTE **)pvStructInfo;
4635                 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4636                 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
4637                 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4638                  lpszStructType, pbEncoded, cbEncoded,
4639                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4640                  &bytesNeeded);
4641             }
4642         }
4643     }
4644     __EXCEPT(page_fault)
4645     {
4646         SetLastError(STATUS_ACCESS_VIOLATION);
4647         ret = FALSE;
4648     }
4649     __ENDTRY
4650     TRACE("returning %d (%08lx)\n", ret, GetLastError());
4651     return ret;
4652 }
4653
4654 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
4655  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4656  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4657 {
4658     BOOL ret;
4659
4660     if (!pvStructInfo)
4661     {
4662         *pcbStructInfo = sizeof(int);
4663         return TRUE;
4664     }
4665     __TRY
4666     {
4667         BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
4668         CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
4669         DWORD size = sizeof(buf);
4670
4671         blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
4672         ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4673          X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
4674         if (ret)
4675         {
4676             if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4677              pvStructInfo, pcbStructInfo, sizeof(int))))
4678             {
4679                 int val, i;
4680
4681                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4682                     pvStructInfo = *(BYTE **)pvStructInfo;
4683                 if (blob->pbData[blob->cbData - 1] & 0x80)
4684                 {
4685                     /* initialize to a negative value to sign-extend */
4686                     val = -1;
4687                 }
4688                 else
4689                     val = 0;
4690                 for (i = 0; i < blob->cbData; i++)
4691                 {
4692                     val <<= 8;
4693                     val |= blob->pbData[blob->cbData - i - 1];
4694                 }
4695                 memcpy(pvStructInfo, &val, sizeof(int));
4696             }
4697         }
4698         else if (GetLastError() == ERROR_MORE_DATA)
4699             SetLastError(CRYPT_E_ASN1_LARGE);
4700     }
4701     __EXCEPT(page_fault)
4702     {
4703         SetLastError(STATUS_ACCESS_VIOLATION);
4704         ret = FALSE;
4705     }
4706     __ENDTRY
4707     return ret;
4708 }
4709
4710 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
4711  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4712  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4713 {
4714     BOOL ret;
4715
4716     if (pbEncoded[0] == ASN_INTEGER)
4717     {
4718         DWORD bytesNeeded, dataLen;
4719
4720         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4721         {
4722             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4723
4724             bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4725             if (!pvStructInfo)
4726                 *pcbStructInfo = bytesNeeded;
4727             else if (*pcbStructInfo < bytesNeeded)
4728             {
4729                 *pcbStructInfo = bytesNeeded;
4730                 SetLastError(ERROR_MORE_DATA);
4731                 ret = FALSE;
4732             }
4733             else
4734             {
4735                 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4736
4737                 blob->cbData = dataLen;
4738                 assert(blob->pbData);
4739                 if (blob->cbData)
4740                 {
4741                     DWORD i;
4742
4743                     for (i = 0; i < blob->cbData; i++)
4744                     {
4745                         blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4746                          dataLen - i - 1);
4747                     }
4748                 }
4749             }
4750         }
4751     }
4752     else
4753     {
4754         SetLastError(CRYPT_E_ASN1_BADTAG);
4755         ret = FALSE;
4756     }
4757     return ret;
4758 }
4759
4760 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
4761  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4762  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4763 {
4764     BOOL ret;
4765
4766     __TRY
4767     {
4768         DWORD bytesNeeded;
4769
4770         if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4771          lpszStructType, pbEncoded, cbEncoded,
4772          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4773         {
4774             if (!pvStructInfo)
4775                 *pcbStructInfo = bytesNeeded;
4776             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4777              pvStructInfo, pcbStructInfo, bytesNeeded)))
4778             {
4779                 CRYPT_INTEGER_BLOB *blob;
4780
4781                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4782                     pvStructInfo = *(BYTE **)pvStructInfo;
4783                 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4784                 blob->pbData = (BYTE *)pvStructInfo +
4785                  sizeof(CRYPT_INTEGER_BLOB);
4786                 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4787                  lpszStructType, pbEncoded, cbEncoded,
4788                  dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4789                  &bytesNeeded);
4790             }
4791         }
4792     }
4793     __EXCEPT(page_fault)
4794     {
4795         SetLastError(STATUS_ACCESS_VIOLATION);
4796         ret = FALSE;
4797     }
4798     __ENDTRY
4799     return ret;
4800 }
4801
4802 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
4803  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4804  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4805 {
4806     BOOL ret;
4807
4808     __TRY
4809     {
4810         if (pbEncoded[0] == ASN_INTEGER)
4811         {
4812             DWORD bytesNeeded, dataLen;
4813             CRYPT_INTEGER_BLOB *blob;
4814
4815             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4816             {
4817                 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4818                 if (!pvStructInfo)
4819                     *pcbStructInfo = bytesNeeded;
4820                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4821                  pvStructInfo, pcbStructInfo, bytesNeeded)))
4822                 {
4823                     BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4824
4825                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4826                         pvStructInfo = *(BYTE **)pvStructInfo;
4827                     blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4828                     blob->cbData = dataLen;
4829                     blob->pbData = (BYTE *)pvStructInfo +
4830                      sizeof(CRYPT_INTEGER_BLOB);
4831                     /* remove leading zero byte if it exists */
4832                     if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
4833                     {
4834                         blob->cbData--;
4835                         blob->pbData++;
4836                     }
4837                     if (blob->cbData)
4838                     {
4839                         DWORD i;
4840
4841                         for (i = 0; i < blob->cbData; i++)
4842                             blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4843                              pbEncoded[1] - i - 1);
4844                     }
4845                 }
4846             }
4847         }
4848         else
4849         {
4850             SetLastError(CRYPT_E_ASN1_BADTAG);
4851             ret = FALSE;
4852         }
4853     }
4854     __EXCEPT(page_fault)
4855     {
4856         SetLastError(STATUS_ACCESS_VIOLATION);
4857         ret = FALSE;
4858     }
4859     __ENDTRY
4860     return ret;
4861 }
4862
4863 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
4864  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4865  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4866 {
4867     BOOL ret;
4868
4869     if (!pvStructInfo)
4870     {
4871         *pcbStructInfo = sizeof(int);
4872         return TRUE;
4873     }
4874     __TRY
4875     {
4876         if (pbEncoded[0] == ASN_ENUMERATED)
4877         {
4878             unsigned int val = 0, i;
4879
4880             if (cbEncoded <= 1)
4881             {
4882                 SetLastError(CRYPT_E_ASN1_EOD);
4883                 ret = FALSE;
4884             }
4885             else if (pbEncoded[1] == 0)
4886             {
4887                 SetLastError(CRYPT_E_ASN1_CORRUPT);
4888                 ret = FALSE;
4889             }
4890             else
4891             {
4892                 /* A little strange looking, but we have to accept a sign byte:
4893                  * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff.  Also,
4894                  * assuming a small length is okay here, it has to be in short
4895                  * form.
4896                  */
4897                 if (pbEncoded[1] > sizeof(unsigned int) + 1)
4898                 {
4899                     SetLastError(CRYPT_E_ASN1_LARGE);
4900                     return FALSE;
4901                 }
4902                 for (i = 0; i < pbEncoded[1]; i++)
4903                 {
4904                     val <<= 8;
4905                     val |= pbEncoded[2 + i];
4906                 }
4907                 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4908                  pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
4909                 {
4910                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4911                         pvStructInfo = *(BYTE **)pvStructInfo;
4912                     memcpy(pvStructInfo, &val, sizeof(unsigned int));
4913                 }
4914             }
4915         }
4916         else
4917         {
4918             SetLastError(CRYPT_E_ASN1_BADTAG);
4919             ret = FALSE;
4920         }
4921     }
4922     __EXCEPT(page_fault)
4923     {
4924         SetLastError(STATUS_ACCESS_VIOLATION);
4925         ret = FALSE;
4926     }
4927     __ENDTRY
4928     return ret;
4929 }
4930
4931 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
4932  * if it fails.
4933  */
4934 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
4935  do { \
4936     BYTE i; \
4937  \
4938     (word) = 0; \
4939     for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
4940     { \
4941         if (!isdigit(*(pbEncoded))) \
4942         { \
4943             SetLastError(CRYPT_E_ASN1_CORRUPT); \
4944             ret = FALSE; \
4945         } \
4946         else \
4947         { \
4948             (word) *= 10; \
4949             (word) += *(pbEncoded)++ - '0'; \
4950         } \
4951     } \
4952  } while (0)
4953
4954 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
4955  SYSTEMTIME *sysTime)
4956 {
4957     BOOL ret;
4958
4959     __TRY
4960     {
4961         ret = TRUE;
4962         if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
4963         {
4964             WORD hours, minutes = 0;
4965             BYTE sign = *pbEncoded++;
4966
4967             len--;
4968             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
4969             if (ret && hours >= 24)
4970             {
4971                 SetLastError(CRYPT_E_ASN1_CORRUPT);
4972                 ret = FALSE;
4973             }
4974             else if (len >= 2)
4975             {
4976                 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
4977                 if (ret && minutes >= 60)
4978                 {
4979                     SetLastError(CRYPT_E_ASN1_CORRUPT);
4980                     ret = FALSE;
4981                 }
4982             }
4983             if (ret)
4984             {
4985                 if (sign == '+')
4986                 {
4987                     sysTime->wHour += hours;
4988                     sysTime->wMinute += minutes;
4989                 }
4990                 else
4991                 {
4992                     if (hours > sysTime->wHour)
4993                     {
4994                         sysTime->wDay--;
4995                         sysTime->wHour = 24 - (hours - sysTime->wHour);
4996                     }
4997                     else
4998                         sysTime->wHour -= hours;
4999                     if (minutes > sysTime->wMinute)
5000                     {
5001                         sysTime->wHour--;
5002                         sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
5003                     }
5004                     else
5005                         sysTime->wMinute -= minutes;
5006                 }
5007             }
5008         }
5009     }
5010     __EXCEPT(page_fault)
5011     {
5012         SetLastError(STATUS_ACCESS_VIOLATION);
5013         ret = FALSE;
5014     }
5015     __ENDTRY
5016     return ret;
5017 }
5018
5019 #define MIN_ENCODED_TIME_LENGTH 10
5020
5021 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
5022  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5023  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5024 {
5025     BOOL ret;
5026
5027     if (!pvStructInfo)
5028     {
5029         *pcbStructInfo = sizeof(FILETIME);
5030         return TRUE;
5031     }
5032     __TRY
5033     {
5034         ret = TRUE;
5035         if (pbEncoded[0] == ASN_UTCTIME)
5036         {
5037             if (cbEncoded <= 1)
5038             {
5039                 SetLastError(CRYPT_E_ASN1_EOD);
5040                 ret = FALSE;
5041             }
5042             else if (pbEncoded[1] > 0x7f)
5043             {
5044                 /* long-form date strings really can't be valid */
5045                 SetLastError(CRYPT_E_ASN1_CORRUPT);
5046                 ret = FALSE;
5047             }
5048             else
5049             {
5050                 SYSTEMTIME sysTime = { 0 };
5051                 BYTE len = pbEncoded[1];
5052
5053                 if (len < MIN_ENCODED_TIME_LENGTH)
5054                 {
5055                     SetLastError(CRYPT_E_ASN1_CORRUPT);
5056                     ret = FALSE;
5057                 }
5058                 else
5059                 {
5060                     pbEncoded += 2;
5061                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
5062                     if (sysTime.wYear >= 50)
5063                         sysTime.wYear += 1900;
5064                     else
5065                         sysTime.wYear += 2000;
5066                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
5067                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
5068                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
5069                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
5070                     if (ret && len > 0)
5071                     {
5072                         if (len >= 2 && isdigit(*pbEncoded) &&
5073                          isdigit(*(pbEncoded + 1)))
5074                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5075                              sysTime.wSecond);
5076                         else if (isdigit(*pbEncoded))
5077                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
5078                              sysTime.wSecond);
5079                         if (ret)
5080                             ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
5081                              &sysTime);
5082                     }
5083                     if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
5084                      pDecodePara, pvStructInfo, pcbStructInfo,
5085                      sizeof(FILETIME))))
5086                     {
5087                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5088                             pvStructInfo = *(BYTE **)pvStructInfo;
5089                         ret = SystemTimeToFileTime(&sysTime,
5090                          (FILETIME *)pvStructInfo);
5091                     }
5092                 }
5093             }
5094         }
5095         else
5096         {
5097             SetLastError(CRYPT_E_ASN1_BADTAG);
5098             ret = FALSE;
5099         }
5100     }
5101     __EXCEPT(page_fault)
5102     {
5103         SetLastError(STATUS_ACCESS_VIOLATION);
5104         ret = FALSE;
5105     }
5106     __ENDTRY
5107     return ret;
5108 }
5109
5110 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
5111  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5112  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5113 {
5114     BOOL ret;
5115
5116     if (!pvStructInfo)
5117     {
5118         *pcbStructInfo = sizeof(FILETIME);
5119         return TRUE;
5120     }
5121     __TRY
5122     {
5123         ret = TRUE;
5124         if (pbEncoded[0] == ASN_GENERALTIME)
5125         {
5126             if (cbEncoded <= 1)
5127             {
5128                 SetLastError(CRYPT_E_ASN1_EOD);
5129                 ret = FALSE;
5130             }
5131             else if (pbEncoded[1] > 0x7f)
5132             {
5133                 /* long-form date strings really can't be valid */
5134                 SetLastError(CRYPT_E_ASN1_CORRUPT);
5135                 ret = FALSE;
5136             }
5137             else
5138             {
5139                 BYTE len = pbEncoded[1];
5140
5141                 if (len < MIN_ENCODED_TIME_LENGTH)
5142                 {
5143                     SetLastError(CRYPT_E_ASN1_CORRUPT);
5144                     ret = FALSE;
5145                 }
5146                 else
5147                 {
5148                     SYSTEMTIME sysTime = { 0 };
5149
5150                     pbEncoded += 2;
5151                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
5152                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
5153                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
5154                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
5155                     if (ret && len > 0)
5156                     {
5157                         CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5158                          sysTime.wMinute);
5159                         if (ret && len > 0)
5160                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5161                              sysTime.wSecond);
5162                         if (ret && len > 0 && (*pbEncoded == '.' ||
5163                          *pbEncoded == ','))
5164                         {
5165                             BYTE digits;
5166
5167                             pbEncoded++;
5168                             len--;
5169                             /* workaround macro weirdness */
5170                             digits = min(len, 3);
5171                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
5172                              sysTime.wMilliseconds);
5173                         }
5174                         if (ret)
5175                             ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
5176                              &sysTime);
5177                     }
5178                     if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
5179                      pDecodePara, pvStructInfo, pcbStructInfo,
5180                      sizeof(FILETIME))))
5181                     {
5182                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5183                             pvStructInfo = *(BYTE **)pvStructInfo;
5184                         ret = SystemTimeToFileTime(&sysTime,
5185                          (FILETIME *)pvStructInfo);
5186                     }
5187                 }
5188             }
5189         }
5190         else
5191         {
5192             SetLastError(CRYPT_E_ASN1_BADTAG);
5193             ret = FALSE;
5194         }
5195     }
5196     __EXCEPT(page_fault)
5197     {
5198         SetLastError(STATUS_ACCESS_VIOLATION);
5199         ret = FALSE;
5200     }
5201     __ENDTRY
5202     return ret;
5203 }
5204
5205 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
5206  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5207  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5208 {
5209     BOOL ret;
5210
5211     __TRY
5212     {
5213         if (pbEncoded[0] == ASN_UTCTIME)
5214             ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
5215              pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
5216              pcbStructInfo);
5217         else if (pbEncoded[0] == ASN_GENERALTIME)
5218             ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
5219              lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
5220              pvStructInfo, pcbStructInfo);
5221         else
5222         {
5223             SetLastError(CRYPT_E_ASN1_BADTAG);
5224             ret = FALSE;
5225         }
5226     }
5227     __EXCEPT(page_fault)
5228     {
5229         SetLastError(STATUS_ACCESS_VIOLATION);
5230         ret = FALSE;
5231     }
5232     __ENDTRY
5233     return ret;
5234 }
5235
5236 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
5237  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5238  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5239 {
5240     BOOL ret = TRUE;
5241
5242     __TRY
5243     {
5244         if (pbEncoded[0] == ASN_SEQUENCEOF)
5245         {
5246             DWORD bytesNeeded, dataLen, remainingLen, cValue;
5247
5248             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
5249             {
5250                 BYTE lenBytes;
5251                 const BYTE *ptr;
5252
5253                 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
5254                 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
5255                 cValue = 0;
5256                 ptr = pbEncoded + 1 + lenBytes;
5257                 remainingLen = dataLen;
5258                 while (ret && remainingLen)
5259                 {
5260                     DWORD nextLen;
5261
5262                     ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5263                     if (ret)
5264                     {
5265                         DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5266
5267                         remainingLen -= 1 + nextLenBytes + nextLen;
5268                         ptr += 1 + nextLenBytes + nextLen;
5269                         bytesNeeded += sizeof(CRYPT_DER_BLOB);
5270                         if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
5271                             bytesNeeded += 1 + nextLenBytes + nextLen;
5272                         cValue++;
5273                     }
5274                 }
5275                 if (ret)
5276                 {
5277                     CRYPT_SEQUENCE_OF_ANY *seq;
5278                     BYTE *nextPtr;
5279                     DWORD i;
5280
5281                     if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
5282                      pvStructInfo, pcbStructInfo, bytesNeeded)))
5283                     {
5284                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5285                             pvStructInfo = *(BYTE **)pvStructInfo;
5286                         seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
5287                         seq->cValue = cValue;
5288                         seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
5289                          sizeof(*seq));
5290                         nextPtr = (BYTE *)seq->rgValue +
5291                          cValue * sizeof(CRYPT_DER_BLOB);
5292                         ptr = pbEncoded + 1 + lenBytes;
5293                         remainingLen = dataLen;
5294                         i = 0;
5295                         while (ret && remainingLen)
5296                         {
5297                             DWORD nextLen;
5298
5299                             ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5300                             if (ret)
5301                             {
5302                                 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5303
5304                                 seq->rgValue[i].cbData = 1 + nextLenBytes +
5305                                  nextLen;
5306                                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
5307                                     seq->rgValue[i].pbData = (BYTE *)ptr;
5308                                 else
5309                                 {
5310                                     seq->rgValue[i].pbData = nextPtr;
5311                                     memcpy(nextPtr, ptr, 1 + nextLenBytes +
5312                                      nextLen);
5313                                     nextPtr += 1 + nextLenBytes + nextLen;
5314                                 }
5315                                 remainingLen -= 1 + nextLenBytes + nextLen;
5316                                 ptr += 1 + nextLenBytes + nextLen;
5317                                 i++;
5318                             }
5319                         }
5320                     }
5321                 }
5322             }
5323         }
5324         else
5325         {
5326             SetLastError(CRYPT_E_ASN1_BADTAG);
5327             return FALSE;
5328         }
5329     }
5330     __EXCEPT(page_fault)
5331     {
5332         SetLastError(STATUS_ACCESS_VIOLATION);
5333         ret = FALSE;
5334     }
5335     __ENDTRY
5336     return ret;
5337 }
5338
5339 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
5340  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5341  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5342 {
5343     BOOL ret = FALSE;
5344     HMODULE lib = NULL;
5345     CryptDecodeObjectExFunc decodeFunc = NULL;
5346
5347     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
5348      dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded,
5349      cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5350
5351     if (!pvStructInfo && !pcbStructInfo)
5352     {
5353         SetLastError(ERROR_INVALID_PARAMETER);
5354         return FALSE;
5355     }
5356     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
5357      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
5358     {
5359         SetLastError(ERROR_FILE_NOT_FOUND);
5360         return FALSE;
5361     }
5362     if (!cbEncoded)
5363     {
5364         SetLastError(CRYPT_E_ASN1_EOD);
5365         return FALSE;
5366     }
5367     if (cbEncoded > MAX_ENCODED_LEN)
5368     {
5369         SetLastError(CRYPT_E_ASN1_LARGE);
5370         return FALSE;
5371     }
5372
5373     SetLastError(NOERROR);
5374     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
5375         *(BYTE **)pvStructInfo = NULL;
5376     if (!HIWORD(lpszStructType))
5377     {
5378         switch (LOWORD(lpszStructType))
5379         {
5380         case (WORD)X509_CERT:
5381             decodeFunc = CRYPT_AsnDecodeCert;
5382             break;
5383         case (WORD)X509_CERT_TO_BE_SIGNED:
5384             decodeFunc = CRYPT_AsnDecodeCertInfo;
5385             break;
5386         case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
5387             decodeFunc = CRYPT_AsnDecodeCRLInfo;
5388             break;
5389         case (WORD)X509_EXTENSIONS:
5390             decodeFunc = CRYPT_AsnDecodeExtensions;
5391             break;
5392         case (WORD)X509_NAME:
5393             decodeFunc = CRYPT_AsnDecodeName;
5394             break;
5395         case (WORD)X509_PUBLIC_KEY_INFO:
5396             decodeFunc = CRYPT_AsnDecodePubKeyInfo;
5397             break;
5398         case (WORD)X509_ALTERNATE_NAME:
5399             decodeFunc = CRYPT_AsnDecodeAltName;
5400             break;
5401         case (WORD)X509_BASIC_CONSTRAINTS2:
5402             decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5403             break;
5404         case (WORD)RSA_CSP_PUBLICKEYBLOB:
5405             decodeFunc = CRYPT_AsnDecodeRsaPubKey;
5406             break;
5407         case (WORD)X509_OCTET_STRING:
5408             decodeFunc = CRYPT_AsnDecodeOctets;
5409             break;
5410         case (WORD)X509_BITS:
5411         case (WORD)X509_KEY_USAGE:
5412             decodeFunc = CRYPT_AsnDecodeBits;
5413             break;
5414         case (WORD)X509_INTEGER:
5415             decodeFunc = CRYPT_AsnDecodeInt;
5416             break;
5417         case (WORD)X509_MULTI_BYTE_INTEGER:
5418             decodeFunc = CRYPT_AsnDecodeInteger;
5419             break;
5420         case (WORD)X509_MULTI_BYTE_UINT:
5421             decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
5422             break;
5423         case (WORD)X509_ENUMERATED:
5424             decodeFunc = CRYPT_AsnDecodeEnumerated;
5425             break;
5426         case (WORD)X509_CHOICE_OF_TIME:
5427             decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
5428             break;
5429         case (WORD)X509_SEQUENCE_OF_ANY:
5430             decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
5431             break;
5432         case (WORD)PKCS_UTC_TIME:
5433             decodeFunc = CRYPT_AsnDecodeUtcTime;
5434             break;
5435         default:
5436             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
5437         }
5438     }
5439     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
5440         decodeFunc = CRYPT_AsnDecodeExtensions;
5441     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
5442         decodeFunc = CRYPT_AsnDecodeUtcTime;
5443     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
5444         decodeFunc = CRYPT_AsnDecodeEnumerated;
5445     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
5446         decodeFunc = CRYPT_AsnDecodeBits;
5447     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
5448         decodeFunc = CRYPT_AsnDecodeOctets;
5449     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
5450         decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5451     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
5452         decodeFunc = CRYPT_AsnDecodeAltName;
5453     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
5454         decodeFunc = CRYPT_AsnDecodeAltName;
5455     else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
5456         decodeFunc = CRYPT_AsnDecodeAltName;
5457     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
5458         decodeFunc = CRYPT_AsnDecodeAltName;
5459     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
5460         decodeFunc = CRYPT_AsnDecodeAltName;
5461     else
5462         TRACE("OID %s not found or unimplemented, looking for DLL\n",
5463          debugstr_a(lpszStructType));
5464     if (!decodeFunc)
5465         decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
5466          lpszStructType, "CryptDecodeObjectEx", &lib);
5467     if (decodeFunc)
5468         ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
5469          cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5470     else
5471         SetLastError(ERROR_FILE_NOT_FOUND);
5472     if (lib)
5473         FreeLibrary(lib);
5474     return ret;
5475 }