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