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