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