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