Remove redundant check.
[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         ret = TRUE;
1322         if (rdn->cRDNAttr)
1323         {
1324             blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
1325              rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1326             if (!blobs)
1327                 ret = FALSE;
1328         }
1329         for (i = 0; ret && i < rdn->cRDNAttr; i++)
1330         {
1331             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1332              NULL, &blobs[i].cbData);
1333             if (ret)
1334                 bytesNeeded += blobs[i].cbData;
1335         }
1336         if (ret)
1337         {
1338             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1339             bytesNeeded += 1 + lenBytes;
1340             if (pbEncoded)
1341             {
1342                 if (*pcbEncoded < bytesNeeded)
1343                 {
1344                     SetLastError(ERROR_MORE_DATA);
1345                     ret = FALSE;
1346                 }
1347                 else
1348                 {
1349                     for (i = 0; ret && i < rdn->cRDNAttr; i++)
1350                     {
1351                         blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
1352                          blobs[i].cbData);
1353                         if (!blobs[i].pbData)
1354                             ret = FALSE;
1355                         else
1356                             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1357                              &rdn->rgRDNAttr[i], blobs[i].pbData,
1358                              &blobs[i].cbData);
1359                     }
1360                     if (ret)
1361                     {
1362                         qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1363                          BLOBComp);
1364                         *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1365                         CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1366                          &lenBytes);
1367                         pbEncoded += lenBytes;
1368                         for (i = 0; ret && i < rdn->cRDNAttr; i++)
1369                         {
1370                             memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1371                             pbEncoded += blobs[i].cbData;
1372                         }
1373                     }
1374                 }
1375             }
1376             *pcbEncoded = bytesNeeded;
1377         }
1378         if (blobs)
1379         {
1380             for (i = 0; i < rdn->cRDNAttr; i++)
1381                 HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
1382         }
1383     }
1384     __EXCEPT(page_fault)
1385     {
1386         SetLastError(STATUS_ACCESS_VIOLATION);
1387         ret = FALSE;
1388     }
1389     __ENDTRY
1390     HeapFree(GetProcessHeap(), 0, blobs);
1391     return ret;
1392 }
1393
1394 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1395  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1396  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1397 {
1398     BOOL ret;
1399
1400     __TRY
1401     {
1402         const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1403         DWORD bytesNeeded = 0, lenBytes, size, i;
1404
1405         TRACE("encoding name with %ld RDNs\n", info->cRDN);
1406         ret = TRUE;
1407         for (i = 0; ret && i < info->cRDN; i++)
1408         {
1409             ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1410              &size);
1411             if (ret)
1412                 bytesNeeded += size;
1413         }
1414         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1415         bytesNeeded += 1 + lenBytes;
1416         if (ret)
1417         {
1418             if (!pbEncoded)
1419                 *pcbEncoded = bytesNeeded;
1420             else
1421             {
1422                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1423                  pbEncoded, pcbEncoded, bytesNeeded)))
1424                 {
1425                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1426                         pbEncoded = *(BYTE **)pbEncoded;
1427                     *pbEncoded++ = ASN_SEQUENCEOF;
1428                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1429                      &lenBytes);
1430                     pbEncoded += lenBytes;
1431                     for (i = 0; ret && i < info->cRDN; i++)
1432                     {
1433                         size = bytesNeeded;
1434                         ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1435                          &info->rgRDN[i], pbEncoded, &size);
1436                         if (ret)
1437                         {
1438                             pbEncoded += size;
1439                             bytesNeeded -= size;
1440                         }
1441                     }
1442                 }
1443             }
1444         }
1445     }
1446     __EXCEPT(page_fault)
1447     {
1448         SetLastError(STATUS_ACCESS_VIOLATION);
1449         ret = FALSE;
1450     }
1451     __ENDTRY
1452     return ret;
1453 }
1454
1455 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1456  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1457  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1458 {
1459     BOOL val = *(const BOOL *)pvStructInfo, ret;
1460
1461     TRACE("%d\n", val);
1462
1463     if (!pbEncoded)
1464     {
1465         *pcbEncoded = 3;
1466         ret = TRUE;
1467     }
1468     else if (*pcbEncoded < 3)
1469     {
1470         *pcbEncoded = 3;
1471         SetLastError(ERROR_MORE_DATA);
1472         ret = FALSE;
1473     }
1474     else
1475     {
1476         *pcbEncoded = 3;
1477         *pbEncoded++ = ASN_BOOL;
1478         *pbEncoded++ = 1;
1479         *pbEncoded++ = val ? 0xff : 0;
1480         ret = TRUE;
1481     }
1482     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1483     return ret;
1484 }
1485
1486 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1487  BYTE *pbEncoded, DWORD *pcbEncoded)
1488 {
1489     BOOL ret;
1490     DWORD dataLen;
1491
1492     ret = TRUE;
1493     switch (entry->dwAltNameChoice)
1494     {
1495     case CERT_ALT_NAME_RFC822_NAME:
1496     case CERT_ALT_NAME_DNS_NAME:
1497     case CERT_ALT_NAME_URL:
1498         if (entry->u.pwszURL)
1499         {
1500             DWORD i;
1501
1502             /* Not + 1: don't encode the NULL-terminator */
1503             dataLen = lstrlenW(entry->u.pwszURL);
1504             for (i = 0; ret && i < dataLen; i++)
1505             {
1506                 if (entry->u.pwszURL[i] > 0x7f)
1507                 {
1508                     SetLastError(CRYPT_E_INVALID_IA5_STRING);
1509                     ret = FALSE;
1510                     *pcbEncoded = i;
1511                 }
1512             }
1513         }
1514         else
1515             dataLen = 0;
1516         break;
1517     case CERT_ALT_NAME_IP_ADDRESS:
1518         dataLen = entry->u.IPAddress.cbData;
1519         break;
1520     case CERT_ALT_NAME_REGISTERED_ID:
1521         /* FIXME: encode OID */
1522     case CERT_ALT_NAME_OTHER_NAME:
1523     case CERT_ALT_NAME_DIRECTORY_NAME:
1524         FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice);
1525         return FALSE;
1526     default:
1527         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1528         return FALSE;
1529     }
1530     if (ret)
1531     {
1532         DWORD bytesNeeded, lenBytes;
1533
1534         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1535         bytesNeeded = 1 + dataLen + lenBytes;
1536         if (!pbEncoded)
1537             *pcbEncoded = bytesNeeded;
1538         else if (*pcbEncoded < bytesNeeded)
1539         {
1540             SetLastError(ERROR_MORE_DATA);
1541             *pcbEncoded = bytesNeeded;
1542             ret = FALSE;
1543         }
1544         else
1545         {
1546             *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1547             CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1548             pbEncoded += lenBytes;
1549             switch (entry->dwAltNameChoice)
1550             {
1551             case CERT_ALT_NAME_RFC822_NAME:
1552             case CERT_ALT_NAME_DNS_NAME:
1553             case CERT_ALT_NAME_URL:
1554             {
1555                 DWORD i;
1556
1557                 for (i = 0; i < dataLen; i++)
1558                     *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1559                 break;
1560             }
1561             case CERT_ALT_NAME_IP_ADDRESS:
1562                 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1563                 break;
1564             }
1565             if (ret)
1566                 *pcbEncoded = bytesNeeded;
1567         }
1568     }
1569     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1570     return ret;
1571 }
1572
1573 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1574  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1575  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1576 {
1577     BOOL ret;
1578
1579     __TRY
1580     {
1581         const CERT_ALT_NAME_INFO *info =
1582          (const CERT_ALT_NAME_INFO *)pvStructInfo;
1583
1584         DWORD bytesNeeded, dataLen, lenBytes, i;
1585
1586         ret = TRUE;
1587         /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1588          * can't encode an erroneous entry index if it's bigger than this.
1589          */
1590         for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1591         {
1592             DWORD len;
1593
1594             ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1595              &len);
1596             if (ret)
1597                 dataLen += len;
1598             else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1599             {
1600                 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1601                  * the bad character, now set the index of the bad
1602                  * entry
1603                  */
1604                 *pcbEncoded = (BYTE)i <<
1605                  CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1606             }
1607         }
1608         if (ret)
1609         {
1610             CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1611             bytesNeeded = 1 + lenBytes + dataLen;
1612             if (!pbEncoded)
1613             {
1614                 *pcbEncoded = bytesNeeded;
1615                 ret = TRUE;
1616             }
1617             else
1618             {
1619                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1620                  pbEncoded, pcbEncoded, bytesNeeded)))
1621                 {
1622                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1623                         pbEncoded = *(BYTE **)pbEncoded;
1624                     *pbEncoded++ = ASN_SEQUENCEOF;
1625                     CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1626                     pbEncoded += lenBytes;
1627                     for (i = 0; ret && i < info->cAltEntry; i++)
1628                     {
1629                         DWORD len = dataLen;
1630
1631                         ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1632                          pbEncoded, &len);
1633                         if (ret)
1634                         {
1635                             pbEncoded += len;
1636                             dataLen -= len;
1637                         }
1638                     }
1639                 }
1640             }
1641         }
1642     }
1643     __EXCEPT(page_fault)
1644     {
1645         SetLastError(STATUS_ACCESS_VIOLATION);
1646         ret = FALSE;
1647     }
1648     __ENDTRY
1649     return ret;
1650 }
1651
1652 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1653  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1654  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1655 {
1656     BOOL ret;
1657
1658     __TRY
1659     {
1660         const CERT_BASIC_CONSTRAINTS2_INFO *info =
1661          (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1662         struct AsnEncodeSequenceItem items[2] = { { 0 } };
1663         DWORD cItem = 0;
1664
1665         if (info->fCA)
1666         {
1667             items[cItem].pvStructInfo = &info->fCA;
1668             items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1669             cItem++;
1670         }
1671         if (info->fPathLenConstraint)
1672         {
1673             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1674             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1675             cItem++;
1676         }
1677         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1678          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1679     }
1680     __EXCEPT(page_fault)
1681     {
1682         SetLastError(STATUS_ACCESS_VIOLATION);
1683         ret = FALSE;
1684     }
1685     __ENDTRY
1686     return ret;
1687 }
1688
1689 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
1690  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1691  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1692 {
1693     BOOL ret;
1694
1695     __TRY
1696     {
1697         const BLOBHEADER *hdr =
1698          (const BLOBHEADER *)pvStructInfo;
1699
1700         if (hdr->bType != PUBLICKEYBLOB)
1701         {
1702             SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1703             ret = FALSE;
1704         }
1705         else
1706         {
1707             const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
1708              ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
1709             CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
1710              (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
1711             struct AsnEncodeSequenceItem items[] = { 
1712              { &blob, CRYPT_AsnEncodeInteger, 0 },
1713              { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
1714             };
1715
1716             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1717              sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1718              pcbEncoded);
1719         }
1720     }
1721     __EXCEPT(page_fault)
1722     {
1723         SetLastError(STATUS_ACCESS_VIOLATION);
1724         ret = FALSE;
1725     }
1726     __ENDTRY
1727     return ret;
1728 }
1729
1730 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1731  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1732  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1733 {
1734     BOOL ret;
1735
1736     __TRY
1737     {
1738         const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1739         DWORD bytesNeeded, lenBytes;
1740
1741         TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1742          dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1743
1744         CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1745         bytesNeeded = 1 + lenBytes + blob->cbData;
1746         if (!pbEncoded)
1747         {
1748             *pcbEncoded = bytesNeeded;
1749             ret = TRUE;
1750         }
1751         else
1752         {
1753             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1754              pcbEncoded, bytesNeeded)))
1755             {
1756                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1757                     pbEncoded = *(BYTE **)pbEncoded;
1758                 *pbEncoded++ = ASN_OCTETSTRING;
1759                 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1760                 pbEncoded += lenBytes;
1761                 if (blob->cbData)
1762                     memcpy(pbEncoded, blob->pbData, blob->cbData);
1763             }
1764         }
1765     }
1766     __EXCEPT(page_fault)
1767     {
1768         SetLastError(STATUS_ACCESS_VIOLATION);
1769         ret = FALSE;
1770     }
1771     __ENDTRY
1772     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1773     return ret;
1774 }
1775
1776 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1777  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1778  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1779 {
1780     BOOL ret;
1781
1782     __TRY
1783     {
1784         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1785         DWORD bytesNeeded, lenBytes, dataBytes;
1786         BYTE unusedBits;
1787
1788         /* yep, MS allows cUnusedBits to be >= 8 */
1789         if (!blob->cUnusedBits)
1790         {
1791             dataBytes = blob->cbData;
1792             unusedBits = 0;
1793         }
1794         else if (blob->cbData * 8 > blob->cUnusedBits)
1795         {
1796             dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1797             unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1798              blob->cUnusedBits;
1799         }
1800         else
1801         {
1802             dataBytes = 0;
1803             unusedBits = 0;
1804         }
1805         CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1806         bytesNeeded = 1 + lenBytes + dataBytes + 1;
1807         if (!pbEncoded)
1808         {
1809             *pcbEncoded = bytesNeeded;
1810             ret = TRUE;
1811         }
1812         else
1813         {
1814             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1815              pcbEncoded, bytesNeeded)))
1816             {
1817                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1818                     pbEncoded = *(BYTE **)pbEncoded;
1819                 *pbEncoded++ = ASN_BITSTRING;
1820                 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1821                 pbEncoded += lenBytes;
1822                 *pbEncoded++ = unusedBits;
1823                 if (dataBytes)
1824                 {
1825                     BYTE mask = 0xff << unusedBits;
1826
1827                     if (dataBytes > 1)
1828                     {
1829                         memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1830                         pbEncoded += dataBytes - 1;
1831                     }
1832                     *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1833                 }
1834             }
1835         }
1836     }
1837     __EXCEPT(page_fault)
1838     {
1839         SetLastError(STATUS_ACCESS_VIOLATION);
1840         ret = FALSE;
1841     }
1842     __ENDTRY
1843     return ret;
1844 }
1845
1846 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
1847  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1848  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1849 {
1850     BOOL ret;
1851
1852     __TRY
1853     {
1854         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1855         CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
1856
1857         ret = TRUE;
1858         if (newBlob.cbData)
1859         {
1860             newBlob.pbData = HeapAlloc(GetProcessHeap(), 0, newBlob.cbData);
1861             if (newBlob.pbData)
1862             {
1863                 DWORD i;
1864
1865                 for (i = 0; i < newBlob.cbData; i++)
1866                     newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
1867             }
1868             else
1869                 ret = FALSE;
1870         }
1871         if (ret)
1872             ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
1873              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1874         HeapFree(GetProcessHeap(), 0, newBlob.pbData);
1875     }
1876     __EXCEPT(page_fault)
1877     {
1878         SetLastError(STATUS_ACCESS_VIOLATION);
1879         ret = FALSE;
1880     }
1881     __ENDTRY
1882     return ret;
1883 }
1884
1885 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1886  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1887  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1888 {
1889     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1890
1891     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1892      &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1893 }
1894
1895 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1896  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1897  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1898 {
1899     BOOL ret;
1900
1901     __TRY
1902     {
1903         DWORD significantBytes, lenBytes;
1904         BYTE padByte = 0, bytesNeeded;
1905         BOOL pad = FALSE;
1906         const CRYPT_INTEGER_BLOB *blob =
1907          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1908
1909         significantBytes = blob->cbData;
1910         if (significantBytes)
1911         {
1912             if (blob->pbData[significantBytes - 1] & 0x80)
1913             {
1914                 /* negative, lop off leading (little-endian) 0xffs */
1915                 for (; significantBytes > 0 &&
1916                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1917                     ;
1918                 if (blob->pbData[significantBytes - 1] < 0x80)
1919                 {
1920                     padByte = 0xff;
1921                     pad = TRUE;
1922                 }
1923             }
1924             else
1925             {
1926                 /* positive, lop off leading (little-endian) zeroes */
1927                 for (; significantBytes > 0 &&
1928                  !blob->pbData[significantBytes - 1]; significantBytes--)
1929                     ;
1930                 if (significantBytes == 0)
1931                     significantBytes = 1;
1932                 if (blob->pbData[significantBytes - 1] > 0x7f)
1933                 {
1934                     padByte = 0;
1935                     pad = TRUE;
1936                 }
1937             }
1938         }
1939         if (pad)
1940             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1941         else
1942             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1943         bytesNeeded = 1 + lenBytes + significantBytes;
1944         if (pad)
1945             bytesNeeded++;
1946         if (!pbEncoded)
1947         {
1948             *pcbEncoded = bytesNeeded;
1949             ret = TRUE;
1950         }
1951         else
1952         {
1953             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1954              pcbEncoded, bytesNeeded)))
1955             {
1956                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1957                     pbEncoded = *(BYTE **)pbEncoded;
1958                 *pbEncoded++ = ASN_INTEGER;
1959                 if (pad)
1960                 {
1961                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1962                     pbEncoded += lenBytes;
1963                     *pbEncoded++ = padByte;
1964                 }
1965                 else
1966                 {
1967                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1968                     pbEncoded += lenBytes;
1969                 }
1970                 for (; significantBytes > 0; significantBytes--)
1971                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
1972             }
1973         }
1974     }
1975     __EXCEPT(page_fault)
1976     {
1977         SetLastError(STATUS_ACCESS_VIOLATION);
1978         ret = FALSE;
1979     }
1980     __ENDTRY
1981     return ret;
1982 }
1983
1984 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1985  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1986  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1987 {
1988     BOOL ret;
1989
1990     __TRY
1991     {
1992         DWORD significantBytes, lenBytes;
1993         BYTE bytesNeeded;
1994         BOOL pad = FALSE;
1995         const CRYPT_INTEGER_BLOB *blob =
1996          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1997
1998         significantBytes = blob->cbData;
1999         if (significantBytes)
2000         {
2001             /* positive, lop off leading (little-endian) zeroes */
2002             for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2003              significantBytes--)
2004                 ;
2005             if (significantBytes == 0)
2006                 significantBytes = 1;
2007             if (blob->pbData[significantBytes - 1] > 0x7f)
2008                 pad = TRUE;
2009         }
2010         if (pad)
2011             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2012         else
2013             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2014         bytesNeeded = 1 + lenBytes + significantBytes;
2015         if (pad)
2016             bytesNeeded++;
2017         if (!pbEncoded)
2018         {
2019             *pcbEncoded = bytesNeeded;
2020             ret = TRUE;
2021         }
2022         else
2023         {
2024             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2025              pcbEncoded, bytesNeeded)))
2026             {
2027                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2028                     pbEncoded = *(BYTE **)pbEncoded;
2029                 *pbEncoded++ = ASN_INTEGER;
2030                 if (pad)
2031                 {
2032                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2033                     pbEncoded += lenBytes;
2034                     *pbEncoded++ = 0;
2035                 }
2036                 else
2037                 {
2038                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2039                     pbEncoded += lenBytes;
2040                 }
2041                 for (; significantBytes > 0; significantBytes--)
2042                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
2043             }
2044         }
2045     }
2046     __EXCEPT(page_fault)
2047     {
2048         SetLastError(STATUS_ACCESS_VIOLATION);
2049         ret = FALSE;
2050     }
2051     __ENDTRY
2052     return ret;
2053 }
2054
2055 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2056  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2057  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2058 {
2059     CRYPT_INTEGER_BLOB blob;
2060     BOOL ret;
2061
2062     /* Encode as an unsigned integer, then change the tag to enumerated */
2063     blob.cbData = sizeof(DWORD);
2064     blob.pbData = (BYTE *)pvStructInfo;
2065     ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2066      X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2067     if (ret && pbEncoded)
2068     {
2069         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2070             pbEncoded = *(BYTE **)pbEncoded;
2071         pbEncoded[0] = ASN_ENUMERATED;
2072     }
2073     return ret;
2074 }
2075
2076 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2077  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2078  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2079 {
2080     BOOL ret;
2081
2082     __TRY
2083     {
2084         SYSTEMTIME sysTime;
2085         /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
2086          * temporary buffer because the output buffer is not NULL-terminated.
2087          */
2088         char buf[16];
2089         static const DWORD bytesNeeded = sizeof(buf) - 1;
2090
2091         if (!pbEncoded)
2092         {
2093             *pcbEncoded = bytesNeeded;
2094             ret = TRUE;
2095         }
2096         else
2097         {
2098             /* Sanity check the year, this is a two-digit year format */
2099             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2100              &sysTime);
2101             if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2102             {
2103                 SetLastError(CRYPT_E_BAD_ENCODE);
2104                 ret = FALSE;
2105             }
2106             if (ret)
2107             {
2108                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2109                  pbEncoded, pcbEncoded, bytesNeeded)))
2110                 {
2111                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2112                         pbEncoded = *(BYTE **)pbEncoded;
2113                     buf[0] = ASN_UTCTIME;
2114                     buf[1] = bytesNeeded - 2;
2115                     snprintf(buf + 2, sizeof(buf) - 2,
2116                      "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2117                      sysTime.wYear - 2000 : sysTime.wYear - 1900,
2118                      sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2119                      sysTime.wMinute, sysTime.wSecond);
2120                     memcpy(pbEncoded, buf, bytesNeeded);
2121                 }
2122             }
2123         }
2124     }
2125     __EXCEPT(page_fault)
2126     {
2127         SetLastError(STATUS_ACCESS_VIOLATION);
2128         ret = FALSE;
2129     }
2130     __ENDTRY
2131     return ret;
2132 }
2133
2134 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2135  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2136  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2137 {
2138     BOOL ret;
2139
2140     __TRY
2141     {
2142         SYSTEMTIME sysTime;
2143         /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
2144          * temporary buffer because the output buffer is not NULL-terminated.
2145          */
2146         char buf[18];
2147         static const DWORD bytesNeeded = sizeof(buf) - 1;
2148
2149         if (!pbEncoded)
2150         {
2151             *pcbEncoded = bytesNeeded;
2152             ret = TRUE;
2153         }
2154         else
2155         {
2156             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2157              &sysTime);
2158             if (ret)
2159                 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2160                  pcbEncoded, bytesNeeded);
2161             if (ret)
2162             {
2163                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2164                     pbEncoded = *(BYTE **)pbEncoded;
2165                 buf[0] = ASN_GENERALTIME;
2166                 buf[1] = bytesNeeded - 2;
2167                 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2168                  sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2169                  sysTime.wMinute, sysTime.wSecond);
2170                 memcpy(pbEncoded, buf, bytesNeeded);
2171             }
2172         }
2173     }
2174     __EXCEPT(page_fault)
2175     {
2176         SetLastError(STATUS_ACCESS_VIOLATION);
2177         ret = FALSE;
2178     }
2179     __ENDTRY
2180     return ret;
2181 }
2182
2183 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2184  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2185  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2186 {
2187     BOOL ret;
2188
2189     __TRY
2190     {
2191         SYSTEMTIME sysTime;
2192
2193         /* Check the year, if it's in the UTCTime range call that encode func */
2194         if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2195             return FALSE;
2196         if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2197             ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2198              pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2199         else
2200             ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2201              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2202              pcbEncoded);
2203     }
2204     __EXCEPT(page_fault)
2205     {
2206         SetLastError(STATUS_ACCESS_VIOLATION);
2207         ret = FALSE;
2208     }
2209     __ENDTRY
2210     return ret;
2211 }
2212
2213 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2214  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2215  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2216 {
2217     BOOL ret;
2218
2219     __TRY
2220     {
2221         DWORD bytesNeeded, dataLen, lenBytes, i;
2222         const CRYPT_SEQUENCE_OF_ANY *seq =
2223          (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2224
2225         for (i = 0, dataLen = 0; i < seq->cValue; i++)
2226             dataLen += seq->rgValue[i].cbData;
2227         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2228         bytesNeeded = 1 + lenBytes + dataLen;
2229         if (!pbEncoded)
2230         {
2231             *pcbEncoded = bytesNeeded;
2232             ret = TRUE;
2233         }
2234         else
2235         {
2236             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2237              pcbEncoded, bytesNeeded)))
2238             {
2239                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2240                     pbEncoded = *(BYTE **)pbEncoded;
2241                 *pbEncoded++ = ASN_SEQUENCEOF;
2242                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2243                 pbEncoded += lenBytes;
2244                 for (i = 0; i < seq->cValue; i++)
2245                 {
2246                     memcpy(pbEncoded, seq->rgValue[i].pbData,
2247                      seq->rgValue[i].cbData);
2248                     pbEncoded += seq->rgValue[i].cbData;
2249                 }
2250             }
2251         }
2252     }
2253     __EXCEPT(page_fault)
2254     {
2255         SetLastError(STATUS_ACCESS_VIOLATION);
2256         ret = FALSE;
2257     }
2258     __ENDTRY
2259     return ret;
2260 }
2261
2262 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2263  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2264  void *pvEncoded, DWORD *pcbEncoded)
2265 {
2266     BOOL ret = FALSE;
2267     HMODULE lib = NULL;
2268     CryptEncodeObjectExFunc encodeFunc = NULL;
2269
2270     TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2271      debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2272      pvEncoded, pcbEncoded);
2273
2274     if (!pvEncoded && !pcbEncoded)
2275     {
2276         SetLastError(ERROR_INVALID_PARAMETER);
2277         return FALSE;
2278     }
2279     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2280      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2281     {
2282         SetLastError(ERROR_FILE_NOT_FOUND);
2283         return FALSE;
2284     }
2285
2286     SetLastError(NOERROR);
2287     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2288         *(BYTE **)pvEncoded = NULL;
2289     if (!HIWORD(lpszStructType))
2290     {
2291         switch (LOWORD(lpszStructType))
2292         {
2293         case (WORD)X509_CERT:
2294             encodeFunc = CRYPT_AsnEncodeCert;
2295             break;
2296         case (WORD)X509_CERT_TO_BE_SIGNED:
2297             encodeFunc = CRYPT_AsnEncodeCertInfo;
2298             break;
2299         case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2300             encodeFunc = CRYPT_AsnEncodeCRLInfo;
2301             break;
2302         case (WORD)X509_EXTENSIONS:
2303             encodeFunc = CRYPT_AsnEncodeExtensions;
2304             break;
2305         case (WORD)X509_NAME:
2306             encodeFunc = CRYPT_AsnEncodeName;
2307             break;
2308         case (WORD)X509_PUBLIC_KEY_INFO:
2309             encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2310             break;
2311         case (WORD)X509_ALTERNATE_NAME:
2312             encodeFunc = CRYPT_AsnEncodeAltName;
2313             break;
2314         case (WORD)X509_BASIC_CONSTRAINTS2:
2315             encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2316             break;
2317         case (WORD)RSA_CSP_PUBLICKEYBLOB:
2318             encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2319             break;
2320         case (WORD)X509_OCTET_STRING:
2321             encodeFunc = CRYPT_AsnEncodeOctets;
2322             break;
2323         case (WORD)X509_BITS:
2324         case (WORD)X509_KEY_USAGE:
2325             encodeFunc = CRYPT_AsnEncodeBits;
2326             break;
2327         case (WORD)X509_INTEGER:
2328             encodeFunc = CRYPT_AsnEncodeInt;
2329             break;
2330         case (WORD)X509_MULTI_BYTE_INTEGER:
2331             encodeFunc = CRYPT_AsnEncodeInteger;
2332             break;
2333         case (WORD)X509_MULTI_BYTE_UINT:
2334             encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2335             break;
2336         case (WORD)X509_ENUMERATED:
2337             encodeFunc = CRYPT_AsnEncodeEnumerated;
2338             break;
2339         case (WORD)X509_CHOICE_OF_TIME:
2340             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2341             break;
2342         case (WORD)X509_SEQUENCE_OF_ANY:
2343             encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2344             break;
2345         case (WORD)PKCS_UTC_TIME:
2346             encodeFunc = CRYPT_AsnEncodeUtcTime;
2347             break;
2348         default:
2349             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2350         }
2351     }
2352     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2353         encodeFunc = CRYPT_AsnEncodeExtensions;
2354     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2355         encodeFunc = CRYPT_AsnEncodeUtcTime;
2356     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2357         encodeFunc = CRYPT_AsnEncodeEnumerated;
2358     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2359         encodeFunc = CRYPT_AsnEncodeBits;
2360     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2361         encodeFunc = CRYPT_AsnEncodeOctets;
2362     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2363         encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2364     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2365         encodeFunc = CRYPT_AsnEncodeAltName;
2366     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2367         encodeFunc = CRYPT_AsnEncodeAltName;
2368     else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2369         encodeFunc = CRYPT_AsnEncodeAltName;
2370     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2371         encodeFunc = CRYPT_AsnEncodeAltName;
2372     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2373         encodeFunc = CRYPT_AsnEncodeAltName;
2374     else
2375         TRACE("OID %s not found or unimplemented, looking for DLL\n",
2376          debugstr_a(lpszStructType));
2377     if (!encodeFunc)
2378         encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
2379          lpszStructType, "CryptEncodeObjectEx", &lib);
2380     if (encodeFunc)
2381         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2382          dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2383     else
2384         SetLastError(ERROR_FILE_NOT_FOUND);
2385     if (lib)
2386         FreeLibrary(lib);
2387     return ret;
2388 }
2389
2390 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2391  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
2392  DWORD *pcbStructInfo)
2393 {
2394     BOOL ret = FALSE;
2395     HMODULE lib;
2396     CryptDecodeObjectFunc pCryptDecodeObject;
2397
2398     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType,
2399      debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
2400      pvStructInfo, pcbStructInfo);
2401
2402     if (!pvStructInfo && !pcbStructInfo)
2403     {
2404         SetLastError(ERROR_INVALID_PARAMETER);
2405         return FALSE;
2406     }
2407
2408     /* Try registered DLL first.. */
2409     pCryptDecodeObject =
2410      (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
2411      lpszStructType, "CryptDecodeObject", &lib);
2412     if (pCryptDecodeObject)
2413     {
2414         ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
2415          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
2416         FreeLibrary(lib);
2417     }
2418     else
2419     {
2420         /* If not, use CryptDecodeObjectEx */
2421         ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
2422          cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
2423     }
2424     return ret;
2425 }
2426
2427 /* Gets the number of length bytes from the given (leading) length byte */
2428 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
2429
2430 /* Helper function to get the encoded length of the data starting at pbEncoded,
2431  * where pbEncoded[0] is the tag.  If the data are too short to contain a
2432  * length or if the length is too large for cbEncoded, sets an appropriate
2433  * error code and returns FALSE.
2434  */
2435 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
2436  DWORD *len)
2437 {
2438     BOOL ret;
2439
2440     if (cbEncoded <= 1)
2441     {
2442         SetLastError(CRYPT_E_ASN1_CORRUPT);
2443         ret = FALSE;
2444     }
2445     else if (pbEncoded[1] <= 0x7f)
2446     {
2447         if (pbEncoded[1] + 1 > cbEncoded)
2448         {
2449             SetLastError(CRYPT_E_ASN1_EOD);
2450             ret = FALSE;
2451         }
2452         else
2453         {
2454             *len = pbEncoded[1];
2455             ret = TRUE;
2456         }
2457     }
2458     else
2459     {
2460         BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
2461
2462         if (lenLen > sizeof(DWORD) + 1)
2463         {
2464             SetLastError(CRYPT_E_ASN1_LARGE);
2465             ret = FALSE;
2466         }
2467         else if (lenLen + 2 > cbEncoded)
2468         {
2469             SetLastError(CRYPT_E_ASN1_CORRUPT);
2470             ret = FALSE;
2471         }
2472         else
2473         {
2474             DWORD out = 0;
2475
2476             pbEncoded += 2;
2477             while (--lenLen)
2478             {
2479                 out <<= 8;
2480                 out |= *pbEncoded++;
2481             }
2482             if (out + lenLen + 1 > cbEncoded)
2483             {
2484                 SetLastError(CRYPT_E_ASN1_EOD);
2485                 ret = FALSE;
2486             }
2487             else
2488             {
2489                 *len = out;
2490                 ret = TRUE;
2491             }
2492         }
2493     }
2494     return ret;
2495 }
2496
2497 /* Helper function to check *pcbStructInfo, set it to the required size, and
2498  * optionally to allocate memory.  Assumes pvStructInfo is not NULL.
2499  * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
2500  * pointer to the newly allocated memory.
2501  */
2502 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
2503  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2504  DWORD bytesNeeded)
2505 {
2506     BOOL ret = TRUE;
2507
2508     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2509     {
2510         if (pDecodePara && pDecodePara->pfnAlloc)
2511             *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
2512         else
2513             *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
2514         if (!*(BYTE **)pvStructInfo)
2515             ret = FALSE;
2516         else
2517             *pcbStructInfo = bytesNeeded;
2518     }
2519     else if (*pcbStructInfo < bytesNeeded)
2520     {
2521         *pcbStructInfo = bytesNeeded;
2522         SetLastError(ERROR_MORE_DATA);
2523         ret = FALSE;
2524     }
2525     return ret;
2526 }
2527
2528 /* A few of the members need explanation:
2529  * offset:
2530  *     A sequence is decoded into a struct.  The offset member is the
2531  *     offset of this item within that struct.
2532  * decodeFunc:
2533  *     The decoder function to use.  If this is NULL, then the member isn't
2534  *     decoded, but minSize space is reserved for it.
2535  * minSize:
2536  *     The minimum amount of space occupied after decoding.  You must set this.
2537  * optional:
2538  *     If true, and a decoding function fails with CRYPT_E_ASN1_BADTAG, then
2539  *     minSize space is filled with 0 for this member.  (Any other failure
2540  *     results in CRYPT_AsnDecodeSequence failing.)
2541  * hasPointer, pointerOffset, minSize:
2542  *     If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
2543  *     the offset within the (outer) struct of the data pointer (or to the
2544  *     first data pointer, if more than one exist).
2545  * size:
2546  *     Used by CRYPT_AsnDecodeSequence, not for your use.
2547  */
2548 struct AsnDecodeSequenceItem
2549 {
2550     DWORD                   offset;
2551     CryptDecodeObjectExFunc decodeFunc;
2552     DWORD                   minSize;
2553     BOOL                    optional;
2554     BOOL                    hasPointer;
2555     DWORD                   pointerOffset;
2556     DWORD                   size;
2557 };
2558
2559 /* This decodes an arbitrary sequence into a contiguous block of memory
2560  * (basically, a struct.)  Each element being decoded is described by a struct
2561  * AsnDecodeSequenceItem, see above.
2562  * startingPointer is an optional pointer to the first place where dynamic
2563  * data will be stored.  If you know the starting offset, you may pass it
2564  * here.  Otherwise, pass NULL, and one will be inferred from the items.
2565  * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
2566  * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
2567  */
2568 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
2569  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2570  DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
2571  void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer)
2572 {
2573     BOOL ret;
2574
2575     TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld, %p\n", items, cItem, pbEncoded,
2576      cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
2577      startingPointer);
2578
2579     if (pbEncoded[0] == ASN_SEQUENCE)
2580     {
2581         DWORD dataLen;
2582
2583         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2584         {
2585             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2586             DWORD i, bytesNeeded = 0, minSize = 0;
2587             const BYTE *ptr;
2588
2589             ptr = pbEncoded + 1 + lenBytes;
2590             for (i = 0; ret && i < cItem; i++)
2591             {
2592                 DWORD nextItemLen;
2593
2594                 minSize += items[i].minSize;
2595                 if (cbEncoded - (ptr - pbEncoded) != 0)
2596                 {
2597                     if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2598                      &nextItemLen)))
2599                     {
2600                         BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2601
2602                         if (items[i].decodeFunc)
2603                         {
2604                             TRACE("sizing item %ld\n", i);
2605                             ret = items[i].decodeFunc(dwCertEncodingType, NULL,
2606                              ptr, 1 + nextItemLenBytes + nextItemLen,
2607                              dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
2608                              &items[i].size);
2609                             if (ret)
2610                             {
2611                                 /* Account for alignment padding */
2612                                 bytesNeeded += items[i].size;
2613                                 if (items[i].size % sizeof(DWORD))
2614                                     bytesNeeded += sizeof(DWORD) -
2615                                      items[i].size % sizeof(DWORD);
2616                                 ptr += 1 + nextItemLenBytes + nextItemLen;
2617                             }
2618                             else if (items[i].optional &&
2619                              GetLastError() == CRYPT_E_ASN1_BADTAG)
2620                             {
2621                                 TRACE("skipping optional item %ld\n", i);
2622                                 bytesNeeded += items[i].minSize;
2623                                 SetLastError(NOERROR);
2624                                 ret = TRUE;
2625                             }
2626                             else
2627                                 TRACE("item %ld failed: %08lx\n", i,
2628                                  GetLastError());
2629                         }
2630                         else
2631                             bytesNeeded += items[i].minSize;
2632                     }
2633                 }
2634                 else if (items[i].optional)
2635                     bytesNeeded += items[i].minSize;
2636                 else
2637                 {
2638                     SetLastError(CRYPT_E_ASN1_CORRUPT);
2639                     ret = FALSE;
2640                 }
2641             }
2642             if (cbEncoded - (ptr - pbEncoded) != 0)
2643             {
2644                 TRACE("%ld remaining bytes, failing\n", cbEncoded -
2645                  (ptr - pbEncoded));
2646                 SetLastError(CRYPT_E_ASN1_CORRUPT);
2647                 ret = FALSE;
2648             }
2649             if (ret)
2650             {
2651                 if (!pvStructInfo)
2652                     *pcbStructInfo = bytesNeeded;
2653                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2654                  pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2655                 {
2656                     BYTE *nextData;
2657
2658                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2659                         pvStructInfo = *(BYTE **)pvStructInfo;
2660                     if (startingPointer)
2661                         nextData = (BYTE *)startingPointer;
2662                     else
2663                         nextData = (BYTE *)pvStructInfo + minSize;
2664                     memset(pvStructInfo, 0, minSize);
2665                     ptr = pbEncoded + 1 + lenBytes;
2666                     for (i = 0; ret && i < cItem; i++)
2667                     {
2668                         if (cbEncoded - (ptr - pbEncoded) != 0)
2669                         {
2670                             DWORD nextItemLen;
2671                             BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2672
2673                             CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2674                              &nextItemLen);
2675                             if (items[i].hasPointer)
2676                             {
2677                                 *(BYTE **)((BYTE *)pvStructInfo +
2678                                  items[i].pointerOffset) = nextData;
2679                             }
2680                             if (items[i].decodeFunc)
2681                             {
2682                                 TRACE("decoding item %ld\n", i);
2683                                 ret = items[i].decodeFunc(dwCertEncodingType,
2684                                  NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
2685                                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2686                                  (BYTE *)pvStructInfo + items[i].offset,
2687                                  &items[i].size);
2688                                 if (!ret)
2689                                     TRACE("item %ld failed: %08lx\n", i,
2690                                      GetLastError());
2691                             }
2692                             else
2693                                 items[i].size = items[i].minSize;
2694                             if (ret)
2695                             {
2696                                 if (items[i].hasPointer &&
2697                                  items[i].size > items[i].minSize)
2698                                 {
2699                                     nextData += items[i].size -
2700                                      items[i].minSize;
2701                                     /* align nextData to DWORD boundaries */
2702                                     if (items[i].size % sizeof(DWORD))
2703                                     {
2704                                         nextData += sizeof(DWORD) -
2705                                          items[i].size % sizeof(DWORD);
2706                                     }
2707                                 }
2708                                 ptr += 1 + nextItemLenBytes + nextItemLen;
2709                             }
2710                             else if (items[i].optional &&
2711                              GetLastError() == CRYPT_E_ASN1_BADTAG)
2712                             {
2713                                 SetLastError(NOERROR);
2714                                 ret = TRUE;
2715                             }
2716                         }
2717                         else if (!items[i].optional)
2718                         {
2719                             SetLastError(CRYPT_E_ASN1_CORRUPT);
2720                             ret = FALSE;
2721                         }
2722                     }
2723                 }
2724             }
2725         }
2726     }
2727     else
2728     {
2729         SetLastError(CRYPT_E_ASN1_BADTAG);
2730         ret = FALSE;
2731     }
2732     TRACE("returning %d (%08lx)\n", ret, GetLastError());
2733     return ret;
2734 }
2735
2736 /* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
2737  * pvStructInfo.  The BLOB must be non-empty, otherwise the last error is set
2738  * to CRYPT_E_ASN1_CORRUPT.
2739  * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
2740  * set!
2741  */
2742 static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
2743  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2744  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2745 {
2746     BOOL ret;
2747     DWORD dataLen;
2748
2749     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2750     {
2751         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2752         DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
2753        
2754         if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2755             bytesNeeded += 1 + lenBytes + dataLen;
2756
2757         if (!pvStructInfo)
2758             *pcbStructInfo = bytesNeeded;
2759         else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, 
2760          pvStructInfo, pcbStructInfo, bytesNeeded)))
2761         {
2762             CRYPT_DER_BLOB *blob = (CRYPT_DER_BLOB *)pvStructInfo;
2763
2764             blob->cbData = 1 + lenBytes + dataLen;
2765             if (blob->cbData)
2766             {
2767                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2768                     blob->pbData = (BYTE *)pbEncoded;
2769                 else
2770                 {
2771                     assert(blob->pbData);
2772                     memcpy(blob->pbData, pbEncoded, blob->cbData);
2773                 }
2774             }
2775             else
2776             {
2777                 SetLastError(CRYPT_E_ASN1_CORRUPT);
2778                 ret = FALSE;
2779             }
2780         }
2781     }
2782     return ret;
2783 }
2784
2785 /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */
2786 static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType,
2787  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2788  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2789 {
2790     BOOL ret;
2791
2792     TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
2793      pDecodePara, pvStructInfo, *pcbStructInfo);
2794
2795     /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in-
2796      * place.
2797      */
2798     ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType,
2799      pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pDecodePara,
2800      pvStructInfo, pcbStructInfo);
2801     if (ret && pvStructInfo)
2802     {
2803         CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
2804
2805         if (blob->cbData)
2806         {
2807             DWORD i;
2808             BYTE temp;
2809
2810             for (i = 0; i < blob->cbData / 2; i++)
2811             {
2812                 temp = blob->pbData[i];
2813                 blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
2814                 blob->pbData[blob->cbData - i - 1] = temp;
2815             }
2816         }
2817     }
2818     TRACE("returning %d (%08lx)\n", ret, GetLastError());
2819     return ret;
2820 }
2821
2822 static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
2823  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2824  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2825 {
2826     BOOL ret = TRUE;
2827
2828     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2829      pDecodePara, pvStructInfo, *pcbStructInfo);
2830
2831     __TRY
2832     {
2833         struct AsnDecodeSequenceItem items[] = {
2834          { offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
2835            CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2836            offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 },
2837          { offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm),
2838            CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
2839            FALSE, TRUE, offsetof(CERT_SIGNED_CONTENT_INFO,
2840            SignatureAlgorithm.pszObjId), 0 },
2841          { offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
2842            CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
2843            offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 },
2844         };
2845
2846         if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
2847             items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
2848         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2849          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2850          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2851     }
2852     __EXCEPT(page_fault)
2853     {
2854         SetLastError(STATUS_ACCESS_VIOLATION);
2855         ret = FALSE;
2856     }
2857     __ENDTRY
2858     return ret;
2859 }
2860
2861 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
2862  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2863  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2864 {
2865     BOOL ret;
2866
2867     if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR))
2868     {
2869         DWORD dataLen;
2870
2871         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2872         {
2873             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2874
2875             ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
2876              pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
2877              pvStructInfo, pcbStructInfo);
2878         }
2879     }
2880     else
2881     {
2882         SetLastError(CRYPT_E_ASN1_BADTAG);
2883         ret = FALSE;
2884     }
2885     return ret;
2886 }
2887
2888 static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
2889  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2890  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2891 {
2892     BOOL ret;
2893
2894     struct AsnDecodeSequenceItem items[] = {
2895      { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
2896        CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2897      { offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
2898        CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
2899     };
2900
2901     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2902      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2903      pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2904     return ret;
2905 }
2906
2907 static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType,
2908  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2909  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2910 {
2911     BOOL ret;
2912
2913     if (pbEncoded[0] == (ASN_CONTEXT | ASN_CONSTRUCTOR | 3))
2914     {
2915         DWORD dataLen;
2916
2917         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2918         {
2919             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2920
2921             ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
2922              X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
2923              pDecodePara, pvStructInfo, pcbStructInfo);
2924         }
2925     }
2926     else
2927     {
2928         SetLastError(CRYPT_E_ASN1_BADTAG);
2929         ret = FALSE;
2930     }
2931     return ret;
2932 }
2933
2934 static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
2935  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2936  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2937 {
2938     BOOL ret = TRUE;
2939
2940     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2941      pDecodePara, pvStructInfo, *pcbStructInfo);
2942
2943     __TRY
2944     {
2945         struct AsnDecodeSequenceItem items[] = {
2946          { offsetof(CERT_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
2947            sizeof(DWORD), TRUE, FALSE, 0, 0 },
2948          { offsetof(CERT_INFO, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2949            sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2950            SerialNumber.pbData), 0 },
2951          { offsetof(CERT_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
2952            sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CERT_INFO,
2953            SignatureAlgorithm.pszObjId), 0 },
2954          { offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
2955            sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2956            Issuer.pbData) },
2957          { offsetof(CERT_INFO, NotBefore), CRYPT_AsnDecodeValidity,
2958            sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE, FALSE, 0 },
2959          { offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
2960            sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
2961            Subject.pbData) },
2962          { offsetof(CERT_INFO, SubjectPublicKeyInfo), CRYPT_AsnDecodePubKeyInfo,
2963            sizeof(CERT_PUBLIC_KEY_INFO), FALSE, TRUE, offsetof(CERT_INFO,
2964            SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
2965          { offsetof(CERT_INFO, IssuerUniqueId), CRYPT_AsnDecodeBitsInternal,
2966            sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2967            IssuerUniqueId.pbData), 0 },
2968          { offsetof(CERT_INFO, SubjectUniqueId), CRYPT_AsnDecodeBitsInternal,
2969            sizeof(CRYPT_BIT_BLOB), TRUE, TRUE, offsetof(CERT_INFO,
2970            SubjectUniqueId.pbData), 0 },
2971          { offsetof(CERT_INFO, cExtension), CRYPT_AsnDecodeCertExtensions,
2972            sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CERT_INFO,
2973            rgExtension), 0 },
2974         };
2975
2976         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2977          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2978          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2979     }
2980     __EXCEPT(page_fault)
2981     {
2982         SetLastError(STATUS_ACCESS_VIOLATION);
2983         ret = FALSE;
2984     }
2985     __ENDTRY
2986     return ret;
2987 }
2988
2989 static BOOL CRYPT_AsnDecodeCRLEntry(const BYTE *pbEncoded, DWORD cbEncoded,
2990  DWORD dwFlags, PCRL_ENTRY entry, DWORD *pcbEntry)
2991 {
2992     BOOL ret;
2993     struct AsnDecodeSequenceItem items[] = {
2994      { offsetof(CRL_ENTRY, SerialNumber), CRYPT_AsnDecodeIntegerInternal,
2995        sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE, offsetof(CRL_ENTRY,
2996        SerialNumber.pbData), 0 },
2997      { offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
2998        sizeof(FILETIME), FALSE, FALSE, 0 },
2999      { offsetof(CRL_ENTRY, cExtension), CRYPT_AsnDecodeExtensionsInternal,
3000        sizeof(CERT_EXTENSIONS), TRUE, TRUE, offsetof(CRL_ENTRY,
3001        rgExtension), 0 },
3002     };
3003
3004     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry,
3005      *pcbEntry);
3006
3007     ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3008      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3009      NULL, entry, pcbEntry, entry ? entry->SerialNumber.pbData : NULL);
3010     TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3011     return ret;
3012 }
3013
3014 typedef struct _WINE_CRL_ENTRIES {
3015     DWORD      cCRLEntry;
3016     PCRL_ENTRY rgCRLEntry;
3017 } WINE_CRL_ENTRIES, *PWINE_CRL_ENTRIES;
3018
3019 /* Warning: assumes pvStructInfo is a WINE_CRL_ENTRIES whose rgCRLEntry has
3020  * been set prior to calling.
3021  */
3022 static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
3023  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3024  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3025 {
3026     BOOL ret;
3027
3028     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3029      pDecodePara, pvStructInfo, *pcbStructInfo);
3030
3031     if (pbEncoded[0] == ASN_SEQUENCEOF)
3032     {
3033         DWORD dataLen, bytesNeeded;
3034
3035         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3036         {
3037             DWORD cCRLEntry = 0;
3038             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3039
3040             bytesNeeded = sizeof(WINE_CRL_ENTRIES);
3041             if (dataLen)
3042             {
3043                 const BYTE *ptr;
3044                 DWORD size;
3045
3046                 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3047                  ptr - pbEncoded - 1 - lenBytes < dataLen; )
3048                 {
3049                     size = 0;
3050                     ret = CRYPT_AsnDecodeCRLEntry(ptr,
3051                      cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3052                     if (ret)
3053                     {
3054                         DWORD nextLen;
3055
3056                         cCRLEntry++;
3057                         bytesNeeded += size;
3058                         ret = CRYPT_GetLen(ptr,
3059                          cbEncoded - (ptr - pbEncoded), &nextLen);
3060                         if (ret)
3061                             ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3062                     }
3063                 }
3064             }
3065             if (ret)
3066             {
3067                 if (!pvStructInfo)
3068                     *pcbStructInfo = bytesNeeded;
3069                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3070                  pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3071                 {
3072                     DWORD size, i;
3073                     BYTE *nextData;
3074                     const BYTE *ptr;
3075                     PWINE_CRL_ENTRIES entries;
3076
3077                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3078                         pvStructInfo = *(BYTE **)pvStructInfo;
3079                     *pcbStructInfo = bytesNeeded;
3080                     entries = (PWINE_CRL_ENTRIES)pvStructInfo;
3081                     entries->cCRLEntry = cCRLEntry;
3082                     assert(entries->rgCRLEntry);
3083                     nextData = (BYTE *)entries->rgCRLEntry +
3084                      entries->cCRLEntry * sizeof(CRL_ENTRY);
3085                     for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3086                      i < cCRLEntry && ptr - pbEncoded - 1 - lenBytes <
3087                      dataLen; i++)
3088                     {
3089                         entries->rgCRLEntry[i].SerialNumber.pbData = nextData;
3090                         size = bytesNeeded;
3091                         ret = CRYPT_AsnDecodeCRLEntry(ptr,
3092                          cbEncoded - (ptr - pbEncoded), dwFlags,
3093                          &entries->rgCRLEntry[i], &size);
3094                         if (ret)
3095                         {
3096                             DWORD nextLen;
3097
3098                             bytesNeeded -= size;
3099                             /* Increment nextData by the difference of the
3100                              * minimum size and the actual size.
3101                              */
3102                             if (size > sizeof(CRL_ENTRY))
3103                                 nextData += size - sizeof(CRL_ENTRY);
3104                             ret = CRYPT_GetLen(ptr,
3105                              cbEncoded - (ptr - pbEncoded), &nextLen);
3106                             if (ret)
3107                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3108                         }
3109                     }
3110                 }
3111             }
3112         }
3113     }
3114     else
3115     {
3116         SetLastError(CRYPT_E_ASN1_BADTAG);
3117         ret = FALSE;
3118     }
3119     TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3120     return ret;
3121 }
3122
3123 static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
3124  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3125  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3126 {
3127     BOOL ret = TRUE;
3128
3129     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3130      pDecodePara, pvStructInfo, *pcbStructInfo);
3131
3132     __TRY
3133     {
3134         struct AsnDecodeSequenceItem items[] = {
3135          { offsetof(CRL_INFO, dwVersion), CRYPT_AsnDecodeCertVersion,
3136            sizeof(DWORD), TRUE, FALSE, 0, 0 },
3137          { offsetof(CRL_INFO, SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
3138            sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE, offsetof(CRL_INFO,
3139            SignatureAlgorithm.pszObjId), 0 },
3140          { offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
3141            sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO,
3142            Issuer.pbData) },
3143          { offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
3144            sizeof(FILETIME), FALSE, FALSE, 0 },
3145          { offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
3146            sizeof(FILETIME), TRUE, FALSE, 0 },
3147          { offsetof(CRL_INFO, cCRLEntry), CRYPT_AsnDecodeCRLEntries,
3148            sizeof(WINE_CRL_ENTRIES), TRUE, TRUE, offsetof(CRL_INFO,
3149            rgCRLEntry), 0 },
3150          /* Note that the extensions are ignored by MS, so I'll ignore them too
3151           */
3152          { offsetof(CRL_INFO, cExtension), NULL,
3153            sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 },
3154         };
3155
3156         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3157          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3158          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3159     }
3160     __EXCEPT(page_fault)
3161     {
3162         SetLastError(STATUS_ACCESS_VIOLATION);
3163         ret = FALSE;
3164     }
3165     __ENDTRY
3166
3167     TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3168     return ret;
3169 }
3170
3171 /* Differences between this and CRYPT_AsnDecodeOid:
3172  * - pvStructInfo is a LPSTR *, not an LPSTR
3173  * - CRYPT_AsnDecodeOid doesn't account for the size of an LPSTR in its byte
3174  *   count, whereas our callers (typically CRYPT_AsnDecodeSequence) expect this
3175  *   to
3176  */
3177 static BOOL WINAPI CRYPT_AsnDecodeOidWrapper(DWORD dwCertEncodingType,
3178  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3179  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3180 {
3181     BOOL ret;
3182
3183     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3184      pDecodePara, pvStructInfo, *pcbStructInfo);
3185
3186     ret = CRYPT_AsnDecodeOid(pbEncoded, cbEncoded, dwFlags,
3187      pvStructInfo ? *(LPSTR *)pvStructInfo : NULL, pcbStructInfo);
3188     if (ret || GetLastError() == ERROR_MORE_DATA)
3189         *pcbStructInfo += sizeof(LPSTR);
3190     if (ret && pvStructInfo)
3191         TRACE("returning %s\n", debugstr_a(*(LPSTR *)pvStructInfo));
3192     return ret;
3193 }
3194
3195 /* Warning:  assumes ext->pszObjId is set ahead of time! */
3196 static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
3197  DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
3198 {
3199     struct AsnDecodeSequenceItem items[] = {
3200      { offsetof(CERT_EXTENSION, pszObjId), CRYPT_AsnDecodeOidWrapper,
3201        sizeof(LPSTR), FALSE, TRUE, offsetof(CERT_EXTENSION, pszObjId), 0 },
3202      { offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool,
3203        sizeof(BOOL), TRUE, FALSE, 0, 0 },
3204      { offsetof(CERT_EXTENSION, Value), CRYPT_AsnDecodeOctetsInternal,
3205        sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE, offsetof(CERT_EXTENSION,
3206        Value.pbData) },
3207     };
3208     BOOL ret = TRUE;
3209
3210     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, ext,
3211      *pcbExt);
3212
3213     if (ext)
3214         TRACE("ext->pszObjId is %p\n", ext->pszObjId);
3215     ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3216      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
3217      ext, pcbExt, ext ? ext->pszObjId : NULL);
3218     if (ext)
3219         TRACE("ext->pszObjId is %p (%s)\n", ext->pszObjId,
3220          debugstr_a(ext->pszObjId));
3221     TRACE("returning %d (%08lx)\n", ret, GetLastError());
3222     return ret;
3223 }
3224
3225 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
3226  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3227  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3228 {
3229     BOOL ret = TRUE;
3230
3231     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3232      pDecodePara, pvStructInfo, *pcbStructInfo);
3233
3234     if (pbEncoded[0] == ASN_SEQUENCEOF)
3235     {
3236         DWORD dataLen, bytesNeeded;
3237
3238         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3239         {
3240             DWORD cExtension = 0;
3241             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3242
3243             bytesNeeded = sizeof(CERT_EXTENSIONS);
3244             if (dataLen)
3245             {
3246                 const BYTE *ptr;
3247                 DWORD size;
3248
3249                 for (ptr = pbEncoded + 1 + lenBytes; ret &&
3250                  ptr - pbEncoded - 1 - lenBytes < dataLen; )
3251                 {
3252                     size = 0;
3253                     ret = CRYPT_AsnDecodeExtension(ptr,
3254                      cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3255                     if (ret)
3256                     {
3257                         DWORD nextLen;
3258
3259                         cExtension++;
3260                         bytesNeeded += size;
3261                         ret = CRYPT_GetLen(ptr,
3262                          cbEncoded - (ptr - pbEncoded), &nextLen);
3263                         if (ret)
3264                             ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3265                     }
3266                 }
3267             }
3268             if (ret)
3269             {
3270                 if (!pvStructInfo)
3271                     *pcbStructInfo = bytesNeeded;
3272                 else if (*pcbStructInfo < bytesNeeded)
3273                 {
3274                     SetLastError(ERROR_MORE_DATA);
3275                     *pcbStructInfo = bytesNeeded;
3276                     ret = FALSE;
3277                 }
3278                 else
3279                 {
3280                     DWORD size, i;
3281                     BYTE *nextData;
3282                     const BYTE *ptr;
3283                     CERT_EXTENSIONS *exts;
3284
3285                     *pcbStructInfo = bytesNeeded;
3286                     exts = (CERT_EXTENSIONS *)pvStructInfo;
3287                     exts->cExtension = cExtension;
3288                     assert(exts->rgExtension);
3289                     nextData = (BYTE *)exts->rgExtension +
3290                      exts->cExtension * sizeof(CERT_EXTENSION);
3291                     for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3292                      i < cExtension && ptr - pbEncoded - 1 - lenBytes <
3293                      dataLen; i++)
3294                     {
3295                         exts->rgExtension[i].pszObjId = (LPSTR)nextData;
3296                         size = bytesNeeded;
3297                         ret = CRYPT_AsnDecodeExtension(ptr,
3298                          cbEncoded - (ptr - pbEncoded), dwFlags,
3299                          &exts->rgExtension[i], &size);
3300                         if (ret)
3301                         {
3302                             DWORD nextLen;
3303
3304                             bytesNeeded -= size;
3305                             if (size > sizeof(CERT_EXTENSION))
3306                                 nextData += size - sizeof(CERT_EXTENSION);
3307                             ret = CRYPT_GetLen(ptr,
3308                              cbEncoded - (ptr - pbEncoded), &nextLen);
3309                             if (ret)
3310                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3311                         }
3312                     }
3313                 }
3314             }
3315         }
3316     }
3317     else
3318     {
3319         SetLastError(CRYPT_E_ASN1_BADTAG);
3320         ret = FALSE;
3321     }
3322     return ret;
3323 }
3324
3325 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
3326  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3327  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3328 {
3329     BOOL ret = TRUE;
3330
3331     __TRY
3332     {
3333         ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3334          lpszStructType, pbEncoded, cbEncoded,
3335          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
3336         if (ret && pvStructInfo)
3337         {
3338             ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
3339              pcbStructInfo, *pcbStructInfo);
3340             if (ret)
3341             {
3342                 CERT_EXTENSIONS *exts;
3343
3344                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3345                     pvStructInfo = *(BYTE **)pvStructInfo;
3346                 exts = (CERT_EXTENSIONS *)pvStructInfo;
3347                 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
3348                  sizeof(CERT_EXTENSIONS));
3349                 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3350                  lpszStructType, pbEncoded, cbEncoded,
3351                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3352                  pcbStructInfo);
3353             }
3354         }
3355     }
3356     __EXCEPT(page_fault)
3357     {
3358         SetLastError(STATUS_ACCESS_VIOLATION);
3359         ret = FALSE;
3360     }
3361     __ENDTRY
3362     return ret;
3363 }
3364
3365 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
3366 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
3367  DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
3368 {
3369     BOOL ret = TRUE;
3370
3371     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, pszObjId,
3372      *pcbObjId);
3373
3374     __TRY
3375     {
3376         if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
3377         {
3378             DWORD dataLen;
3379
3380             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3381             {
3382                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3383                 DWORD bytesNeeded;
3384
3385                 if (dataLen)
3386                 {
3387                     /* The largest possible string for the first two components
3388                      * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
3389                      */
3390                     char firstTwo[6];
3391                     const BYTE *ptr;
3392
3393                     snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
3394                      pbEncoded[1 + lenBytes] / 40,
3395                      pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
3396                      * 40);
3397                     bytesNeeded = strlen(firstTwo) + 1;
3398                     for (ptr = pbEncoded + 2 + lenBytes; ret &&
3399                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
3400                     {
3401                         /* large enough for ".4000000" */
3402                         char str[9];
3403                         int val = 0;
3404
3405                         while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3406                          (*ptr & 0x80))
3407                         {
3408                             val <<= 7;
3409                             val |= *ptr & 0x7f;
3410                             ptr++;
3411                         }
3412                         if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
3413                          (*ptr & 0x80))
3414                         {
3415                             SetLastError(CRYPT_E_ASN1_CORRUPT);
3416                             ret = FALSE;
3417                         }
3418                         else
3419                         {
3420                             val <<= 7;
3421                             val |= *ptr++;
3422                             snprintf(str, sizeof(str), ".%d", val);
3423                             bytesNeeded += strlen(str);
3424                         }
3425                     }
3426                     if (!pszObjId)
3427                         *pcbObjId = bytesNeeded;
3428                     else if (*pcbObjId < bytesNeeded)
3429                     {
3430                         *pcbObjId = bytesNeeded;
3431                         SetLastError(ERROR_MORE_DATA);
3432                         ret = FALSE;
3433                     }
3434                     else
3435                     {
3436                         *pszObjId = 0;
3437                         sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
3438                          pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
3439                          40) * 40);
3440                         pszObjId += strlen(pszObjId);
3441                         for (ptr = pbEncoded + 2 + lenBytes; ret &&
3442                          ptr - pbEncoded - 1 - lenBytes < dataLen; )
3443                         {
3444                             int val = 0;
3445
3446                             while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3447                              (*ptr & 0x80))
3448                             {
3449                                 val <<= 7;
3450                                 val |= *ptr & 0x7f;
3451                                 ptr++;
3452                             }
3453                             val <<= 7;
3454                             val |= *ptr++;
3455                             sprintf(pszObjId, ".%d", val);
3456                             pszObjId += strlen(pszObjId);
3457                         }
3458                     }
3459                 }
3460                 else
3461                     bytesNeeded = 0;
3462                 *pcbObjId = bytesNeeded;
3463             }
3464         }
3465         else
3466         {
3467             SetLastError(CRYPT_E_ASN1_BADTAG);
3468             ret = FALSE;
3469         }
3470     }
3471     __EXCEPT(page_fault)
3472     {
3473         SetLastError(STATUS_ACCESS_VIOLATION);
3474         ret = FALSE;
3475     }
3476     __ENDTRY
3477     return ret;
3478 }
3479
3480 /* Warning: this assumes the address of value->Value.pbData is already set, in
3481  * order to avoid overwriting memory.  (In some cases, it may change it, if it
3482  * doesn't copy anything to memory.)  Be sure to set it correctly!
3483  */
3484 static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
3485  DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD *pcbValue)
3486 {
3487     BOOL ret = TRUE;
3488
3489     __TRY
3490     {
3491         DWORD dataLen;
3492
3493         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3494         {
3495             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3496
3497             switch (pbEncoded[0])
3498             {
3499             case ASN_NUMERICSTRING:
3500             case ASN_PRINTABLESTRING:
3501             case ASN_IA5STRING:
3502                 break;
3503             default:
3504                 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
3505                 SetLastError(OSS_UNIMPLEMENTED);
3506                 ret = FALSE;
3507             }
3508             if (ret)
3509             {
3510                 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
3511
3512                 switch (pbEncoded[0])
3513                 {
3514                 case ASN_NUMERICSTRING:
3515                 case ASN_PRINTABLESTRING:
3516                 case ASN_IA5STRING:
3517                     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3518                         bytesNeeded += dataLen;
3519                     break;
3520                 }
3521                 if (!value)
3522                     *pcbValue = bytesNeeded;
3523                 else if (*pcbValue < bytesNeeded)
3524                 {
3525                     *pcbValue = bytesNeeded;
3526                     SetLastError(ERROR_MORE_DATA);
3527                     ret = FALSE;
3528                 }
3529                 else
3530                 {
3531                     *pcbValue = bytesNeeded;
3532                     switch (pbEncoded[0])
3533                     {
3534                     case ASN_NUMERICSTRING:
3535                         value->dwValueType = CERT_RDN_NUMERIC_STRING;
3536                         break;
3537                     case ASN_PRINTABLESTRING:
3538                         value->dwValueType = CERT_RDN_PRINTABLE_STRING;
3539                         break;
3540                     case ASN_IA5STRING:
3541                         value->dwValueType = CERT_RDN_IA5_STRING;
3542                         break;
3543                     }
3544                     if (dataLen)
3545                     {
3546                         switch (pbEncoded[0])
3547                         {
3548                         case ASN_NUMERICSTRING:
3549                         case ASN_PRINTABLESTRING:
3550                         case ASN_IA5STRING:
3551                             value->Value.cbData = dataLen;
3552                             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3553                                 value->Value.pbData = (BYTE *)pbEncoded + 1 +
3554                                  lenBytes;
3555                             else
3556                             {
3557                                 assert(value->Value.pbData);
3558                                 memcpy(value->Value.pbData,
3559                                  pbEncoded + 1 + lenBytes, dataLen);
3560                             }
3561                             break;
3562                         }
3563                     }
3564                     else
3565                     {
3566                         value->Value.cbData = 0;
3567                         value->Value.pbData = NULL;
3568                     }
3569                 }
3570             }
3571         }
3572     }
3573     __EXCEPT(page_fault)
3574     {
3575         SetLastError(STATUS_ACCESS_VIOLATION);
3576         ret = FALSE;
3577     }
3578     __ENDTRY
3579     return ret;
3580 }
3581
3582 /* FIXME: this should use CRYPT_AsnDecodeSequence (though that won't accept it
3583  * at the moment because of the ASN_CONSTRUCTOR tag.)
3584  */
3585 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded,
3586  DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD *pcbAttr)
3587 {
3588     BOOL ret;
3589
3590     __TRY
3591     {
3592         if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCE))
3593         {
3594             DWORD bytesNeeded, dataLen, size;
3595             BYTE lenBytes;
3596
3597             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3598             {
3599                 /* The data length must be at least 4, two for the tag and
3600                  * length for the OID, and two for the string (assuming both
3601                  * have short-form lengths.)
3602                  */
3603                 if (dataLen < 4)
3604                 {
3605                     SetLastError(CRYPT_E_ASN1_EOD);
3606                     ret = FALSE;
3607                 }
3608                 else
3609                 {
3610                     bytesNeeded = sizeof(CERT_RDN_ATTR);
3611                     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3612                     ret = CRYPT_AsnDecodeOid(pbEncoded + 1 + lenBytes,
3613                      cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
3614                     if (ret)
3615                     {
3616                         /* ugly: need to know the size of the next element of
3617                          * the sequence, so get it directly
3618                          */
3619                         DWORD objIdOfset = 1 + lenBytes, objIdLen,
3620                          nameValueOffset = 0;
3621
3622                         ret = CRYPT_GetLen(pbEncoded + objIdOfset,
3623                          cbEncoded - objIdOfset, &objIdLen);
3624                         bytesNeeded += size;
3625                         /* hack: like encoding, this takes advantage of the
3626                          * fact that the rest of the structure is identical to
3627                          * a CERT_NAME_VALUE.
3628                          */
3629                         if (ret)
3630                         {
3631                             nameValueOffset = objIdOfset + objIdLen + 1 +
3632                              GET_LEN_BYTES(pbEncoded[objIdOfset]);
3633                             ret = CRYPT_AsnDecodeNameValue(
3634                              pbEncoded + nameValueOffset,
3635                              cbEncoded - nameValueOffset, dwFlags, NULL, &size);
3636                         }
3637                         if (ret)
3638                         {
3639                             bytesNeeded += size;
3640                             if (!attr)
3641                                 *pcbAttr = bytesNeeded;
3642                             else if (*pcbAttr < bytesNeeded)
3643                             {
3644                                 *pcbAttr = bytesNeeded;
3645                                 SetLastError(ERROR_MORE_DATA);
3646                                 ret = FALSE;
3647                             }
3648                             else
3649                             {
3650                                 BYTE *originalData = attr->Value.pbData;
3651
3652                                 *pcbAttr = bytesNeeded;
3653                                 /* strange: decode the value first, because it
3654                                  * has a counted size, and we can store the OID
3655                                  * after it.  Keep track of the original data
3656                                  * pointer, we'll need to know whether it was
3657                                  * changed.
3658                                  */
3659                                 size = bytesNeeded;
3660                                 ret = CRYPT_AsnDecodeNameValue(
3661                                  pbEncoded + nameValueOffset,
3662                                  cbEncoded - nameValueOffset, dwFlags,
3663                                  (CERT_NAME_VALUE *)&attr->dwValueType, &size);
3664                                 if (ret)
3665                                 {
3666                                     if (objIdLen)
3667                                     {
3668                                         /* if the data were copied to the
3669                                          * original location, the OID goes
3670                                          * after.  Otherwise it goes in the
3671                                          * spot originally reserved for the
3672                                          * data.
3673                                          */
3674                                         if (attr->Value.pbData == originalData)
3675                                             attr->pszObjId =
3676                                              (LPSTR)(attr->Value.pbData +
3677                                              attr->Value.cbData);
3678                                         else
3679                                             attr->pszObjId =
3680                                              (LPSTR)originalData;
3681                                         size = bytesNeeded - size;
3682                                         ret = CRYPT_AsnDecodeOid(
3683                                          pbEncoded + objIdOfset,
3684                                          cbEncoded - objIdOfset,
3685                                          dwFlags, attr->pszObjId, &size);
3686                                     }
3687                                     else
3688                                         attr->pszObjId = NULL;
3689                                 }
3690                             }
3691                         }
3692                     }
3693                 }
3694             }
3695         }
3696         else
3697         {
3698             SetLastError(CRYPT_E_ASN1_BADTAG);
3699             ret = FALSE;
3700         }
3701     }
3702     __EXCEPT(page_fault)
3703     {
3704         SetLastError(STATUS_ACCESS_VIOLATION);
3705         ret = FALSE;
3706     }
3707     __ENDTRY
3708     return ret;
3709 }
3710
3711 static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
3712  DWORD dwFlags, CERT_RDN *rdn, DWORD *pcbRdn)
3713 {
3714     BOOL ret = TRUE;
3715
3716     __TRY
3717     {
3718         if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SETOF))
3719         {
3720             DWORD dataLen;
3721
3722             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3723             {
3724                 DWORD bytesNeeded, cRDNAttr = 0;
3725                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3726
3727                 bytesNeeded = sizeof(CERT_RDN);
3728                 if (dataLen)
3729                 {
3730                     const BYTE *ptr;
3731                     DWORD size;
3732
3733                     for (ptr = pbEncoded + 1 + lenBytes; ret &&
3734                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
3735                     {
3736                         ret = CRYPT_AsnDecodeRdnAttr(ptr,
3737                          cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3738                         if (ret)
3739                         {
3740                             DWORD nextLen;
3741
3742                             cRDNAttr++;
3743                             bytesNeeded += size;
3744                             ret = CRYPT_GetLen(ptr,
3745                              cbEncoded - (ptr - pbEncoded), &nextLen);
3746                             if (ret)
3747                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3748                         }
3749                     }
3750                 }
3751                 if (ret)
3752                 {
3753                     if (!rdn)
3754                         *pcbRdn = bytesNeeded;
3755                     else if (*pcbRdn < bytesNeeded)
3756                     {
3757                         *pcbRdn = bytesNeeded;
3758                         SetLastError(ERROR_MORE_DATA);
3759                         ret = FALSE;
3760                     }
3761                     else
3762                     {
3763                         DWORD size, i;
3764                         BYTE *nextData;
3765                         const BYTE *ptr;
3766
3767                         *pcbRdn = bytesNeeded;
3768                         rdn->cRDNAttr = cRDNAttr;
3769                         rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn +
3770                          sizeof(CERT_RDN));
3771                         nextData = (BYTE *)rdn->rgRDNAttr +
3772                          rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
3773                         for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3774                          i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
3775                          dataLen; i++)
3776                         {
3777                             rdn->rgRDNAttr[i].Value.pbData = nextData;
3778                             size = bytesNeeded;
3779                             ret = CRYPT_AsnDecodeRdnAttr(ptr,
3780                              cbEncoded - (ptr - pbEncoded), dwFlags,
3781                              &rdn->rgRDNAttr[i], &size);
3782                             if (ret)
3783                             {
3784                                 DWORD nextLen;
3785
3786                                 bytesNeeded -= size;
3787                                 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
3788                                  * data may not have been copied.
3789                                  */
3790                                 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
3791                                     nextData +=
3792                                      rdn->rgRDNAttr[i].Value.cbData;
3793                                 /* Ugly: the OID, if copied, is stored in
3794                                  * memory after the value, so increment by its
3795                                  * string length if it's set and points here.
3796                                  */
3797                                 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId
3798                                  == nextData)
3799                                     nextData += strlen(
3800                                      rdn->rgRDNAttr[i].pszObjId) + 1;
3801                                 ret = CRYPT_GetLen(ptr,
3802                                  cbEncoded - (ptr - pbEncoded), &nextLen);
3803                                 if (ret)
3804                                     ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3805                             }
3806                         }
3807                     }
3808                 }
3809             }
3810         }
3811         else
3812         {
3813             SetLastError(CRYPT_E_ASN1_BADTAG);
3814             ret = FALSE;
3815         }
3816     }
3817     __EXCEPT(page_fault)
3818     {
3819         SetLastError(STATUS_ACCESS_VIOLATION);
3820         ret = FALSE;
3821     }
3822     __ENDTRY
3823     return ret;
3824 }
3825
3826 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
3827  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3828  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3829 {
3830     BOOL ret = TRUE;
3831
3832     __TRY
3833     {
3834         if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
3835         {
3836             DWORD dataLen;
3837
3838             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3839             {
3840                 DWORD bytesNeeded, cRDN = 0;
3841                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3842
3843                 bytesNeeded = sizeof(CERT_NAME_INFO);
3844                 if (dataLen)
3845                 {
3846                     const BYTE *ptr;
3847
3848                     for (ptr = pbEncoded + 1 + lenBytes; ret &&
3849                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
3850                     {
3851                         DWORD size;
3852
3853                         ret = CRYPT_AsnDecodeRdn(ptr,
3854                          cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
3855                         if (ret)
3856                         {
3857                             DWORD nextLen;
3858
3859                             cRDN++;
3860                             bytesNeeded += size;
3861                             ret = CRYPT_GetLen(ptr,
3862                              cbEncoded - (ptr - pbEncoded), &nextLen);
3863                             if (ret)
3864                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
3865                         }
3866                     }
3867                 }
3868                 if (ret)
3869                 {
3870                     if (!pvStructInfo)
3871                         *pcbStructInfo = bytesNeeded;
3872                     else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
3873                      pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
3874                     {
3875                         CERT_NAME_INFO *info;
3876
3877                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3878                             pvStructInfo = *(BYTE **)pvStructInfo;
3879                         info = (CERT_NAME_INFO *)pvStructInfo;
3880                         info->cRDN = cRDN;
3881                         if (info->cRDN == 0)
3882                             info->rgRDN = NULL;
3883                         else
3884                         {
3885                             DWORD size, i;
3886                             BYTE *nextData;
3887                             const BYTE *ptr;
3888
3889                             info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
3890                              sizeof(CERT_NAME_INFO));
3891                             nextData = (BYTE *)info->rgRDN +
3892                              info->cRDN * sizeof(CERT_RDN);
3893                             for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
3894                              i < cRDN && ptr - pbEncoded - 1 - lenBytes <
3895                              dataLen; i++)
3896                             {
3897                                 info->rgRDN[i].rgRDNAttr =
3898                                  (CERT_RDN_ATTR *)nextData;
3899                                 size = bytesNeeded;
3900                                 ret = CRYPT_AsnDecodeRdn(ptr,
3901                                  cbEncoded - (ptr - pbEncoded), dwFlags,
3902                                  &info->rgRDN[i], &size);
3903                                 if (ret)
3904                                 {
3905                                     DWORD nextLen;
3906
3907                                     nextData += size;
3908                                     bytesNeeded -= size;
3909                                     ret = CRYPT_GetLen(ptr,
3910                                      cbEncoded - (ptr - pbEncoded), &nextLen);
3911                                     if (ret)
3912                                         ptr += nextLen + 1 +
3913                                          GET_LEN_BYTES(ptr[1]);
3914                                 }
3915                             }
3916                         }
3917                     }
3918                 }
3919             }
3920         }
3921         else
3922         {
3923             SetLastError(CRYPT_E_ASN1_BADTAG);
3924             ret = FALSE;
3925         }
3926     }
3927     __EXCEPT(page_fault)
3928     {
3929         SetLastError(STATUS_ACCESS_VIOLATION);
3930         ret = FALSE;
3931     }
3932     __ENDTRY
3933     return ret;
3934 }
3935
3936 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
3937  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3938  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3939 {
3940     BOOL ret = TRUE;
3941     DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
3942
3943     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3944      pDecodePara, pvStructInfo, *pcbStructInfo);
3945
3946     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3947         bytesNeeded += cbEncoded;
3948     if (!pvStructInfo)
3949         *pcbStructInfo = bytesNeeded;
3950     else if (*pcbStructInfo < bytesNeeded)
3951     {
3952         SetLastError(ERROR_MORE_DATA);
3953         *pcbStructInfo = bytesNeeded;
3954         ret = FALSE;
3955     }
3956     else
3957     {
3958         PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
3959
3960         *pcbStructInfo = bytesNeeded;
3961         blob->cbData = cbEncoded;
3962         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3963             blob->pbData = (LPBYTE)pbEncoded;
3964         else
3965         {
3966             assert(blob->pbData);
3967             memcpy(blob->pbData, pbEncoded, blob->cbData);
3968         }
3969     }
3970     return ret;
3971 }
3972
3973 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
3974  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3975  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3976 {
3977     CRYPT_ALGORITHM_IDENTIFIER *algo =
3978      (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
3979     BOOL ret = TRUE;
3980     struct AsnDecodeSequenceItem items[] = {
3981      { offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
3982        CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE, 
3983        offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
3984      { offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
3985        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE, 
3986        offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
3987     };
3988
3989     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3990      pDecodePara, pvStructInfo, *pcbStructInfo);
3991
3992     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3993      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3994      pDecodePara, pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
3995     if (ret && pvStructInfo)
3996     {
3997         TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
3998          debugstr_a(algo->pszObjId));
3999     }
4000     return ret;
4001 }
4002
4003 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
4004  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4005  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4006 {
4007     BOOL ret = TRUE;
4008
4009     __TRY
4010     {
4011         struct AsnDecodeSequenceItem items[] = {
4012          { offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
4013            CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
4014            FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO,
4015            Algorithm.pszObjId) },
4016          { offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
4017            CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
4018            offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) },
4019         };
4020
4021         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4022          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4023          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4024     }
4025     __EXCEPT(page_fault)
4026     {
4027         SetLastError(STATUS_ACCESS_VIOLATION);
4028         ret = FALSE;
4029     }
4030     __ENDTRY
4031     return ret;
4032 }
4033
4034 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
4035  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4036  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4037 {
4038     BOOL ret;
4039
4040     if (cbEncoded < 3)
4041     {
4042         SetLastError(CRYPT_E_ASN1_CORRUPT);
4043         return FALSE;
4044     }
4045     if (pbEncoded[0] != ASN_BOOL)
4046     {
4047         SetLastError(CRYPT_E_ASN1_BADTAG);
4048         return FALSE;
4049     }
4050     if (GET_LEN_BYTES(pbEncoded[1]) > 1)
4051     {
4052         SetLastError(CRYPT_E_ASN1_CORRUPT);
4053         return FALSE;
4054     }
4055     if (pbEncoded[1] > 1)
4056     {
4057         SetLastError(CRYPT_E_ASN1_CORRUPT);
4058         return FALSE;
4059     }
4060     if (!pvStructInfo)
4061     {
4062         *pcbStructInfo = sizeof(BOOL);
4063         ret = TRUE;
4064     }
4065     else if (*pcbStructInfo < sizeof(BOOL))
4066     {
4067         *pcbStructInfo = sizeof(BOOL);
4068         SetLastError(ERROR_MORE_DATA);
4069         ret = FALSE;
4070     }
4071     else
4072     {
4073         *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
4074         ret = TRUE;
4075     }
4076     TRACE("returning %d (%08lx)\n", ret, GetLastError());
4077     return ret;
4078 }
4079
4080 static BOOL CRYPT_AsnDecodeAltNameEntry(const BYTE *pbEncoded, DWORD cbEncoded,
4081  DWORD dwFlags, CERT_ALT_NAME_ENTRY *entry, DWORD *pcbEntry)
4082 {
4083     DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY);
4084     BOOL ret;
4085
4086     if (cbEncoded < 2)
4087     {
4088         SetLastError(CRYPT_E_ASN1_CORRUPT);
4089         return FALSE;
4090     }
4091     if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT)
4092     {
4093         SetLastError(CRYPT_E_ASN1_BADTAG);
4094         return FALSE;
4095     }
4096     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4097     if (1 + lenBytes > cbEncoded)
4098     {
4099         SetLastError(CRYPT_E_ASN1_CORRUPT);
4100         return FALSE;
4101     }
4102     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4103     {
4104         switch (pbEncoded[0] & ASN_TYPE_MASK)
4105         {
4106         case 1: /* rfc822Name */
4107         case 2: /* dNSName */
4108         case 6: /* uniformResourceIdentifier */
4109             bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
4110             break;
4111         case 7: /* iPAddress */
4112             bytesNeeded += dataLen;
4113             break;
4114         case 8: /* registeredID */
4115             /* FIXME: decode as OID */
4116         case 0: /* otherName */
4117         case 4: /* directoryName */
4118             FIXME("stub\n");
4119             SetLastError(CRYPT_E_ASN1_BADTAG);
4120             ret = FALSE;
4121             break;
4122         case 3: /* x400Address, unimplemented */
4123         case 5: /* ediPartyName, unimplemented */
4124             SetLastError(CRYPT_E_ASN1_BADTAG);
4125             ret = FALSE;
4126             break;
4127         default:
4128             SetLastError(CRYPT_E_ASN1_CORRUPT);
4129             ret = FALSE;
4130         }
4131         if (ret)
4132         {
4133             if (!entry)
4134                 *pcbEntry = bytesNeeded;
4135             else if (*pcbEntry < bytesNeeded)
4136             {
4137                 SetLastError(ERROR_MORE_DATA);
4138                 ret = FALSE;
4139             }
4140             else
4141             {
4142                 /* MS used values one greater than the asn1 ones.. sigh */
4143                 entry->dwAltNameChoice = (pbEncoded[0] & 0x7f) + 1;
4144                 switch (pbEncoded[0] & ASN_TYPE_MASK)
4145                 {
4146                 case 1: /* rfc822Name */
4147                 case 2: /* dNSName */
4148                 case 6: /* uniformResourceIdentifier */
4149                 {
4150                     DWORD i;
4151
4152                     for (i = 0; i < dataLen; i++)
4153                         entry->u.pwszURL[i] =
4154                          (WCHAR)pbEncoded[1 + lenBytes + i];
4155                     entry->u.pwszURL[i] = 0;
4156                     break;
4157                 }
4158                 case 7: /* iPAddress */
4159                     /* The next data pointer is in the pwszURL spot, that is,
4160                      * the first 4 bytes.  Need to move it to the next spot.
4161                      */
4162                     entry->u.IPAddress.pbData = (LPBYTE)entry->u.pwszURL;
4163                     entry->u.IPAddress.cbData = dataLen;
4164                     memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes,
4165                      dataLen);
4166                     break;
4167                 }
4168             }
4169         }
4170     }
4171     return ret;
4172 }
4173
4174 static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
4175  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4176  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4177 {
4178     BOOL ret = TRUE;
4179
4180     __TRY
4181     {
4182         if (pbEncoded[0] == ASN_SEQUENCEOF)
4183         {
4184             DWORD dataLen;
4185
4186             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4187             {
4188                 DWORD bytesNeeded, cEntry = 0;
4189                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4190
4191                 bytesNeeded = sizeof(CERT_ALT_NAME_INFO);
4192                 if (dataLen)
4193                 {
4194                     const BYTE *ptr;
4195
4196                     for (ptr = pbEncoded + 1 + lenBytes; ret &&
4197                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
4198                     {
4199                         DWORD size;
4200
4201                         ret = CRYPT_AsnDecodeAltNameEntry(ptr,
4202                          cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
4203                         if (ret)
4204                         {
4205                             DWORD nextLen;
4206
4207                             cEntry++;
4208                             bytesNeeded += size;
4209                             ret = CRYPT_GetLen(ptr,
4210                              cbEncoded - (ptr - pbEncoded), &nextLen);
4211                             if (ret)
4212                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
4213                         }
4214                     }
4215                 }
4216                 if (ret)
4217                 {
4218                     if (!pvStructInfo)
4219                         *pcbStructInfo = bytesNeeded;
4220                     else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
4221                      pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
4222                     {
4223                         CERT_ALT_NAME_INFO *info;
4224
4225                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4226                             pvStructInfo = *(BYTE **)pvStructInfo;
4227                         info = (CERT_ALT_NAME_INFO *)pvStructInfo;
4228                         info->cAltEntry = 0;
4229                         if (cEntry == 0)
4230                             info->rgAltEntry = NULL;
4231                         else
4232                         {
4233                             DWORD size, i;
4234                             BYTE *nextData;
4235                             const BYTE *ptr;
4236
4237                             info->rgAltEntry =
4238                              (CERT_ALT_NAME_ENTRY *)((BYTE *)pvStructInfo +
4239                              sizeof(CERT_ALT_NAME_INFO));
4240                             nextData = (BYTE *)info->rgAltEntry +
4241                              cEntry * sizeof(CERT_ALT_NAME_ENTRY);
4242                             for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
4243                              i < cEntry && ptr - pbEncoded - 1 - lenBytes <
4244                              dataLen; i++)
4245                             {
4246                                 info->rgAltEntry[i].u.pwszURL =
4247                                  (LPWSTR)nextData;
4248                                 size = bytesNeeded;
4249                                 ret = CRYPT_AsnDecodeAltNameEntry(ptr,
4250                                  cbEncoded - (ptr - pbEncoded), dwFlags,
4251                                  &info->rgAltEntry[i], &size);
4252                                 if (ret)
4253                                 {
4254                                     DWORD nextLen;
4255
4256                                     info->cAltEntry++;
4257                                     nextData += size -
4258                                      sizeof(CERT_ALT_NAME_ENTRY);
4259                                     bytesNeeded -= size;
4260                                     ret = CRYPT_GetLen(ptr,
4261                                      cbEncoded - (ptr - pbEncoded), &nextLen);
4262                                     if (ret)
4263                                         ptr += nextLen + 1 +
4264                                          GET_LEN_BYTES(ptr[1]);
4265                                 }
4266                             }
4267                         }
4268                     }
4269                 }
4270             }
4271         }
4272         else
4273         {
4274             SetLastError(CRYPT_E_ASN1_BADTAG);
4275             ret = FALSE;
4276         }
4277     }
4278     __EXCEPT(page_fault)
4279     {
4280         SetLastError(STATUS_ACCESS_VIOLATION);
4281         ret = FALSE;
4282     }
4283     __ENDTRY
4284     return ret;
4285 }
4286
4287 struct PATH_LEN_CONSTRAINT
4288 {
4289     BOOL  fPathLenConstraint;
4290     DWORD dwPathLenConstraint;
4291 };
4292
4293 static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType,
4294  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4295  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4296 {
4297     BOOL ret = TRUE;
4298
4299     if (cbEncoded)
4300     {
4301         if (pbEncoded[0] == ASN_INTEGER)
4302         {
4303             DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT);
4304
4305             if (!pvStructInfo)
4306                 *pcbStructInfo = bytesNeeded;
4307             else if (*pcbStructInfo < bytesNeeded)
4308             {
4309                 SetLastError(ERROR_MORE_DATA);
4310                 *pcbStructInfo = bytesNeeded;
4311                 ret = FALSE;
4312             }
4313             else
4314             {
4315                 struct PATH_LEN_CONSTRAINT *constraint =
4316                  (struct PATH_LEN_CONSTRAINT *)pvStructInfo;
4317                 DWORD size = sizeof(constraint->dwPathLenConstraint);
4318
4319                 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
4320                  pbEncoded, cbEncoded, 0, NULL,
4321                  &constraint->dwPathLenConstraint, &size);
4322                 if (ret)
4323                     constraint->fPathLenConstraint = TRUE;
4324                 TRACE("got an int, dwPathLenConstraint is %ld\n",
4325                  constraint->dwPathLenConstraint);
4326             }
4327         }
4328         else
4329         {
4330             SetLastError(CRYPT_E_ASN1_CORRUPT);
4331             ret = FALSE;
4332         }
4333     }
4334     TRACE("returning %d (%08lx)\n", ret, GetLastError());
4335     return ret;
4336 }
4337
4338 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
4339  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4340  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4341 {
4342     BOOL ret;
4343
4344     __TRY
4345     {
4346         struct AsnDecodeSequenceItem items[] = {
4347          { offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA), CRYPT_AsnDecodeBool,
4348            sizeof(BOOL), TRUE, FALSE, 0, 0 },
4349          { offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fPathLenConstraint),
4350            CRYPT_AsnDecodePathLenConstraint, sizeof(struct PATH_LEN_CONSTRAINT),
4351            TRUE, FALSE, 0, 0 },
4352         };
4353
4354         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4355          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4356          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4357     }
4358     __EXCEPT(page_fault)
4359     {
4360         SetLastError(STATUS_ACCESS_VIOLATION);
4361         ret = FALSE;
4362     }
4363     __ENDTRY
4364     return ret;
4365 }
4366
4367 #define RSA1_MAGIC 0x31415352
4368
4369 struct DECODED_RSA_PUB_KEY
4370 {
4371     DWORD              pubexp;
4372     CRYPT_INTEGER_BLOB modulus;
4373 };
4374
4375 static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
4376  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4377  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4378 {
4379     BOOL ret;
4380
4381     __TRY
4382     {
4383         struct AsnDecodeSequenceItem items[] = {
4384          { offsetof(struct DECODED_RSA_PUB_KEY, modulus),
4385            CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB),
4386            FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData),
4387            0 },
4388          { offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
4389            CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
4390         };
4391         struct DECODED_RSA_PUB_KEY *decodedKey = NULL;
4392         DWORD size = 0;
4393
4394         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4395          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
4396          CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL);
4397         if (ret)
4398         {
4399             DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
4400              decodedKey->modulus.cbData;
4401
4402             if (!pvStructInfo)
4403             {
4404                 *pcbStructInfo = bytesNeeded;
4405                 ret = TRUE;
4406             }
4407             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4408              pvStructInfo, pcbStructInfo, bytesNeeded)))
4409             {
4410                 BLOBHEADER *hdr;
4411                 RSAPUBKEY *rsaPubKey;
4412
4413                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4414                     pvStructInfo = *(BYTE **)pvStructInfo;
4415                 hdr = (BLOBHEADER *)pvStructInfo;
4416                 hdr->bType = PUBLICKEYBLOB;
4417                 hdr->bVersion = CUR_BLOB_VERSION;
4418                 hdr->reserved = 0;
4419                 hdr->aiKeyAlg = CALG_RSA_KEYX;
4420                 rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo +
4421                  sizeof(BLOBHEADER));
4422                 rsaPubKey->magic = RSA1_MAGIC;
4423                 rsaPubKey->pubexp = decodedKey->pubexp;
4424                 rsaPubKey->bitlen = decodedKey->modulus.cbData * 8;
4425                 memcpy((BYTE *)pvStructInfo + sizeof(BLOBHEADER) +
4426                  sizeof(RSAPUBKEY), decodedKey->modulus.pbData,
4427                  decodedKey->modulus.cbData);
4428             }
4429             LocalFree(decodedKey);
4430         }
4431     }
4432     __EXCEPT(page_fault)
4433     {
4434         SetLastError(STATUS_ACCESS_VIOLATION);
4435         ret = FALSE;
4436     }
4437     __ENDTRY
4438     return ret;
4439 }
4440
4441 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
4442  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4443  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4444 {
4445     BOOL ret;
4446
4447     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4448      pDecodePara, pvStructInfo, *pcbStructInfo);
4449
4450     if (pbEncoded[0] == ASN_OCTETSTRING)
4451     {
4452         DWORD bytesNeeded, dataLen;
4453
4454         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4455         {
4456             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4457                 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
4458             else
4459                 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
4460             if (!pvStructInfo)
4461                 *pcbStructInfo = bytesNeeded;
4462             else if (*pcbStructInfo < bytesNeeded)
4463             {
4464                 SetLastError(ERROR_MORE_DATA);
4465                 *pcbStructInfo = bytesNeeded;
4466                 ret = FALSE;
4467             }
4468             else
4469             {
4470                 CRYPT_DATA_BLOB *blob;
4471                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4472
4473                 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4474                 blob->cbData = dataLen;
4475                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4476                     blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
4477                 else
4478                 {
4479                     assert(blob->pbData);
4480                     if (blob->cbData)
4481                         memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
4482                          blob->cbData);
4483                 }
4484             }
4485         }
4486     }
4487     else
4488     {
4489         SetLastError(CRYPT_E_ASN1_BADTAG);
4490         ret = FALSE;
4491     }
4492     return ret;
4493 }
4494
4495 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
4496  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4497  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4498 {
4499     BOOL ret;
4500
4501     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4502      pDecodePara, pvStructInfo, *pcbStructInfo);
4503
4504     __TRY
4505     {
4506         DWORD bytesNeeded;
4507
4508         if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4509          lpszStructType, pbEncoded, cbEncoded,
4510          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4511         {
4512             if (!pvStructInfo)
4513                 *pcbStructInfo = bytesNeeded;
4514             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4515              pvStructInfo, pcbStructInfo, bytesNeeded)))
4516             {
4517                 CRYPT_DATA_BLOB *blob;
4518
4519                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4520                     pvStructInfo = *(BYTE **)pvStructInfo;
4521                 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4522                 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB);
4523                 ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4524                  lpszStructType, pbEncoded, cbEncoded,
4525                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4526                  &bytesNeeded);
4527             }
4528         }
4529         else
4530         {
4531             SetLastError(CRYPT_E_ASN1_BADTAG);
4532             ret = FALSE;
4533         }
4534     }
4535     __EXCEPT(page_fault)
4536     {
4537         SetLastError(STATUS_ACCESS_VIOLATION);
4538         ret = FALSE;
4539     }
4540     __ENDTRY
4541     return ret;
4542 }
4543
4544 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
4545  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4546  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4547 {
4548     BOOL ret;
4549
4550     TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
4551      pDecodePara, pvStructInfo, *pcbStructInfo);
4552
4553     if (pbEncoded[0] == ASN_BITSTRING)
4554     {
4555         DWORD bytesNeeded, dataLen;
4556
4557         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4558         {
4559             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4560                 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
4561             else
4562                 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
4563             if (!pvStructInfo)
4564                 *pcbStructInfo = bytesNeeded;
4565             else if (*pcbStructInfo < bytesNeeded)
4566             {
4567                 *pcbStructInfo = bytesNeeded;
4568                 SetLastError(ERROR_MORE_DATA);
4569                 ret = FALSE;
4570             }
4571             else
4572             {
4573                 CRYPT_BIT_BLOB *blob;
4574
4575                 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4576                 blob->cbData = dataLen - 1;
4577                 blob->cUnusedBits = *(pbEncoded + 1 +
4578                  GET_LEN_BYTES(pbEncoded[1]));
4579                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4580                 {
4581                     blob->pbData = (BYTE *)pbEncoded + 2 +
4582                      GET_LEN_BYTES(pbEncoded[1]);
4583                 }
4584                 else
4585                 {
4586                     assert(blob->pbData);
4587                     if (blob->cbData)
4588                     {
4589                         BYTE mask = 0xff << blob->cUnusedBits;
4590
4591                         memcpy(blob->pbData, pbEncoded + 2 +
4592                          GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
4593                         blob->pbData[blob->cbData - 1] &= mask;
4594                     }
4595                 }
4596             }
4597         }
4598     }
4599     else
4600     {
4601         SetLastError(CRYPT_E_ASN1_BADTAG);
4602         ret = FALSE;
4603     }
4604     TRACE("returning %d (%08lx)\n", ret, GetLastError());
4605     return ret;
4606 }
4607
4608 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
4609  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4610  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4611 {
4612     BOOL ret;
4613
4614     TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
4615      pDecodePara, pvStructInfo, pcbStructInfo);
4616
4617     __TRY
4618     {
4619         DWORD bytesNeeded;
4620
4621         if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4622          lpszStructType, pbEncoded, cbEncoded,
4623          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4624         {
4625             if (!pvStructInfo)
4626                 *pcbStructInfo = bytesNeeded;
4627             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4628              pvStructInfo, pcbStructInfo, bytesNeeded)))
4629             {
4630                 CRYPT_BIT_BLOB *blob;
4631
4632                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4633                     pvStructInfo = *(BYTE **)pvStructInfo;
4634                 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4635                 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
4636                 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4637                  lpszStructType, pbEncoded, cbEncoded,
4638                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4639                  &bytesNeeded);
4640             }
4641         }
4642     }
4643     __EXCEPT(page_fault)
4644     {
4645         SetLastError(STATUS_ACCESS_VIOLATION);
4646         ret = FALSE;
4647     }
4648     __ENDTRY
4649     TRACE("returning %d (%08lx)\n", ret, GetLastError());
4650     return ret;
4651 }
4652
4653 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
4654  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4655  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4656 {
4657     BOOL ret;
4658
4659     if (!pvStructInfo)
4660     {
4661         *pcbStructInfo = sizeof(int);
4662         return TRUE;
4663     }
4664     __TRY
4665     {
4666         BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
4667         CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
4668         DWORD size = sizeof(buf);
4669
4670         blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
4671         ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4672          X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
4673         if (ret)
4674         {
4675             if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4676              pvStructInfo, pcbStructInfo, sizeof(int))))
4677             {
4678                 int val, i;
4679
4680                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4681                     pvStructInfo = *(BYTE **)pvStructInfo;
4682                 if (blob->pbData[blob->cbData - 1] & 0x80)
4683                 {
4684                     /* initialize to a negative value to sign-extend */
4685                     val = -1;
4686                 }
4687                 else
4688                     val = 0;
4689                 for (i = 0; i < blob->cbData; i++)
4690                 {
4691                     val <<= 8;
4692                     val |= blob->pbData[blob->cbData - i - 1];
4693                 }
4694                 memcpy(pvStructInfo, &val, sizeof(int));
4695             }
4696         }
4697         else if (GetLastError() == ERROR_MORE_DATA)
4698             SetLastError(CRYPT_E_ASN1_LARGE);
4699     }
4700     __EXCEPT(page_fault)
4701     {
4702         SetLastError(STATUS_ACCESS_VIOLATION);
4703         ret = FALSE;
4704     }
4705     __ENDTRY
4706     return ret;
4707 }
4708
4709 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
4710  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4711  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4712 {
4713     BOOL ret;
4714
4715     if (pbEncoded[0] == ASN_INTEGER)
4716     {
4717         DWORD bytesNeeded, dataLen;
4718
4719         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4720         {
4721             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4722
4723             bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4724             if (!pvStructInfo)
4725                 *pcbStructInfo = bytesNeeded;
4726             else if (*pcbStructInfo < bytesNeeded)
4727             {
4728                 *pcbStructInfo = bytesNeeded;
4729                 SetLastError(ERROR_MORE_DATA);
4730                 ret = FALSE;
4731             }
4732             else
4733             {
4734                 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4735
4736                 blob->cbData = dataLen;
4737                 assert(blob->pbData);
4738                 if (blob->cbData)
4739                 {
4740                     DWORD i;
4741
4742                     for (i = 0; i < blob->cbData; i++)
4743                     {
4744                         blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4745                          dataLen - i - 1);
4746                     }
4747                 }
4748             }
4749         }
4750     }
4751     else
4752     {
4753         SetLastError(CRYPT_E_ASN1_BADTAG);
4754         ret = FALSE;
4755     }
4756     return ret;
4757 }
4758
4759 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
4760  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4761  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4762 {
4763     BOOL ret;
4764
4765     __TRY
4766     {
4767         DWORD bytesNeeded;
4768
4769         if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4770          lpszStructType, pbEncoded, cbEncoded,
4771          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4772         {
4773             if (!pvStructInfo)
4774                 *pcbStructInfo = bytesNeeded;
4775             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4776              pvStructInfo, pcbStructInfo, bytesNeeded)))
4777             {
4778                 CRYPT_INTEGER_BLOB *blob;
4779
4780                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4781                     pvStructInfo = *(BYTE **)pvStructInfo;
4782                 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4783                 blob->pbData = (BYTE *)pvStructInfo +
4784                  sizeof(CRYPT_INTEGER_BLOB);
4785                 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4786                  lpszStructType, pbEncoded, cbEncoded,
4787                  dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4788                  &bytesNeeded);
4789             }
4790         }
4791     }
4792     __EXCEPT(page_fault)
4793     {
4794         SetLastError(STATUS_ACCESS_VIOLATION);
4795         ret = FALSE;
4796     }
4797     __ENDTRY
4798     return ret;
4799 }
4800
4801 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
4802  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4803  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4804 {
4805     BOOL ret;
4806
4807     __TRY
4808     {
4809         if (pbEncoded[0] == ASN_INTEGER)
4810         {
4811             DWORD bytesNeeded, dataLen;
4812             CRYPT_INTEGER_BLOB *blob;
4813
4814             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4815             {
4816                 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4817                 if (!pvStructInfo)
4818                     *pcbStructInfo = bytesNeeded;
4819                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4820                  pvStructInfo, pcbStructInfo, bytesNeeded)))
4821                 {
4822                     BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4823
4824                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4825                         pvStructInfo = *(BYTE **)pvStructInfo;
4826                     blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4827                     blob->cbData = dataLen;
4828                     blob->pbData = (BYTE *)pvStructInfo +
4829                      sizeof(CRYPT_INTEGER_BLOB);
4830                     /* remove leading zero byte if it exists */
4831                     if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
4832                     {
4833                         blob->cbData--;
4834                         blob->pbData++;
4835                     }
4836                     if (blob->cbData)
4837                     {
4838                         DWORD i;
4839
4840                         for (i = 0; i < blob->cbData; i++)
4841                             blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4842                              pbEncoded[1] - i - 1);
4843                     }
4844                 }
4845             }
4846         }
4847         else
4848         {
4849             SetLastError(CRYPT_E_ASN1_BADTAG);
4850             ret = FALSE;
4851         }
4852     }
4853     __EXCEPT(page_fault)
4854     {
4855         SetLastError(STATUS_ACCESS_VIOLATION);
4856         ret = FALSE;
4857     }
4858     __ENDTRY
4859     return ret;
4860 }
4861
4862 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
4863  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4864  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4865 {
4866     BOOL ret;
4867
4868     if (!pvStructInfo)
4869     {
4870         *pcbStructInfo = sizeof(int);
4871         return TRUE;
4872     }
4873     __TRY
4874     {
4875         if (pbEncoded[0] == ASN_ENUMERATED)
4876         {
4877             unsigned int val = 0, i;
4878
4879             if (cbEncoded <= 1)
4880             {
4881                 SetLastError(CRYPT_E_ASN1_EOD);
4882                 ret = FALSE;
4883             }
4884             else if (pbEncoded[1] == 0)
4885             {
4886                 SetLastError(CRYPT_E_ASN1_CORRUPT);
4887                 ret = FALSE;
4888             }
4889             else
4890             {
4891                 /* A little strange looking, but we have to accept a sign byte:
4892                  * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff.  Also,
4893                  * assuming a small length is okay here, it has to be in short
4894                  * form.
4895                  */
4896                 if (pbEncoded[1] > sizeof(unsigned int) + 1)
4897                 {
4898                     SetLastError(CRYPT_E_ASN1_LARGE);
4899                     return FALSE;
4900                 }
4901                 for (i = 0; i < pbEncoded[1]; i++)
4902                 {
4903                     val <<= 8;
4904                     val |= pbEncoded[2 + i];
4905                 }
4906                 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4907                  pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
4908                 {
4909                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4910                         pvStructInfo = *(BYTE **)pvStructInfo;
4911                     memcpy(pvStructInfo, &val, sizeof(unsigned int));
4912                 }
4913             }
4914         }
4915         else
4916         {
4917             SetLastError(CRYPT_E_ASN1_BADTAG);
4918             ret = FALSE;
4919         }
4920     }
4921     __EXCEPT(page_fault)
4922     {
4923         SetLastError(STATUS_ACCESS_VIOLATION);
4924         ret = FALSE;
4925     }
4926     __ENDTRY
4927     return ret;
4928 }
4929
4930 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
4931  * if it fails.
4932  */
4933 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
4934  do { \
4935     BYTE i; \
4936  \
4937     (word) = 0; \
4938     for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
4939     { \
4940         if (!isdigit(*(pbEncoded))) \
4941         { \
4942             SetLastError(CRYPT_E_ASN1_CORRUPT); \
4943             ret = FALSE; \
4944         } \
4945         else \
4946         { \
4947             (word) *= 10; \
4948             (word) += *(pbEncoded)++ - '0'; \
4949         } \
4950     } \
4951  } while (0)
4952
4953 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
4954  SYSTEMTIME *sysTime)
4955 {
4956     BOOL ret = TRUE;
4957
4958     __TRY
4959     {
4960         if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
4961         {
4962             WORD hours, minutes = 0;
4963             BYTE sign = *pbEncoded++;
4964
4965             len--;
4966             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
4967             if (ret && hours >= 24)
4968             {
4969                 SetLastError(CRYPT_E_ASN1_CORRUPT);
4970                 ret = FALSE;
4971             }
4972             else if (len >= 2)
4973             {
4974                 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
4975                 if (ret && minutes >= 60)
4976                 {
4977                     SetLastError(CRYPT_E_ASN1_CORRUPT);
4978                     ret = FALSE;
4979                 }
4980             }
4981             if (ret)
4982             {
4983                 if (sign == '+')
4984                 {
4985                     sysTime->wHour += hours;
4986                     sysTime->wMinute += minutes;
4987                 }
4988                 else
4989                 {
4990                     if (hours > sysTime->wHour)
4991                     {
4992                         sysTime->wDay--;
4993                         sysTime->wHour = 24 - (hours - sysTime->wHour);
4994                     }
4995                     else
4996                         sysTime->wHour -= hours;
4997                     if (minutes > sysTime->wMinute)
4998                     {
4999                         sysTime->wHour--;
5000                         sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
5001                     }
5002                     else
5003                         sysTime->wMinute -= minutes;
5004                 }
5005             }
5006         }
5007     }
5008     __EXCEPT(page_fault)
5009     {
5010         SetLastError(STATUS_ACCESS_VIOLATION);
5011         ret = FALSE;
5012     }
5013     __ENDTRY
5014     return ret;
5015 }
5016
5017 #define MIN_ENCODED_TIME_LENGTH 10
5018
5019 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
5020  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5021  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5022 {
5023     BOOL ret = TRUE;
5024
5025     if (!pvStructInfo)
5026     {
5027         *pcbStructInfo = sizeof(FILETIME);
5028         return TRUE;
5029     }
5030     __TRY
5031     {
5032         if (pbEncoded[0] == ASN_UTCTIME)
5033         {
5034             if (cbEncoded <= 1)
5035             {
5036                 SetLastError(CRYPT_E_ASN1_EOD);
5037                 ret = FALSE;
5038             }
5039             else if (pbEncoded[1] > 0x7f)
5040             {
5041                 /* long-form date strings really can't be valid */
5042                 SetLastError(CRYPT_E_ASN1_CORRUPT);
5043                 ret = FALSE;
5044             }
5045             else
5046             {
5047                 SYSTEMTIME sysTime = { 0 };
5048                 BYTE len = pbEncoded[1];
5049
5050                 if (len < MIN_ENCODED_TIME_LENGTH)
5051                 {
5052                     SetLastError(CRYPT_E_ASN1_CORRUPT);
5053                     ret = FALSE;
5054                 }
5055                 else
5056                 {
5057                     pbEncoded += 2;
5058                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
5059                     if (sysTime.wYear >= 50)
5060                         sysTime.wYear += 1900;
5061                     else
5062                         sysTime.wYear += 2000;
5063                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
5064                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
5065                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
5066                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
5067                     if (ret && len > 0)
5068                     {
5069                         if (len >= 2 && isdigit(*pbEncoded) &&
5070                          isdigit(*(pbEncoded + 1)))
5071                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5072                              sysTime.wSecond);
5073                         else if (isdigit(*pbEncoded))
5074                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
5075                              sysTime.wSecond);
5076                         if (ret)
5077                             ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
5078                              &sysTime);
5079                     }
5080                     if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
5081                      pDecodePara, pvStructInfo, pcbStructInfo,
5082                      sizeof(FILETIME))))
5083                     {
5084                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5085                             pvStructInfo = *(BYTE **)pvStructInfo;
5086                         ret = SystemTimeToFileTime(&sysTime,
5087                          (FILETIME *)pvStructInfo);
5088                     }
5089                 }
5090             }
5091         }
5092         else
5093         {
5094             SetLastError(CRYPT_E_ASN1_BADTAG);
5095             ret = FALSE;
5096         }
5097     }
5098     __EXCEPT(page_fault)
5099     {
5100         SetLastError(STATUS_ACCESS_VIOLATION);
5101         ret = FALSE;
5102     }
5103     __ENDTRY
5104     return ret;
5105 }
5106
5107 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
5108  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5109  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5110 {
5111     BOOL ret = TRUE;
5112
5113     if (!pvStructInfo)
5114     {
5115         *pcbStructInfo = sizeof(FILETIME);
5116         return TRUE;
5117     }
5118     __TRY
5119     {
5120         if (pbEncoded[0] == ASN_GENERALTIME)
5121         {
5122             if (cbEncoded <= 1)
5123             {
5124                 SetLastError(CRYPT_E_ASN1_EOD);
5125                 ret = FALSE;
5126             }
5127             else if (pbEncoded[1] > 0x7f)
5128             {
5129                 /* long-form date strings really can't be valid */
5130                 SetLastError(CRYPT_E_ASN1_CORRUPT);
5131                 ret = FALSE;
5132             }
5133             else
5134             {
5135                 BYTE len = pbEncoded[1];
5136
5137                 if (len < MIN_ENCODED_TIME_LENGTH)
5138                 {
5139                     SetLastError(CRYPT_E_ASN1_CORRUPT);
5140                     ret = FALSE;
5141                 }
5142                 else
5143                 {
5144                     SYSTEMTIME sysTime = { 0 };
5145
5146                     pbEncoded += 2;
5147                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
5148                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
5149                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
5150                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
5151                     if (ret && len > 0)
5152                     {
5153                         CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5154                          sysTime.wMinute);
5155                         if (ret && len > 0)
5156                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5157                              sysTime.wSecond);
5158                         if (ret && len > 0 && (*pbEncoded == '.' ||
5159                          *pbEncoded == ','))
5160                         {
5161                             BYTE digits;
5162
5163                             pbEncoded++;
5164                             len--;
5165                             /* workaround macro weirdness */
5166                             digits = min(len, 3);
5167                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
5168                              sysTime.wMilliseconds);
5169                         }
5170                         if (ret)
5171                             ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
5172                              &sysTime);
5173                     }
5174                     if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
5175                      pDecodePara, pvStructInfo, pcbStructInfo,
5176                      sizeof(FILETIME))))
5177                     {
5178                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5179                             pvStructInfo = *(BYTE **)pvStructInfo;
5180                         ret = SystemTimeToFileTime(&sysTime,
5181                          (FILETIME *)pvStructInfo);
5182                     }
5183                 }
5184             }
5185         }
5186         else
5187         {
5188             SetLastError(CRYPT_E_ASN1_BADTAG);
5189             ret = FALSE;
5190         }
5191     }
5192     __EXCEPT(page_fault)
5193     {
5194         SetLastError(STATUS_ACCESS_VIOLATION);
5195         ret = FALSE;
5196     }
5197     __ENDTRY
5198     return ret;
5199 }
5200
5201 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
5202  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5203  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5204 {
5205     BOOL ret;
5206
5207     __TRY
5208     {
5209         if (pbEncoded[0] == ASN_UTCTIME)
5210             ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
5211              pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
5212              pcbStructInfo);
5213         else if (pbEncoded[0] == ASN_GENERALTIME)
5214             ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
5215              lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
5216              pvStructInfo, pcbStructInfo);
5217         else
5218         {
5219             SetLastError(CRYPT_E_ASN1_BADTAG);
5220             ret = FALSE;
5221         }
5222     }
5223     __EXCEPT(page_fault)
5224     {
5225         SetLastError(STATUS_ACCESS_VIOLATION);
5226         ret = FALSE;
5227     }
5228     __ENDTRY
5229     return ret;
5230 }
5231
5232 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
5233  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5234  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5235 {
5236     BOOL ret = TRUE;
5237
5238     __TRY
5239     {
5240         if (pbEncoded[0] == ASN_SEQUENCEOF)
5241         {
5242             DWORD bytesNeeded, dataLen, remainingLen, cValue;
5243
5244             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
5245             {
5246                 BYTE lenBytes;
5247                 const BYTE *ptr;
5248
5249                 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
5250                 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
5251                 cValue = 0;
5252                 ptr = pbEncoded + 1 + lenBytes;
5253                 remainingLen = dataLen;
5254                 while (ret && remainingLen)
5255                 {
5256                     DWORD nextLen;
5257
5258                     ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5259                     if (ret)
5260                     {
5261                         DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5262
5263                         remainingLen -= 1 + nextLenBytes + nextLen;
5264                         ptr += 1 + nextLenBytes + nextLen;
5265                         bytesNeeded += sizeof(CRYPT_DER_BLOB);
5266                         if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
5267                             bytesNeeded += 1 + nextLenBytes + nextLen;
5268                         cValue++;
5269                     }
5270                 }
5271                 if (ret)
5272                 {
5273                     CRYPT_SEQUENCE_OF_ANY *seq;
5274                     BYTE *nextPtr;
5275                     DWORD i;
5276
5277                     if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
5278                      pvStructInfo, pcbStructInfo, bytesNeeded)))
5279                     {
5280                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5281                             pvStructInfo = *(BYTE **)pvStructInfo;
5282                         seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
5283                         seq->cValue = cValue;
5284                         seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
5285                          sizeof(*seq));
5286                         nextPtr = (BYTE *)seq->rgValue +
5287                          cValue * sizeof(CRYPT_DER_BLOB);
5288                         ptr = pbEncoded + 1 + lenBytes;
5289                         remainingLen = dataLen;
5290                         i = 0;
5291                         while (ret && remainingLen)
5292                         {
5293                             DWORD nextLen;
5294
5295                             ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5296                             if (ret)
5297                             {
5298                                 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5299
5300                                 seq->rgValue[i].cbData = 1 + nextLenBytes +
5301                                  nextLen;
5302                                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
5303                                     seq->rgValue[i].pbData = (BYTE *)ptr;
5304                                 else
5305                                 {
5306                                     seq->rgValue[i].pbData = nextPtr;
5307                                     memcpy(nextPtr, ptr, 1 + nextLenBytes +
5308                                      nextLen);
5309                                     nextPtr += 1 + nextLenBytes + nextLen;
5310                                 }
5311                                 remainingLen -= 1 + nextLenBytes + nextLen;
5312                                 ptr += 1 + nextLenBytes + nextLen;
5313                                 i++;
5314                             }
5315                         }
5316                     }
5317                 }
5318             }
5319         }
5320         else
5321         {
5322             SetLastError(CRYPT_E_ASN1_BADTAG);
5323             return FALSE;
5324         }
5325     }
5326     __EXCEPT(page_fault)
5327     {
5328         SetLastError(STATUS_ACCESS_VIOLATION);
5329         ret = FALSE;
5330     }
5331     __ENDTRY
5332     return ret;
5333 }
5334
5335 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
5336  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5337  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5338 {
5339     BOOL ret = FALSE;
5340     HMODULE lib = NULL;
5341     CryptDecodeObjectExFunc decodeFunc = NULL;
5342
5343     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
5344      dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded,
5345      cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5346
5347     if (!pvStructInfo && !pcbStructInfo)
5348     {
5349         SetLastError(ERROR_INVALID_PARAMETER);
5350         return FALSE;
5351     }
5352     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
5353      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
5354     {
5355         SetLastError(ERROR_FILE_NOT_FOUND);
5356         return FALSE;
5357     }
5358     if (!cbEncoded)
5359     {
5360         SetLastError(CRYPT_E_ASN1_EOD);
5361         return FALSE;
5362     }
5363     if (cbEncoded > MAX_ENCODED_LEN)
5364     {
5365         SetLastError(CRYPT_E_ASN1_LARGE);
5366         return FALSE;
5367     }
5368
5369     SetLastError(NOERROR);
5370     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
5371         *(BYTE **)pvStructInfo = NULL;
5372     if (!HIWORD(lpszStructType))
5373     {
5374         switch (LOWORD(lpszStructType))
5375         {
5376         case (WORD)X509_CERT:
5377             decodeFunc = CRYPT_AsnDecodeCert;
5378             break;
5379         case (WORD)X509_CERT_TO_BE_SIGNED:
5380             decodeFunc = CRYPT_AsnDecodeCertInfo;
5381             break;
5382         case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
5383             decodeFunc = CRYPT_AsnDecodeCRLInfo;
5384             break;
5385         case (WORD)X509_EXTENSIONS:
5386             decodeFunc = CRYPT_AsnDecodeExtensions;
5387             break;
5388         case (WORD)X509_NAME:
5389             decodeFunc = CRYPT_AsnDecodeName;
5390             break;
5391         case (WORD)X509_PUBLIC_KEY_INFO:
5392             decodeFunc = CRYPT_AsnDecodePubKeyInfo;
5393             break;
5394         case (WORD)X509_ALTERNATE_NAME:
5395             decodeFunc = CRYPT_AsnDecodeAltName;
5396             break;
5397         case (WORD)X509_BASIC_CONSTRAINTS2:
5398             decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5399             break;
5400         case (WORD)RSA_CSP_PUBLICKEYBLOB:
5401             decodeFunc = CRYPT_AsnDecodeRsaPubKey;
5402             break;
5403         case (WORD)X509_OCTET_STRING:
5404             decodeFunc = CRYPT_AsnDecodeOctets;
5405             break;
5406         case (WORD)X509_BITS:
5407         case (WORD)X509_KEY_USAGE:
5408             decodeFunc = CRYPT_AsnDecodeBits;
5409             break;
5410         case (WORD)X509_INTEGER:
5411             decodeFunc = CRYPT_AsnDecodeInt;
5412             break;
5413         case (WORD)X509_MULTI_BYTE_INTEGER:
5414             decodeFunc = CRYPT_AsnDecodeInteger;
5415             break;
5416         case (WORD)X509_MULTI_BYTE_UINT:
5417             decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
5418             break;
5419         case (WORD)X509_ENUMERATED:
5420             decodeFunc = CRYPT_AsnDecodeEnumerated;
5421             break;
5422         case (WORD)X509_CHOICE_OF_TIME:
5423             decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
5424             break;
5425         case (WORD)X509_SEQUENCE_OF_ANY:
5426             decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
5427             break;
5428         case (WORD)PKCS_UTC_TIME:
5429             decodeFunc = CRYPT_AsnDecodeUtcTime;
5430             break;
5431         default:
5432             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
5433         }
5434     }
5435     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
5436         decodeFunc = CRYPT_AsnDecodeExtensions;
5437     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
5438         decodeFunc = CRYPT_AsnDecodeUtcTime;
5439     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
5440         decodeFunc = CRYPT_AsnDecodeEnumerated;
5441     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
5442         decodeFunc = CRYPT_AsnDecodeBits;
5443     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
5444         decodeFunc = CRYPT_AsnDecodeOctets;
5445     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
5446         decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5447     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
5448         decodeFunc = CRYPT_AsnDecodeAltName;
5449     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
5450         decodeFunc = CRYPT_AsnDecodeAltName;
5451     else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
5452         decodeFunc = CRYPT_AsnDecodeAltName;
5453     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
5454         decodeFunc = CRYPT_AsnDecodeAltName;
5455     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
5456         decodeFunc = CRYPT_AsnDecodeAltName;
5457     else
5458         TRACE("OID %s not found or unimplemented, looking for DLL\n",
5459          debugstr_a(lpszStructType));
5460     if (!decodeFunc)
5461         decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
5462          lpszStructType, "CryptDecodeObjectEx", &lib);
5463     if (decodeFunc)
5464         ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
5465          cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5466     else
5467         SetLastError(ERROR_FILE_NOT_FOUND);
5468     if (lib)
5469         FreeLibrary(lib);
5470     return ret;
5471 }