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