Fix gcc 4.0 -Wpointer-sign warnings.
[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 <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include "windef.h"
38 #include "winbase.h"
39 #include "excpt.h"
40 #include "wincrypt.h"
41 #include "winreg.h"
42 #include "snmp.h"
43 #include "wine/debug.h"
44 #include "wine/exception.h"
45
46 /* This is a bit arbitrary, but to set some limit: */
47 #define MAX_ENCODED_LEN 0x02000000
48
49 /* a few asn.1 tags we need */
50 #define ASN_BOOL            (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
51 #define ASN_BITSTRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
52 #define ASN_OCTETSTRING     (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
53 #define ASN_ENUMERATED      (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
54 #define ASN_SETOF           (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
55 #define ASN_NUMERICSTRING   (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
56 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
57 #define ASN_IA5STRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
58 #define ASN_UTCTIME         (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
59 #define ASN_GENERALTIME     (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
60
61 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
62
63 static const WCHAR szDllName[] = { 'D','l','l',0 };
64
65 static BOOL WINAPI CRYPT_AsnEncodeOid(LPCSTR pszObjId, BYTE *pbEncoded,
66  DWORD *pcbEncoded);
67 static BOOL CRYPT_EncodeBool(BOOL val, BYTE *pbEncoded, DWORD *pcbEncoded);
68 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
69  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
70  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
71 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
72  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
73  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
74 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
75  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
76  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
77 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
78  DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
79 static BOOL WINAPI CRYPT_DecodeBool(const BYTE *pbEncoded, DWORD cbEncoded,
80  BOOL *val);
81 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
82  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
83  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
84 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
85  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
86  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
87 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
88  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
89  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
90
91 /* filter for page-fault exceptions */
92 static WINE_EXCEPTION_FILTER(page_fault)
93 {
94     if (GetExceptionCode() == EXCEPTION_ACCESS_VIOLATION)
95         return EXCEPTION_EXECUTE_HANDLER;
96     return EXCEPTION_CONTINUE_SEARCH;
97 }
98
99 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
100  LPCSTR pszOID)
101 {
102     static const char szEncodingTypeFmt[] =
103      "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
104     UINT len;
105     char numericOID[7]; /* enough for "#65535" */
106     const char *oid;
107     LPSTR szKey;
108
109     /* MSDN says the encoding type is a mask, but it isn't treated that way.
110      * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
111      * "EncodingType 2" would be expected if it were a mask.  Instead native
112      * stores values in "EncodingType 3".
113      */
114     if (!HIWORD(pszOID))
115     {
116         snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
117         oid = numericOID;
118     }
119     else
120         oid = pszOID;
121
122     /* This is enough: the lengths of the two string parameters are explicitly
123      * counted, and we need up to five additional characters for the encoding
124      * type.  These are covered by the "%d", "%s", and "%s" characters in the
125      * format specifier that are removed by sprintf.
126      */
127     len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
128     szKey = HeapAlloc(GetProcessHeap(), 0, len);
129     if (szKey)
130         sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
131     return szKey;
132 }
133
134 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
135                   LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
136 {
137     LONG r;
138     HKEY hKey;
139     LPSTR szKey;
140
141     TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
142           debugstr_w(pwszDll), pszOverrideFuncName);
143
144     /* This only registers functions for encoding certs, not messages */
145     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
146         return TRUE;
147
148     /* Native does nothing pwszDll is NULL */
149     if (!pwszDll)
150         return TRUE;
151
152     /* I'm not matching MS bug for bug here, because I doubt any app depends on
153      * it:
154      * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
155      *   it creates would never be used
156      * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
157      * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
158      */
159     if (!pszFuncName || !pszOID)
160     {
161         SetLastError(ERROR_INVALID_PARAMETER);
162         return FALSE;
163     }
164
165     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
166     TRACE("Key name is %s\n", debugstr_a(szKey));
167
168     if (!szKey)
169         return FALSE;
170
171     r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
172     HeapFree(GetProcessHeap(), 0, szKey);
173     if(r != ERROR_SUCCESS)
174         return FALSE;
175
176     /* write the values */
177     if (pszOverrideFuncName)
178         RegSetValueExA(hKey, "FuncName", 0, REG_SZ, pszOverrideFuncName,
179          lstrlenA(pszOverrideFuncName) + 1);
180     RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
181                     (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
182
183     RegCloseKey(hKey);
184     return TRUE;
185 }
186
187 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
188  LPCSTR pszOID)
189 {
190     LPSTR szKey;
191     LONG rc;
192
193     TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
194
195     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
196         return TRUE;
197
198     if (!pszFuncName || !pszOID)
199     {
200         SetLastError(ERROR_INVALID_PARAMETER);
201         return FALSE;
202     }
203
204     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
205     rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
206     HeapFree(GetProcessHeap(), 0, szKey);
207     if (rc)
208         SetLastError(rc);
209     return rc ? FALSE : TRUE;
210 }
211
212 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
213  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
214  DWORD *pcbValueData)
215 {
216     LPSTR szKey;
217     LONG rc;
218     HKEY hKey;
219
220     TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
221      debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
222      pcbValueData);
223
224     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
225         return TRUE;
226
227     if (!pszFuncName || !pszOID || !pwszValueName)
228     {
229         SetLastError(ERROR_INVALID_PARAMETER);
230         return FALSE;
231     }
232
233     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
234     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
235     HeapFree(GetProcessHeap(), 0, szKey);
236     if (rc)
237         SetLastError(rc);
238     else
239     {
240         rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
241          pbValueData, pcbValueData);
242         if (rc)
243             SetLastError(rc);
244         RegCloseKey(hKey);
245     }
246     return rc ? FALSE : TRUE;
247 }
248
249 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
250  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
251  const BYTE *pbValueData, DWORD cbValueData)
252 {
253     LPSTR szKey;
254     LONG rc;
255     HKEY hKey;
256
257     TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
258      debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
259      cbValueData);
260
261     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
262         return TRUE;
263
264     if (!pszFuncName || !pszOID || !pwszValueName)
265     {
266         SetLastError(ERROR_INVALID_PARAMETER);
267         return FALSE;
268     }
269
270     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
271     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
272     HeapFree(GetProcessHeap(), 0, szKey);
273     if (rc)
274         SetLastError(rc);
275     else
276     {
277         rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
278          cbValueData);
279         if (rc)
280             SetLastError(rc);
281         RegCloseKey(hKey);
282     }
283     return rc ? FALSE : TRUE;
284 }
285
286 /* Gets the registered function named szFuncName for dwCertEncodingType and
287  * lpszStructType, or NULL if one could not be found.  *lib will be set to the
288  * handle of the module it's in, or NULL if no module was loaded.  If the
289  * return value is NULL, *lib will also be NULL, to simplify error handling.
290  */
291 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
292  LPCSTR szFuncName, HMODULE *lib)
293 {
294     void *ret = NULL;
295     char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
296      lpszStructType);
297     const char *funcName;
298     long r;
299     HKEY hKey;
300     DWORD type, size = 0;
301
302     TRACE("(%08lx %s %s %p)\n", dwCertEncodingType, debugstr_a(lpszStructType),
303      debugstr_a(szFuncName), lib);
304
305     *lib = NULL;
306     r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
307     HeapFree(GetProcessHeap(), 0, szKey);
308     if(r != ERROR_SUCCESS)
309         return NULL;
310
311     RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
312     if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
313     {
314         funcName = HeapAlloc(GetProcessHeap(), 0, size);
315         RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
316          &size);
317     }
318     else
319         funcName = szFuncName;
320     RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
321     if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
322     {
323         LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
324
325         RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
326          &size);
327         *lib = LoadLibraryW(dllName);
328         if (*lib)
329         {
330              ret = GetProcAddress(*lib, funcName);
331              if (!ret)
332              {
333                  /* Unload the library, the caller doesn't want to unload it
334                   * when the return value is NULL.
335                   */
336                  FreeLibrary(*lib);
337                  *lib = NULL;
338              }
339         }
340         HeapFree(GetProcessHeap(), 0, dllName);
341     }
342     if (funcName != szFuncName)
343         HeapFree(GetProcessHeap(), 0, (char *)funcName);
344     TRACE("returning %p\n", ret);
345     return ret;
346 }
347
348 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
349  BYTE *, DWORD *);
350
351 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
352  const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
353 {
354     BOOL ret = FALSE;
355     HMODULE lib;
356     CryptEncodeObjectFunc pCryptEncodeObject;
357
358     TRACE("(0x%08lx, %s, %p, %p, %p)\n",
359      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
360      "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
361
362     if (!pbEncoded && !pcbEncoded)
363     {
364         SetLastError(ERROR_INVALID_PARAMETER);
365         return FALSE;
366     }
367
368     /* Try registered DLL first.. */
369     pCryptEncodeObject =
370      (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
371      lpszStructType, "CryptEncodeObject", &lib);
372     if (pCryptEncodeObject)
373     {
374         ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
375          pvStructInfo, pbEncoded, pcbEncoded);
376         FreeLibrary(lib);
377     }
378     else
379     {
380         /* If not, use CryptEncodeObjectEx */
381         ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
382          pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
383     }
384     return ret;
385 }
386
387 /* Helper function to check *pcbEncoded, set it to the required size, and
388  * optionally to allocate memory.  Assumes pbEncoded is not NULL.
389  * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
390  * pointer to the newly allocated memory.
391  */
392 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
393  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
394  DWORD bytesNeeded)
395 {
396     BOOL ret = TRUE;
397
398     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
399     {
400         if (pEncodePara && pEncodePara->pfnAlloc)
401             *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
402         else
403             *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
404         if (!*(BYTE **)pbEncoded)
405             ret = FALSE;
406         else
407             *pcbEncoded = bytesNeeded;
408     }
409     else if (bytesNeeded > *pcbEncoded)
410     {
411         *pcbEncoded = bytesNeeded;
412         SetLastError(ERROR_MORE_DATA);
413         ret = FALSE;
414     }
415     return ret;
416 }
417
418 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
419 {
420     DWORD bytesNeeded, significantBytes = 0;
421
422     if (len <= 0x7f)
423         bytesNeeded = 1;
424     else
425     {
426         DWORD temp;
427
428         for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
429          temp <<= 8, significantBytes--)
430             ;
431         bytesNeeded = significantBytes + 1;
432     }
433     if (!pbEncoded)
434     {
435         *pcbEncoded = bytesNeeded;
436         return TRUE;
437     }
438     if (*pcbEncoded < bytesNeeded)
439     {
440         SetLastError(ERROR_MORE_DATA);
441         return FALSE;
442     }
443     if (len <= 0x7f)
444         *pbEncoded = (BYTE)len;
445     else
446     {
447         DWORD i;
448
449         *pbEncoded++ = significantBytes | 0x80;
450         for (i = 0; i < significantBytes; i++)
451         {
452             *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
453             len >>= 8;
454         }
455     }
456     *pcbEncoded = bytesNeeded;
457     return TRUE;
458 }
459
460 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
461  DWORD *pcbEncoded)
462 {
463     BOOL ret;
464     DWORD dataLen, octetsLen, lenBytes, size;
465
466     ret = CRYPT_AsnEncodeOid(ext->pszObjId, NULL, &size);
467     if (ret)
468     {
469         dataLen = size;
470         if (ext->fCritical)
471         {
472             ret = CRYPT_EncodeBool(TRUE, NULL, &size);
473             dataLen += size;
474         }
475         if (ret)
476         {
477             ret = CRYPT_AsnEncodeOctets(X509_ASN_ENCODING, X509_OCTET_STRING,
478              &ext->Value, 0, NULL, NULL, &octetsLen);
479             dataLen += octetsLen;
480         }
481         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
482         *pcbEncoded = 1 + lenBytes + dataLen;
483     }
484     if (ret && pbEncoded)
485     {
486         *pbEncoded++ = ASN_SEQUENCE;
487         CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
488         pbEncoded += lenBytes;
489         ret = CRYPT_AsnEncodeOid(ext->pszObjId, pbEncoded, &size);
490         if (ret)
491         {
492             pbEncoded += size;
493             if (ext->fCritical)
494             {
495                 ret = CRYPT_EncodeBool(TRUE, pbEncoded, &size);
496                 pbEncoded += size;
497             }
498             if (ret)
499             {
500                 ret = CRYPT_AsnEncodeOctets(X509_ASN_ENCODING,
501                  X509_OCTET_STRING, &ext->Value, 0, NULL, pbEncoded,
502                  &octetsLen);
503                 pbEncoded += octetsLen;
504             }
505         }
506     }
507     return ret;
508 }
509
510 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
511  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
512  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
513 {
514     BOOL ret;
515
516     __TRY
517     {
518         DWORD bytesNeeded, dataLen, lenBytes, i;
519         CERT_EXTENSIONS *exts = (CERT_EXTENSIONS *)pvStructInfo;
520
521         ret = TRUE;
522         for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
523         {
524             DWORD size;
525
526             ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
527             if (ret)
528                 dataLen += size;
529         }
530         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
531         bytesNeeded = 1 + lenBytes + dataLen;
532         if (!pbEncoded)
533             *pcbEncoded = bytesNeeded;
534         else
535         {
536             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
537              pcbEncoded, bytesNeeded)))
538             {
539                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
540                     pbEncoded = *(BYTE **)pbEncoded;
541                 *pbEncoded++ = ASN_SEQUENCEOF;
542                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
543                 pbEncoded += lenBytes;
544                 for (i = 0; i < exts->cExtension; i++)
545                 {
546                     DWORD size;
547
548                     ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
549                      pbEncoded, &size);
550                     if (ret)
551                         pbEncoded += size;
552                 }
553             }
554         }
555     }
556     __EXCEPT(page_fault)
557     {
558         SetLastError(STATUS_ACCESS_VIOLATION);
559         ret = FALSE;
560     }
561     __ENDTRY
562     return ret;
563 }
564
565 static BOOL WINAPI CRYPT_AsnEncodeOid(LPCSTR pszObjId, BYTE *pbEncoded,
566  DWORD *pcbEncoded)
567 {
568     DWORD bytesNeeded = 0, lenBytes;
569     BOOL ret = TRUE;
570     int firstPos = 0;
571     BYTE firstByte = 0;
572
573     if (pszObjId)
574     {
575         const char *ptr;
576         int val1, val2;
577
578         if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
579         {
580             SetLastError(CRYPT_E_ASN1_ERROR);
581             return FALSE;
582         }
583         bytesNeeded++;
584         firstByte = val1 * 40 + val2;
585         ptr = pszObjId + firstPos;
586         while (ret && *ptr)
587         {
588             int pos;
589
590             /* note I assume each component is at most 32-bits long in base 2 */
591             if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
592             {
593                 if (val1 >= 0x10000000)
594                     bytesNeeded += 5;
595                 else if (val1 >= 0x200000)
596                     bytesNeeded += 4;
597                 else if (val1 >= 0x4000)
598                     bytesNeeded += 3;
599                 else if (val1 >= 0x80)
600                     bytesNeeded += 2;
601                 else
602                     bytesNeeded += 1;
603                 ptr += pos;
604                 if (*ptr == '.')
605                     ptr++;
606             }
607             else
608             {
609                 SetLastError(CRYPT_E_ASN1_ERROR);
610                 return FALSE;
611             }
612         }
613         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
614     }
615     else
616         lenBytes = 1;
617     bytesNeeded += 1 + lenBytes;
618     if (pbEncoded)
619     {
620         if (*pbEncoded < bytesNeeded)
621         {
622             SetLastError(ERROR_MORE_DATA);
623             ret = FALSE;
624         }
625         else
626         {
627             *pbEncoded++ = ASN_OBJECTIDENTIFIER;
628             CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
629             pbEncoded += lenBytes;
630             if (pszObjId)
631             {
632                 const char *ptr;
633                 int val, pos;
634
635                 *pbEncoded++ = firstByte;
636                 ptr = pszObjId + firstPos;
637                 while (ret && *ptr)
638                 {
639                     sscanf(ptr, "%d%n", &val, &pos);
640                     {
641                         unsigned char outBytes[5];
642                         int numBytes, i;
643
644                         if (val >= 0x10000000)
645                             numBytes = 5;
646                         else if (val >= 0x200000)
647                             numBytes = 4;
648                         else if (val >= 0x4000)
649                             numBytes = 3;
650                         else if (val >= 0x80)
651                             numBytes = 2;
652                         else
653                             numBytes = 1;
654                         for (i = numBytes; i > 0; i--)
655                         {
656                             outBytes[i - 1] = val & 0x7f;
657                             val >>= 7;
658                         }
659                         for (i = 0; i < numBytes - 1; i++)
660                             *pbEncoded++ = outBytes[i] | 0x80;
661                         *pbEncoded++ = outBytes[i];
662                         ptr += pos;
663                         if (*ptr == '.')
664                             ptr++;
665                     }
666                 }
667             }
668         }
669     }
670     *pcbEncoded = bytesNeeded;
671     return ret;
672 }
673
674 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
675  CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
676 {
677     BYTE tag;
678     DWORD bytesNeeded, lenBytes, encodedLen;
679     BOOL ret = TRUE;
680
681     switch (value->dwValueType)
682     {
683     case CERT_RDN_NUMERIC_STRING:
684         tag = ASN_NUMERICSTRING;
685         encodedLen = value->Value.cbData;
686         break;
687     case CERT_RDN_PRINTABLE_STRING:
688         tag = ASN_PRINTABLESTRING;
689         encodedLen = value->Value.cbData;
690         break;
691     case CERT_RDN_IA5_STRING:
692         tag = ASN_IA5STRING;
693         encodedLen = value->Value.cbData;
694         break;
695     case CERT_RDN_ANY_TYPE:
696         /* explicitly disallowed */
697         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
698         return FALSE;
699     default:
700         FIXME("String type %ld unimplemented\n", value->dwValueType);
701         return FALSE;
702     }
703     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
704     bytesNeeded = 1 + lenBytes + encodedLen;
705     if (pbEncoded)
706     {
707         if (*pcbEncoded < bytesNeeded)
708         {
709             SetLastError(ERROR_MORE_DATA);
710             ret = FALSE;
711         }
712         else
713         {
714             *pbEncoded++ = tag;
715             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
716             pbEncoded += lenBytes;
717             switch (value->dwValueType)
718             {
719             case CERT_RDN_NUMERIC_STRING:
720             case CERT_RDN_PRINTABLE_STRING:
721             case CERT_RDN_IA5_STRING:
722                 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
723             }
724         }
725     }
726     *pcbEncoded = bytesNeeded;
727     return ret;
728 }
729
730 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
731  CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
732 {
733     DWORD bytesNeeded = 0, lenBytes, size;
734     BOOL ret;
735
736     ret = CRYPT_AsnEncodeOid(attr->pszObjId, NULL, &size);
737     if (ret)
738     {
739         bytesNeeded += size;
740         /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
741          * with dwValueType, so "cast" it to get its encoded size
742          */
743         ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
744          (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
745         if (ret)
746         {
747             bytesNeeded += size;
748             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
749             bytesNeeded += 1 + lenBytes;
750             if (pbEncoded)
751             {
752                 if (*pcbEncoded < bytesNeeded)
753                 {
754                     SetLastError(ERROR_MORE_DATA);
755                     ret = FALSE;
756                 }
757                 else
758                 {
759                     *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
760                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
761                      &lenBytes);
762                     pbEncoded += lenBytes;
763                     size = bytesNeeded - 1 - lenBytes;
764                     ret = CRYPT_AsnEncodeOid(attr->pszObjId, pbEncoded, &size);
765                     if (ret)
766                     {
767                         pbEncoded += size;
768                         size = bytesNeeded - 1 - lenBytes - size;
769                         ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
770                          (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
771                          &size);
772                     }
773                 }
774             }
775             *pcbEncoded = bytesNeeded;
776         }
777     }
778     return ret;
779 }
780
781 static int BLOBComp(const void *l, const void *r)
782 {
783     CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
784     int ret;
785
786     if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
787         ret = a->cbData - b->cbData;
788     return ret;
789 }
790
791 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
792  */
793 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
794  BYTE *pbEncoded, DWORD *pcbEncoded)
795 {
796     BOOL ret;
797     CRYPT_DER_BLOB *blobs = NULL;
798    
799     __TRY
800     {
801         DWORD bytesNeeded = 0, lenBytes, i;
802
803         ret = TRUE;
804         if (rdn->cRDNAttr)
805         {
806             blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
807              rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
808             if (!blobs)
809                 ret = FALSE;
810         }
811         for (i = 0; ret && i < rdn->cRDNAttr; i++)
812         {
813             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
814              NULL, &blobs[i].cbData);
815             if (ret)
816                 bytesNeeded += blobs[i].cbData;
817         }
818         if (ret)
819         {
820             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
821             bytesNeeded += 1 + lenBytes;
822             if (pbEncoded)
823             {
824                 if (*pcbEncoded < bytesNeeded)
825                 {
826                     SetLastError(ERROR_MORE_DATA);
827                     ret = FALSE;
828                 }
829                 else
830                 {
831                     for (i = 0; ret && i < rdn->cRDNAttr; i++)
832                     {
833                         blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
834                          blobs[i].cbData);
835                         if (!blobs[i].pbData)
836                             ret = FALSE;
837                         else
838                             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
839                              &rdn->rgRDNAttr[i], blobs[i].pbData,
840                              &blobs[i].cbData);
841                     }
842                     if (ret)
843                     {
844                         qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
845                          BLOBComp);
846                         *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
847                         CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
848                          &lenBytes);
849                         pbEncoded += lenBytes;
850                         for (i = 0; ret && i < rdn->cRDNAttr; i++)
851                         {
852                             memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
853                             pbEncoded += blobs[i].cbData;
854                         }
855                     }
856                 }
857             }
858             *pcbEncoded = bytesNeeded;
859         }
860         if (blobs)
861         {
862             for (i = 0; i < rdn->cRDNAttr; i++)
863                 HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
864         }
865     }
866     __EXCEPT(page_fault)
867     {
868         SetLastError(STATUS_ACCESS_VIOLATION);
869         ret = FALSE;
870     }
871     __ENDTRY
872     HeapFree(GetProcessHeap(), 0, blobs);
873     return ret;
874 }
875
876 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
877  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
878  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
879 {
880     BOOL ret;
881
882     __TRY
883     {
884         CERT_NAME_INFO *info = (CERT_NAME_INFO *)pvStructInfo;
885         DWORD bytesNeeded = 0, lenBytes, size, i;
886
887         TRACE("encoding name with %ld RDNs\n", info->cRDN);
888         ret = TRUE;
889         for (i = 0; ret && i < info->cRDN; i++)
890         {
891             ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
892              &size);
893             if (ret)
894                 bytesNeeded += size;
895         }
896         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
897         bytesNeeded += 1 + lenBytes;
898         if (ret)
899         {
900             if (!pbEncoded)
901                 *pcbEncoded = bytesNeeded;
902             else
903             {
904                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
905                  pbEncoded, pcbEncoded, bytesNeeded)))
906                 {
907                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
908                         pbEncoded = *(BYTE **)pbEncoded;
909                     *pbEncoded++ = ASN_SEQUENCEOF;
910                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
911                      &lenBytes);
912                     pbEncoded += lenBytes;
913                     for (i = 0; ret && i < info->cRDN; i++)
914                     {
915                         size = bytesNeeded;
916                         ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
917                          &info->rgRDN[i], pbEncoded, &size);
918                         if (ret)
919                         {
920                             pbEncoded += size;
921                             bytesNeeded -= size;
922                         }
923                     }
924                 }
925             }
926         }
927     }
928     __EXCEPT(page_fault)
929     {
930         SetLastError(STATUS_ACCESS_VIOLATION);
931         ret = FALSE;
932     }
933     __ENDTRY
934     return ret;
935 }
936
937 static BOOL CRYPT_EncodeBool(BOOL val, BYTE *pbEncoded, DWORD *pcbEncoded)
938 {
939     if (!pbEncoded)
940     {
941         *pcbEncoded = 3;
942         return TRUE;
943     }
944     if (*pcbEncoded < 3)
945     {
946         *pcbEncoded = 3;
947         SetLastError(ERROR_MORE_DATA);
948         return FALSE;
949     }
950     *pcbEncoded = 3;
951     *pbEncoded++ = ASN_BOOL;
952     *pbEncoded++ = 1;
953     *pbEncoded++ = val ? 0xff : 0;
954     return TRUE;
955 }
956
957 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
958  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
959  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
960 {
961     BOOL ret;
962
963     __TRY
964     {
965         CERT_BASIC_CONSTRAINTS2_INFO *info =
966          (CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
967         DWORD bytesNeeded = 0, lenBytes, caLen = 0, pathConstraintLen = 0;
968
969         ret = TRUE;
970         if (info->fCA)
971         {
972             ret = CRYPT_EncodeBool(TRUE, NULL, &caLen);
973             if (ret)
974                 bytesNeeded += caLen;
975         }
976         if (info->fPathLenConstraint)
977         {
978             ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER,
979              &info->dwPathLenConstraint, 0, NULL, NULL, &pathConstraintLen);
980             if (ret)
981                 bytesNeeded += pathConstraintLen;
982         }
983         if (ret)
984         {
985             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
986             bytesNeeded += 1 + lenBytes;
987             if (!pbEncoded)
988                 *pcbEncoded = bytesNeeded;
989             else
990             {
991                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
992                  pbEncoded, pcbEncoded, bytesNeeded)))
993                 {
994                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
995                         pbEncoded = *(BYTE **)pbEncoded;
996                     *pbEncoded++ = ASN_SEQUENCE;
997                     CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded,
998                      &lenBytes);
999                     pbEncoded += lenBytes;
1000                     if (info->fCA)
1001                     {
1002                         ret = CRYPT_EncodeBool(TRUE, pbEncoded, &caLen);
1003                         if (ret)
1004                             pbEncoded += caLen;
1005                     }
1006                     if (info->fPathLenConstraint)
1007                     {
1008                         ret = CRYPT_AsnEncodeInt(dwCertEncodingType,
1009                          X509_INTEGER, &info->dwPathLenConstraint, 0, NULL,
1010                          pbEncoded, &pathConstraintLen);
1011                     }
1012                 }
1013             }
1014         }
1015     }
1016     __EXCEPT(page_fault)
1017     {
1018         SetLastError(STATUS_ACCESS_VIOLATION);
1019         ret = FALSE;
1020     }
1021     __ENDTRY
1022     return ret;
1023 }
1024
1025 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1026  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1027  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1028 {
1029     BOOL ret;
1030
1031     __TRY
1032     {
1033         CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)pvStructInfo;
1034         DWORD bytesNeeded, lenBytes;
1035
1036         CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1037         bytesNeeded = 1 + lenBytes + blob->cbData;
1038         if (!pbEncoded)
1039         {
1040             *pcbEncoded = bytesNeeded;
1041             ret = TRUE;
1042         }
1043         else
1044         {
1045             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1046              pcbEncoded, bytesNeeded)))
1047             {
1048                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1049                     pbEncoded = *(BYTE **)pbEncoded;
1050                 *pbEncoded++ = ASN_OCTETSTRING;
1051                 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1052                 pbEncoded += lenBytes;
1053                 if (blob->cbData)
1054                     memcpy(pbEncoded, blob->pbData, blob->cbData);
1055             }
1056         }
1057     }
1058     __EXCEPT(page_fault)
1059     {
1060         SetLastError(STATUS_ACCESS_VIOLATION);
1061         ret = FALSE;
1062     }
1063     __ENDTRY
1064     return ret;
1065 }
1066
1067 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1068  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1069  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1070 {
1071     BOOL ret;
1072
1073     __TRY
1074     {
1075         CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1076         DWORD bytesNeeded, lenBytes, dataBytes;
1077         BYTE unusedBits;
1078
1079         /* yep, MS allows cUnusedBits to be >= 8 */
1080         if (blob->cbData * 8 > blob->cUnusedBits)
1081         {
1082             dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1083             unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1084              blob->cUnusedBits;
1085         }
1086         else
1087         {
1088             dataBytes = 0;
1089             unusedBits = 0;
1090         }
1091         CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1092         bytesNeeded = 1 + lenBytes + dataBytes + 1;
1093         if (!pbEncoded)
1094         {
1095             *pcbEncoded = bytesNeeded;
1096             ret = TRUE;
1097         }
1098         else
1099         {
1100             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1101              pcbEncoded, bytesNeeded)))
1102             {
1103                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1104                     pbEncoded = *(BYTE **)pbEncoded;
1105                 *pbEncoded++ = ASN_BITSTRING;
1106                 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1107                 pbEncoded += lenBytes;
1108                 *pbEncoded++ = unusedBits;
1109                 if (dataBytes)
1110                 {
1111                     BYTE mask = 0xff << unusedBits;
1112
1113                     if (dataBytes > 1)
1114                     {
1115                         memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1116                         pbEncoded += dataBytes - 1;
1117                     }
1118                     *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1119                 }
1120             }
1121         }
1122     }
1123     __EXCEPT(page_fault)
1124     {
1125         SetLastError(STATUS_ACCESS_VIOLATION);
1126         ret = FALSE;
1127     }
1128     __ENDTRY
1129     return ret;
1130 }
1131
1132 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1133  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1134  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1135 {
1136     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1137
1138     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1139      &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1140 }
1141
1142 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1143  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1144  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1145 {
1146     BOOL ret;
1147
1148     __TRY
1149     {
1150         DWORD significantBytes, lenBytes;
1151         BYTE padByte = 0, bytesNeeded;
1152         BOOL pad = FALSE;
1153         CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
1154
1155         significantBytes = blob->cbData;
1156         if (significantBytes)
1157         {
1158             if (blob->pbData[significantBytes - 1] & 0x80)
1159             {
1160                 /* negative, lop off leading (little-endian) 0xffs */
1161                 for (; significantBytes > 0 &&
1162                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1163                     ;
1164                 if (blob->pbData[significantBytes - 1] < 0x80)
1165                 {
1166                     padByte = 0xff;
1167                     pad = TRUE;
1168                 }
1169             }
1170             else
1171             {
1172                 /* positive, lop off leading (little-endian) zeroes */
1173                 for (; significantBytes > 0 &&
1174                  !blob->pbData[significantBytes - 1]; significantBytes--)
1175                     ;
1176                 if (significantBytes == 0)
1177                     significantBytes = 1;
1178                 if (blob->pbData[significantBytes - 1] > 0x7f)
1179                 {
1180                     padByte = 0;
1181                     pad = TRUE;
1182                 }
1183             }
1184         }
1185         if (pad)
1186             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1187         else
1188             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1189         bytesNeeded = 1 + lenBytes + significantBytes;
1190         if (pad)
1191             bytesNeeded++;
1192         if (!pbEncoded)
1193         {
1194             *pcbEncoded = bytesNeeded;
1195             ret = TRUE;
1196         }
1197         else
1198         {
1199             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1200              pcbEncoded, bytesNeeded)))
1201             {
1202                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1203                     pbEncoded = *(BYTE **)pbEncoded;
1204                 *pbEncoded++ = ASN_INTEGER;
1205                 if (pad)
1206                 {
1207                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1208                     pbEncoded += lenBytes;
1209                     *pbEncoded++ = padByte;
1210                 }
1211                 else
1212                 {
1213                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1214                     pbEncoded += lenBytes;
1215                 }
1216                 for (; significantBytes > 0; significantBytes--)
1217                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
1218             }
1219         }
1220     }
1221     __EXCEPT(page_fault)
1222     {
1223         SetLastError(STATUS_ACCESS_VIOLATION);
1224         ret = FALSE;
1225     }
1226     __ENDTRY
1227     return ret;
1228 }
1229
1230 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1231  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1232  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1233 {
1234     BOOL ret;
1235
1236     __TRY
1237     {
1238         DWORD significantBytes, lenBytes;
1239         BYTE bytesNeeded;
1240         BOOL pad = FALSE;
1241         CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
1242
1243         significantBytes = blob->cbData;
1244         if (significantBytes)
1245         {
1246             /* positive, lop off leading (little-endian) zeroes */
1247             for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1248              significantBytes--)
1249                 ;
1250             if (significantBytes == 0)
1251                 significantBytes = 1;
1252             if (blob->pbData[significantBytes - 1] > 0x7f)
1253                 pad = TRUE;
1254         }
1255         if (pad)
1256             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1257         else
1258             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1259         bytesNeeded = 1 + lenBytes + significantBytes;
1260         if (pad)
1261             bytesNeeded++;
1262         if (!pbEncoded)
1263         {
1264             *pcbEncoded = bytesNeeded;
1265             ret = TRUE;
1266         }
1267         else
1268         {
1269             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1270              pcbEncoded, bytesNeeded)))
1271             {
1272                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1273                     pbEncoded = *(BYTE **)pbEncoded;
1274                 *pbEncoded++ = ASN_INTEGER;
1275                 if (pad)
1276                 {
1277                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1278                     pbEncoded += lenBytes;
1279                     *pbEncoded++ = 0;
1280                 }
1281                 else
1282                 {
1283                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1284                     pbEncoded += lenBytes;
1285                 }
1286                 for (; significantBytes > 0; significantBytes--)
1287                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
1288             }
1289         }
1290     }
1291     __EXCEPT(page_fault)
1292     {
1293         SetLastError(STATUS_ACCESS_VIOLATION);
1294         ret = FALSE;
1295     }
1296     __ENDTRY
1297     return ret;
1298 }
1299
1300 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
1301  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1302  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1303 {
1304     CRYPT_INTEGER_BLOB blob;
1305     BOOL ret;
1306
1307     /* Encode as an unsigned integer, then change the tag to enumerated */
1308     blob.cbData = sizeof(DWORD);
1309     blob.pbData = (BYTE *)pvStructInfo;
1310     ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
1311      X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1312     if (ret && pbEncoded)
1313     {
1314         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1315             pbEncoded = *(BYTE **)pbEncoded;
1316         pbEncoded[0] = ASN_ENUMERATED;
1317     }
1318     return ret;
1319 }
1320
1321 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
1322  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1323  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1324 {
1325     BOOL ret;
1326
1327     __TRY
1328     {
1329         SYSTEMTIME sysTime;
1330         /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
1331          * temporary buffer because the output buffer is not NULL-terminated.
1332          */
1333         char buf[16];
1334         static const DWORD bytesNeeded = sizeof(buf) - 1;
1335
1336         if (!pbEncoded)
1337         {
1338             *pcbEncoded = bytesNeeded;
1339             ret = TRUE;
1340         }
1341         else
1342         {
1343             /* Sanity check the year, this is a two-digit year format */
1344             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1345              &sysTime);
1346             if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
1347             {
1348                 SetLastError(CRYPT_E_BAD_ENCODE);
1349                 ret = FALSE;
1350             }
1351             if (ret)
1352             {
1353                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1354                  pbEncoded, pcbEncoded, bytesNeeded)))
1355                 {
1356                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1357                         pbEncoded = *(BYTE **)pbEncoded;
1358                     buf[0] = ASN_UTCTIME;
1359                     buf[1] = bytesNeeded - 2;
1360                     snprintf(buf + 2, sizeof(buf) - 2,
1361                      "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
1362                      sysTime.wYear - 2000 : sysTime.wYear - 1900,
1363                      sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1364                      sysTime.wMinute, sysTime.wSecond);
1365                     memcpy(pbEncoded, buf, bytesNeeded);
1366                 }
1367             }
1368         }
1369     }
1370     __EXCEPT(page_fault)
1371     {
1372         SetLastError(STATUS_ACCESS_VIOLATION);
1373         ret = FALSE;
1374     }
1375     __ENDTRY
1376     return ret;
1377 }
1378
1379 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
1380  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1381  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1382 {
1383     BOOL ret;
1384
1385     __TRY
1386     {
1387         SYSTEMTIME sysTime;
1388         /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
1389          * temporary buffer because the output buffer is not NULL-terminated.
1390          */
1391         char buf[18];
1392         static const DWORD bytesNeeded = sizeof(buf) - 1;
1393
1394         if (!pbEncoded)
1395         {
1396             *pcbEncoded = bytesNeeded;
1397             ret = TRUE;
1398         }
1399         else
1400         {
1401             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1402              &sysTime);
1403             if (ret)
1404                 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1405                  pcbEncoded, bytesNeeded);
1406             if (ret)
1407             {
1408                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1409                     pbEncoded = *(BYTE **)pbEncoded;
1410                 buf[0] = ASN_GENERALTIME;
1411                 buf[1] = bytesNeeded - 2;
1412                 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
1413                  sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1414                  sysTime.wMinute, sysTime.wSecond);
1415                 memcpy(pbEncoded, buf, bytesNeeded);
1416             }
1417         }
1418     }
1419     __EXCEPT(page_fault)
1420     {
1421         SetLastError(STATUS_ACCESS_VIOLATION);
1422         ret = FALSE;
1423     }
1424     __ENDTRY
1425     return ret;
1426 }
1427
1428 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
1429  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1430  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1431 {
1432     BOOL ret;
1433
1434     __TRY
1435     {
1436         SYSTEMTIME sysTime;
1437
1438         /* Check the year, if it's in the UTCTime range call that encode func */
1439         if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1440             return FALSE;
1441         if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
1442             ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
1443              pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1444         else
1445             ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
1446              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1447              pcbEncoded);
1448     }
1449     __EXCEPT(page_fault)
1450     {
1451         SetLastError(STATUS_ACCESS_VIOLATION);
1452         ret = FALSE;
1453     }
1454     __ENDTRY
1455     return ret;
1456 }
1457
1458 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
1459  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1460  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1461 {
1462     BOOL ret;
1463
1464     __TRY
1465     {
1466         DWORD bytesNeeded, dataLen, lenBytes, i;
1467         CRYPT_SEQUENCE_OF_ANY *seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
1468
1469         for (i = 0, dataLen = 0; i < seq->cValue; i++)
1470             dataLen += seq->rgValue[i].cbData;
1471         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1472         bytesNeeded = 1 + lenBytes + dataLen;
1473         if (!pbEncoded)
1474         {
1475             *pcbEncoded = bytesNeeded;
1476             ret = TRUE;
1477         }
1478         else
1479         {
1480             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1481              pcbEncoded, bytesNeeded)))
1482             {
1483                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1484                     pbEncoded = *(BYTE **)pbEncoded;
1485                 *pbEncoded++ = ASN_SEQUENCEOF;
1486                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1487                 pbEncoded += lenBytes;
1488                 for (i = 0; i < seq->cValue; i++)
1489                 {
1490                     memcpy(pbEncoded, seq->rgValue[i].pbData,
1491                      seq->rgValue[i].cbData);
1492                     pbEncoded += seq->rgValue[i].cbData;
1493                 }
1494             }
1495         }
1496     }
1497     __EXCEPT(page_fault)
1498     {
1499         SetLastError(STATUS_ACCESS_VIOLATION);
1500         ret = FALSE;
1501     }
1502     __ENDTRY
1503     return ret;
1504 }
1505
1506 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
1507  DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
1508
1509 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1510  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
1511  void *pvEncoded, DWORD *pcbEncoded)
1512 {
1513     BOOL ret = FALSE;
1514     HMODULE lib = NULL;
1515     CryptEncodeObjectExFunc encodeFunc = NULL;
1516
1517     TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n",
1518      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1519      "(integer value)", pvStructInfo, dwFlags, pEncodePara, pvEncoded,
1520      pcbEncoded);
1521
1522     if (!pvEncoded && !pcbEncoded)
1523     {
1524         SetLastError(ERROR_INVALID_PARAMETER);
1525         return FALSE;
1526     }
1527     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
1528      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
1529     {
1530         SetLastError(ERROR_FILE_NOT_FOUND);
1531         return FALSE;
1532     }
1533
1534     SetLastError(NOERROR);
1535     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
1536         *(BYTE **)pvEncoded = NULL;
1537     if (!HIWORD(lpszStructType))
1538     {
1539         switch (LOWORD(lpszStructType))
1540         {
1541         case (WORD)X509_EXTENSIONS:
1542             encodeFunc = CRYPT_AsnEncodeExtensions;
1543             break;
1544         case (WORD)X509_NAME:
1545             encodeFunc = CRYPT_AsnEncodeName;
1546             break;
1547         case (WORD)X509_BASIC_CONSTRAINTS2:
1548             encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
1549             break;
1550         case (WORD)X509_OCTET_STRING:
1551             encodeFunc = CRYPT_AsnEncodeOctets;
1552             break;
1553         case (WORD)X509_BITS:
1554         case (WORD)X509_KEY_USAGE:
1555             encodeFunc = CRYPT_AsnEncodeBits;
1556             break;
1557         case (WORD)X509_INTEGER:
1558             encodeFunc = CRYPT_AsnEncodeInt;
1559             break;
1560         case (WORD)X509_MULTI_BYTE_INTEGER:
1561             encodeFunc = CRYPT_AsnEncodeInteger;
1562             break;
1563         case (WORD)X509_MULTI_BYTE_UINT:
1564             encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
1565             break;
1566         case (WORD)X509_ENUMERATED:
1567             encodeFunc = CRYPT_AsnEncodeEnumerated;
1568             break;
1569         case (WORD)X509_CHOICE_OF_TIME:
1570             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
1571             break;
1572         case (WORD)X509_SEQUENCE_OF_ANY:
1573             encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
1574             break;
1575         case (WORD)PKCS_UTC_TIME:
1576             encodeFunc = CRYPT_AsnEncodeUtcTime;
1577             break;
1578         default:
1579             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1580         }
1581     }
1582     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
1583         encodeFunc = CRYPT_AsnEncodeExtensions;
1584     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1585         encodeFunc = CRYPT_AsnEncodeUtcTime;
1586     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
1587         encodeFunc = CRYPT_AsnEncodeEnumerated;
1588     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
1589         encodeFunc = CRYPT_AsnEncodeBits;
1590     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
1591         encodeFunc = CRYPT_AsnEncodeOctets;
1592     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
1593         encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
1594     else
1595         TRACE("OID %s not found or unimplemented, looking for DLL\n",
1596          debugstr_a(lpszStructType));
1597     if (!encodeFunc)
1598         encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1599          lpszStructType, "CryptEncodeObjectEx", &lib);
1600     if (encodeFunc)
1601         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
1602          dwFlags, pEncodePara, pvEncoded, pcbEncoded);
1603     else
1604         SetLastError(ERROR_FILE_NOT_FOUND);
1605     if (lib)
1606         FreeLibrary(lib);
1607     return ret;
1608 }
1609
1610 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1611  DWORD, DWORD, void *, DWORD *);
1612
1613 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1614  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
1615  DWORD *pcbStructInfo)
1616 {
1617     BOOL ret = FALSE;
1618     HMODULE lib;
1619     CryptDecodeObjectFunc pCryptDecodeObject;
1620
1621     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
1622      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1623      "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1624      pcbStructInfo);
1625
1626     if (!pvStructInfo && !pcbStructInfo)
1627     {
1628         SetLastError(ERROR_INVALID_PARAMETER);
1629         return FALSE;
1630     }
1631
1632     /* Try registered DLL first.. */
1633     pCryptDecodeObject =
1634      (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
1635      lpszStructType, "CryptDecodeObject", &lib);
1636     if (pCryptDecodeObject)
1637     {
1638         ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
1639          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1640         FreeLibrary(lib);
1641     }
1642     else
1643     {
1644         /* If not, use CryptDecodeObjectEx */
1645         ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
1646          cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
1647     }
1648     return ret;
1649 }
1650
1651 /* Gets the number of length bytes from the given (leading) length byte */
1652 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
1653
1654 /* Helper function to get the encoded length of the data starting at pbEncoded,
1655  * where pbEncoded[0] is the tag.  If the data are too short to contain a
1656  * length or if the length is too large for cbEncoded, sets an appropriate
1657  * error code and returns FALSE.
1658  */
1659 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
1660  DWORD *len)
1661 {
1662     BOOL ret;
1663
1664     if (cbEncoded <= 1)
1665     {
1666         SetLastError(CRYPT_E_ASN1_EOD);
1667         ret = FALSE;
1668     }
1669     else if (pbEncoded[1] <= 0x7f)
1670     {
1671         *len = pbEncoded[1];
1672         ret = TRUE;
1673     }
1674     else
1675     {
1676         BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
1677
1678         if (lenLen > sizeof(DWORD) + 1)
1679         {
1680             SetLastError(CRYPT_E_ASN1_LARGE);
1681             ret = FALSE;
1682         }
1683         else if (lenLen + 2 > cbEncoded)
1684         {
1685             SetLastError(CRYPT_E_ASN1_CORRUPT);
1686             ret = FALSE;
1687         }
1688         else
1689         {
1690             DWORD out = 0;
1691
1692             pbEncoded += 2;
1693             while (--lenLen)
1694             {
1695                 out <<= 8;
1696                 out |= *pbEncoded++;
1697             }
1698             if (out + lenLen + 1 > cbEncoded)
1699             {
1700                 SetLastError(CRYPT_E_ASN1_EOD);
1701                 ret = FALSE;
1702             }
1703             else
1704             {
1705                 *len = out;
1706                 ret = TRUE;
1707             }
1708         }
1709     }
1710     return ret;
1711 }
1712
1713 /* Helper function to check *pcbStructInfo, set it to the required size, and
1714  * optionally to allocate memory.  Assumes pvStructInfo is not NULL.
1715  * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
1716  * pointer to the newly allocated memory.
1717  */
1718 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
1719  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
1720  DWORD bytesNeeded)
1721 {
1722     BOOL ret = TRUE;
1723
1724     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1725     {
1726         if (pDecodePara && pDecodePara->pfnAlloc)
1727             *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
1728         else
1729             *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
1730         if (!*(BYTE **)pvStructInfo)
1731             ret = FALSE;
1732         else
1733             *pcbStructInfo = bytesNeeded;
1734     }
1735     else if (*pcbStructInfo < bytesNeeded)
1736     {
1737         *pcbStructInfo = bytesNeeded;
1738         SetLastError(ERROR_MORE_DATA);
1739         ret = FALSE;
1740     }
1741     return ret;
1742 }
1743
1744 /* Warning:  assumes ext->Value.pbData is set ahead of time! */
1745 static BOOL CRYPT_AsnDecodeExtension(const BYTE *pbEncoded, DWORD cbEncoded,
1746  DWORD dwFlags, CERT_EXTENSION *ext, DWORD *pcbExt)
1747 {
1748     BOOL ret = TRUE;
1749
1750     if (pbEncoded[0] == ASN_SEQUENCE)
1751     {
1752         DWORD dataLen, bytesNeeded;
1753
1754         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1755         {
1756             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]), oidLenBytes = 0;
1757
1758             bytesNeeded = sizeof(CERT_EXTENSION);
1759             if (dataLen)
1760             {
1761                 const BYTE *ptr = pbEncoded + 1 + lenBytes;
1762                 DWORD encodedOidLen, oidLen;
1763
1764                 CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1765                  &encodedOidLen);
1766                 oidLenBytes = GET_LEN_BYTES(ptr[1]);
1767                 ret = CRYPT_AsnDecodeOid(ptr, cbEncoded - (ptr - pbEncoded), 
1768                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, &oidLen);
1769                 if (ret)
1770                 {
1771                     bytesNeeded += oidLen;
1772                     ptr += 1 + encodedOidLen + oidLenBytes;
1773                     if (*ptr == ASN_BOOL)
1774                         ptr += 3;
1775                     ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
1776                      X509_OCTET_STRING, ptr, cbEncoded - (ptr - pbEncoded),
1777                      0, NULL, NULL, &dataLen);
1778                     bytesNeeded += dataLen;
1779                     if (ret)
1780                     {
1781                         if (!ext)
1782                             *pcbExt = bytesNeeded;
1783                         else if (*pcbExt < bytesNeeded)
1784                         {
1785                             SetLastError(ERROR_MORE_DATA);
1786                             ret = FALSE;
1787                         }
1788                         else
1789                         {
1790                             ptr = pbEncoded + 2 + lenBytes + encodedOidLen +
1791                              oidLenBytes;
1792                             if (*ptr == ASN_BOOL)
1793                             {
1794                                 CRYPT_DecodeBool(ptr, cbEncoded -
1795                                  (ptr - pbEncoded), &ext->fCritical);
1796                                 ptr += 3;
1797                             }
1798                             ret = CRYPT_AsnDecodeOctets(X509_ASN_ENCODING,
1799                              X509_OCTET_STRING, ptr,
1800                              cbEncoded - (ptr - pbEncoded),
1801                              dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
1802                              &ext->Value, &dataLen);
1803                             if (ret)
1804                             {
1805                                 ext->pszObjId = ext->Value.pbData +
1806                                  ext->Value.cbData;
1807                                 ptr = pbEncoded + 1 + lenBytes;
1808                                 ret = CRYPT_AsnDecodeOid(ptr,
1809                                  cbEncoded - (ptr - pbEncoded), 
1810                                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG,
1811                                  ext->pszObjId, &oidLen);
1812                             }
1813                         }
1814                     }
1815                 }
1816             }
1817             else
1818             {
1819                 SetLastError(CRYPT_E_ASN1_EOD);
1820                 ret = FALSE;
1821             }
1822         }
1823     }
1824     else
1825     {
1826         SetLastError(CRYPT_E_ASN1_BADTAG);
1827         ret = FALSE;
1828     }
1829     return ret;
1830 }
1831
1832 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
1833  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1834  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1835 {
1836     BOOL ret = TRUE;
1837
1838     __TRY
1839     {
1840         if (pbEncoded[0] == ASN_SEQUENCEOF)
1841         {
1842             DWORD dataLen, bytesNeeded;
1843
1844             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1845             {
1846                 DWORD cExtension = 0;
1847                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1848
1849                 bytesNeeded = sizeof(CERT_EXTENSIONS);
1850                 if (dataLen)
1851                 {
1852                     const BYTE *ptr;
1853                     DWORD size;
1854
1855                     for (ptr = pbEncoded + 1 + lenBytes; ret &&
1856                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
1857                     {
1858                         ret = CRYPT_AsnDecodeExtension(ptr,
1859                          cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1860                         if (ret)
1861                         {
1862                             DWORD nextLen;
1863
1864                             cExtension++;
1865                             bytesNeeded += size;
1866                             ret = CRYPT_GetLen(ptr,
1867                              cbEncoded - (ptr - pbEncoded), &nextLen);
1868                             if (ret)
1869                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1870                         }
1871                     }
1872                 }
1873                 if (ret)
1874                 {
1875                     if (!pvStructInfo)
1876                         *pcbStructInfo = bytesNeeded;
1877                     else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
1878                      pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
1879                     {
1880                         DWORD size, i;
1881                         BYTE *nextData;
1882                         const BYTE *ptr;
1883                         CERT_EXTENSIONS *exts;
1884
1885                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1886                             pvStructInfo = *(BYTE **)pvStructInfo;
1887                         *pcbStructInfo = bytesNeeded;
1888                         exts = (CERT_EXTENSIONS *)pvStructInfo;
1889                         exts->cExtension = cExtension;
1890                         exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
1891                          sizeof(CERT_EXTENSIONS));
1892                         nextData = (BYTE *)exts->rgExtension +
1893                          exts->cExtension * sizeof(CERT_EXTENSION);
1894                         for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
1895                          i < cExtension && ptr - pbEncoded - 1 - lenBytes <
1896                          dataLen; i++)
1897                         {
1898                             exts->rgExtension[i].Value.pbData = nextData;
1899                             size = bytesNeeded;
1900                             ret = CRYPT_AsnDecodeExtension(ptr,
1901                              cbEncoded - (ptr - pbEncoded), dwFlags,
1902                              &exts->rgExtension[i], &size);
1903                             if (ret)
1904                             {
1905                                 DWORD nextLen;
1906
1907                                 bytesNeeded -= size;
1908                                 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
1909                                  * data may not have been copied.
1910                                  */
1911                                 if (exts->rgExtension[i].Value.pbData ==
1912                                  nextData)
1913                                     nextData +=
1914                                      exts->rgExtension[i].Value.cbData;
1915                                 /* Ugly: the OID, if copied, is stored in
1916                                  * memory after the value, so increment by its
1917                                  * string length if it's set and points here.
1918                                  */
1919                                 if ((const BYTE *)exts->rgExtension[i].pszObjId
1920                                  == nextData)
1921                                     nextData += strlen(
1922                                      exts->rgExtension[i].pszObjId) + 1;
1923                                 ret = CRYPT_GetLen(ptr,
1924                                  cbEncoded - (ptr - pbEncoded), &nextLen);
1925                                 if (ret)
1926                                     ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1927                             }
1928                         }
1929                     }
1930                 }
1931             }
1932         }
1933         else
1934         {
1935             SetLastError(CRYPT_E_ASN1_BADTAG);
1936             ret = FALSE;
1937         }
1938     }
1939     __EXCEPT(page_fault)
1940     {
1941         SetLastError(STATUS_ACCESS_VIOLATION);
1942         ret = FALSE;
1943     }
1944     __ENDTRY
1945     return ret;
1946 }
1947
1948 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
1949 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
1950  DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
1951 {
1952     BOOL ret = TRUE;
1953
1954     __TRY
1955     {
1956         if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
1957         {
1958             DWORD dataLen;
1959
1960             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
1961             {
1962                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1963                 DWORD bytesNeeded;
1964
1965                 if (dataLen)
1966                 {
1967                     /* The largest possible string for the first two components
1968                      * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
1969                      */
1970                     char firstTwo[6];
1971                     const BYTE *ptr;
1972
1973                     snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1974                      pbEncoded[1 + lenBytes] / 40,
1975                      pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
1976                      * 40);
1977                     bytesNeeded = strlen(firstTwo) + 1;
1978                     for (ptr = pbEncoded + 2 + lenBytes; ret &&
1979                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
1980                     {
1981                         /* large enough for ".4000000" */
1982                         char str[9];
1983                         int val = 0;
1984
1985                         while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1986                          (*ptr & 0x80))
1987                         {
1988                             val <<= 7;
1989                             val |= *ptr & 0x7f;
1990                             ptr++;
1991                         }
1992                         if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
1993                          (*ptr & 0x80))
1994                         {
1995                             SetLastError(CRYPT_E_ASN1_CORRUPT);
1996                             ret = FALSE;
1997                         }
1998                         else
1999                         {
2000                             val <<= 7;
2001                             val |= *ptr++;
2002                             snprintf(str, sizeof(str), ".%d", val);
2003                             bytesNeeded += strlen(str);
2004                         }
2005                     }
2006                     if (!pszObjId)
2007                         *pcbObjId = bytesNeeded;
2008                     else if (*pcbObjId < bytesNeeded)
2009                     {
2010                         *pcbObjId = bytesNeeded;
2011                         SetLastError(ERROR_MORE_DATA);
2012                         ret = FALSE;
2013                     }
2014                     else
2015                     {
2016                         sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
2017                          pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
2018                          40) * 40);
2019                         pszObjId += strlen(pszObjId);
2020                         for (ptr = pbEncoded + 2 + lenBytes; ret &&
2021                          ptr - pbEncoded - 1 - lenBytes < dataLen; )
2022                         {
2023                             int val = 0;
2024
2025                             while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
2026                              (*ptr & 0x80))
2027                             {
2028                                 val <<= 7;
2029                                 val |= *ptr & 0x7f;
2030                                 ptr++;
2031                             }
2032                             val <<= 7;
2033                             val |= *ptr++;
2034                             sprintf(pszObjId, ".%d", val);
2035                             pszObjId += strlen(pszObjId);
2036                         }
2037                     }
2038                 }
2039                 else
2040                     bytesNeeded = 0;
2041                 *pcbObjId = bytesNeeded;
2042             }
2043         }
2044         else
2045         {
2046             SetLastError(CRYPT_E_ASN1_BADTAG);
2047             ret = FALSE;
2048         }
2049     }
2050     __EXCEPT(page_fault)
2051     {
2052         SetLastError(STATUS_ACCESS_VIOLATION);
2053         ret = FALSE;
2054     }
2055     __ENDTRY
2056     return ret;
2057 }
2058
2059 /* Warning: this assumes the address of value->Value.pbData is already set, in
2060  * order to avoid overwriting memory.  (In some cases, it may change it, if it
2061  * doesn't copy anything to memory.)  Be sure to set it correctly!
2062  */
2063 static BOOL WINAPI CRYPT_AsnDecodeNameValue(const BYTE *pbEncoded,
2064  DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value, DWORD *pcbValue)
2065 {
2066     BOOL ret = TRUE;
2067
2068     __TRY
2069     {
2070         DWORD dataLen;
2071
2072         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2073         {
2074             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2075
2076             switch (pbEncoded[0])
2077             {
2078             case ASN_NUMERICSTRING:
2079             case ASN_PRINTABLESTRING:
2080             case ASN_IA5STRING:
2081                 break;
2082             default:
2083                 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
2084                 SetLastError(OSS_UNIMPLEMENTED);
2085                 ret = FALSE;
2086             }
2087             if (ret)
2088             {
2089                 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
2090
2091                 switch (pbEncoded[0])
2092                 {
2093                 case ASN_NUMERICSTRING:
2094                 case ASN_PRINTABLESTRING:
2095                 case ASN_IA5STRING:
2096                     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2097                         bytesNeeded += dataLen;
2098                     break;
2099                 }
2100                 if (!value)
2101                     *pcbValue = bytesNeeded;
2102                 else if (*pcbValue < bytesNeeded)
2103                 {
2104                     *pcbValue = bytesNeeded;
2105                     SetLastError(ERROR_MORE_DATA);
2106                     ret = FALSE;
2107                 }
2108                 else
2109                 {
2110                     *pcbValue = bytesNeeded;
2111                     switch (pbEncoded[0])
2112                     {
2113                     case ASN_NUMERICSTRING:
2114                         value->dwValueType = CERT_RDN_NUMERIC_STRING;
2115                         break;
2116                     case ASN_PRINTABLESTRING:
2117                         value->dwValueType = CERT_RDN_PRINTABLE_STRING;
2118                         break;
2119                     case ASN_IA5STRING:
2120                         value->dwValueType = CERT_RDN_IA5_STRING;
2121                         break;
2122                     }
2123                     if (dataLen)
2124                     {
2125                         switch (pbEncoded[0])
2126                         {
2127                         case ASN_NUMERICSTRING:
2128                         case ASN_PRINTABLESTRING:
2129                         case ASN_IA5STRING:
2130                             value->Value.cbData = dataLen;
2131                             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2132                                 value->Value.pbData = (BYTE *)pbEncoded + 1 +
2133                                  lenBytes;
2134                             else
2135                             {
2136                                 if (!value->Value.pbData)
2137                                 {
2138                                     SetLastError(CRYPT_E_ASN1_INTERNAL);
2139                                     ret = FALSE;
2140                                 }
2141                                 else
2142                                     memcpy(value->Value.pbData,
2143                                      pbEncoded + 1 + lenBytes, dataLen);
2144                             }
2145                             break;
2146                         }
2147                     }
2148                     else
2149                     {
2150                         value->Value.cbData = 0;
2151                         value->Value.pbData = NULL;
2152                     }
2153                 }
2154             }
2155         }
2156     }
2157     __EXCEPT(page_fault)
2158     {
2159         SetLastError(STATUS_ACCESS_VIOLATION);
2160         ret = FALSE;
2161     }
2162     __ENDTRY
2163     return ret;
2164 }
2165
2166 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(const BYTE *pbEncoded,
2167  DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr, DWORD *pcbAttr)
2168 {
2169     BOOL ret;
2170
2171     __TRY
2172     {
2173         if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCE))
2174         {
2175             DWORD bytesNeeded, dataLen, size;
2176             BYTE lenBytes;
2177
2178             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2179             {
2180                 /* The data length must be at least 4, two for the tag and
2181                  * length for the OID, and two for the string (assuming both
2182                  * have short-form lengths.)
2183                  */
2184                 if (dataLen < 4)
2185                 {
2186                     SetLastError(CRYPT_E_ASN1_EOD);
2187                     ret = FALSE;
2188                 }
2189                 else
2190                 {
2191                     bytesNeeded = sizeof(CERT_RDN_ATTR);
2192                     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2193                     ret = CRYPT_AsnDecodeOid(pbEncoded + 1 + lenBytes,
2194                      cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
2195                     if (ret)
2196                     {
2197                         /* ugly: need to know the size of the next element of
2198                          * the sequence, so get it directly
2199                          */
2200                         DWORD objIdOfset = 1 + lenBytes, objIdLen,
2201                          nameValueOffset = 0;
2202
2203                         ret = CRYPT_GetLen(pbEncoded + objIdOfset,
2204                          cbEncoded - objIdOfset, &objIdLen);
2205                         bytesNeeded += size;
2206                         /* hack: like encoding, this takes advantage of the
2207                          * fact that the rest of the structure is identical to
2208                          * a CERT_NAME_VALUE.
2209                          */
2210                         if (ret)
2211                         {
2212                             nameValueOffset = objIdOfset + objIdLen + 1 +
2213                              GET_LEN_BYTES(pbEncoded[objIdOfset]);
2214                             ret = CRYPT_AsnDecodeNameValue(
2215                              pbEncoded + nameValueOffset,
2216                              cbEncoded - nameValueOffset, dwFlags, NULL, &size);
2217                         }
2218                         if (ret)
2219                         {
2220                             bytesNeeded += size;
2221                             if (!attr)
2222                                 *pcbAttr = bytesNeeded;
2223                             else if (*pcbAttr < bytesNeeded)
2224                             {
2225                                 *pcbAttr = bytesNeeded;
2226                                 SetLastError(ERROR_MORE_DATA);
2227                                 ret = FALSE;
2228                             }
2229                             else
2230                             {
2231                                 BYTE *originalData = attr->Value.pbData;
2232
2233                                 *pcbAttr = bytesNeeded;
2234                                 /* strange: decode the value first, because it
2235                                  * has a counted size, and we can store the OID
2236                                  * after it.  Keep track of the original data
2237                                  * pointer, we'll need to know whether it was
2238                                  * changed.
2239                                  */
2240                                 size = bytesNeeded;
2241                                 ret = CRYPT_AsnDecodeNameValue(
2242                                  pbEncoded + nameValueOffset,
2243                                  cbEncoded - nameValueOffset, dwFlags,
2244                                  (CERT_NAME_VALUE *)&attr->dwValueType, &size);
2245                                 if (ret)
2246                                 {
2247                                     if (objIdLen)
2248                                     {
2249                                         /* if the data were copied to the
2250                                          * original location, the OID goes
2251                                          * after.  Otherwise it goes in the
2252                                          * spot originally reserved for the
2253                                          * data.
2254                                          */
2255                                         if (attr->Value.pbData == originalData)
2256                                             attr->pszObjId =
2257                                              (LPSTR)(attr->Value.pbData +
2258                                              attr->Value.cbData);
2259                                         else
2260                                             attr->pszObjId = originalData;
2261                                         size = bytesNeeded - size;
2262                                         ret = CRYPT_AsnDecodeOid(
2263                                          pbEncoded + objIdOfset,
2264                                          cbEncoded - objIdOfset,
2265                                          dwFlags, attr->pszObjId, &size);
2266                                     }
2267                                     else
2268                                         attr->pszObjId = NULL;
2269                                 }
2270                             }
2271                         }
2272                     }
2273                 }
2274             }
2275         }
2276         else
2277         {
2278             SetLastError(CRYPT_E_ASN1_BADTAG);
2279             ret = FALSE;
2280         }
2281     }
2282     __EXCEPT(page_fault)
2283     {
2284         SetLastError(STATUS_ACCESS_VIOLATION);
2285         ret = FALSE;
2286     }
2287     __ENDTRY
2288     return ret;
2289 }
2290
2291 static BOOL WINAPI CRYPT_AsnDecodeRdn(const BYTE *pbEncoded, DWORD cbEncoded,
2292  DWORD dwFlags, CERT_RDN *rdn, DWORD *pcbRdn)
2293 {
2294     BOOL ret = TRUE;
2295
2296     __TRY
2297     {
2298         if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SETOF))
2299         {
2300             DWORD dataLen;
2301
2302             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2303             {
2304                 DWORD bytesNeeded, cRDNAttr = 0;
2305                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2306
2307                 bytesNeeded = sizeof(CERT_RDN);
2308                 if (dataLen)
2309                 {
2310                     const BYTE *ptr;
2311                     DWORD size;
2312
2313                     for (ptr = pbEncoded + 1 + lenBytes; ret &&
2314                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
2315                     {
2316                         ret = CRYPT_AsnDecodeRdnAttr(ptr,
2317                          cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
2318                         if (ret)
2319                         {
2320                             DWORD nextLen;
2321
2322                             cRDNAttr++;
2323                             bytesNeeded += size;
2324                             ret = CRYPT_GetLen(ptr,
2325                              cbEncoded - (ptr - pbEncoded), &nextLen);
2326                             if (ret)
2327                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2328                         }
2329                     }
2330                 }
2331                 if (ret)
2332                 {
2333                     if (!rdn)
2334                         *pcbRdn = bytesNeeded;
2335                     else if (*pcbRdn < bytesNeeded)
2336                     {
2337                         *pcbRdn = bytesNeeded;
2338                         SetLastError(ERROR_MORE_DATA);
2339                         ret = FALSE;
2340                     }
2341                     else
2342                     {
2343                         DWORD size, i;
2344                         BYTE *nextData;
2345                         const BYTE *ptr;
2346
2347                         *pcbRdn = bytesNeeded;
2348                         rdn->cRDNAttr = cRDNAttr;
2349                         rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn +
2350                          sizeof(CERT_RDN));
2351                         nextData = (BYTE *)rdn->rgRDNAttr +
2352                          rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
2353                         for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
2354                          i < cRDNAttr && ptr - pbEncoded - 1 - lenBytes <
2355                          dataLen; i++)
2356                         {
2357                             rdn->rgRDNAttr[i].Value.pbData = nextData;
2358                             size = bytesNeeded;
2359                             ret = CRYPT_AsnDecodeRdnAttr(ptr,
2360                              cbEncoded - (ptr - pbEncoded), dwFlags,
2361                              &rdn->rgRDNAttr[i], &size);
2362                             if (ret)
2363                             {
2364                                 DWORD nextLen;
2365
2366                                 bytesNeeded -= size;
2367                                 /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the
2368                                  * data may not have been copied.
2369                                  */
2370                                 if (rdn->rgRDNAttr[i].Value.pbData == nextData)
2371                                     nextData +=
2372                                      rdn->rgRDNAttr[i].Value.cbData;
2373                                 /* Ugly: the OID, if copied, is stored in
2374                                  * memory after the value, so increment by its
2375                                  * string length if it's set and points here.
2376                                  */
2377                                 if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId
2378                                  == nextData)
2379                                     nextData += strlen(
2380                                      rdn->rgRDNAttr[i].pszObjId) + 1;
2381                                 ret = CRYPT_GetLen(ptr,
2382                                  cbEncoded - (ptr - pbEncoded), &nextLen);
2383                                 if (ret)
2384                                     ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2385                             }
2386                         }
2387                     }
2388                 }
2389             }
2390         }
2391         else
2392         {
2393             SetLastError(CRYPT_E_ASN1_BADTAG);
2394             ret = FALSE;
2395         }
2396     }
2397     __EXCEPT(page_fault)
2398     {
2399         SetLastError(STATUS_ACCESS_VIOLATION);
2400         ret = FALSE;
2401     }
2402     __ENDTRY
2403     return ret;
2404 }
2405
2406 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
2407  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2408  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2409 {
2410     BOOL ret = TRUE;
2411
2412     __TRY
2413     {
2414         if (pbEncoded[0] == (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
2415         {
2416             DWORD dataLen;
2417
2418             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2419             {
2420                 DWORD bytesNeeded, cRDN = 0;
2421                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2422
2423                 bytesNeeded = sizeof(CERT_NAME_INFO);
2424                 if (dataLen)
2425                 {
2426                     const BYTE *ptr;
2427
2428                     for (ptr = pbEncoded + 1 + lenBytes; ret &&
2429                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
2430                     {
2431                         DWORD size;
2432
2433                         ret = CRYPT_AsnDecodeRdn(ptr,
2434                          cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
2435                         if (ret)
2436                         {
2437                             DWORD nextLen;
2438
2439                             cRDN++;
2440                             bytesNeeded += size;
2441                             ret = CRYPT_GetLen(ptr,
2442                              cbEncoded - (ptr - pbEncoded), &nextLen);
2443                             if (ret)
2444                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2445                         }
2446                     }
2447                 }
2448                 if (ret)
2449                 {
2450                     if (!pvStructInfo)
2451                         *pcbStructInfo = bytesNeeded;
2452                     else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2453                      pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2454                     {
2455                         CERT_NAME_INFO *info;
2456
2457                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2458                             pvStructInfo = *(BYTE **)pvStructInfo;
2459                         info = (CERT_NAME_INFO *)pvStructInfo;
2460                         info->cRDN = cRDN;
2461                         if (info->cRDN == 0)
2462                             info->rgRDN = NULL;
2463                         else
2464                         {
2465                             DWORD size, i;
2466                             BYTE *nextData;
2467                             const BYTE *ptr;
2468
2469                             info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
2470                              sizeof(CERT_NAME_INFO));
2471                             nextData = (BYTE *)info->rgRDN +
2472                              info->cRDN * sizeof(CERT_RDN);
2473                             for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
2474                              i < cRDN && ptr - pbEncoded - 1 - lenBytes <
2475                              dataLen; i++)
2476                             {
2477                                 info->rgRDN[i].rgRDNAttr =
2478                                  (CERT_RDN_ATTR *)nextData;
2479                                 size = bytesNeeded;
2480                                 ret = CRYPT_AsnDecodeRdn(ptr,
2481                                  cbEncoded - (ptr - pbEncoded), dwFlags,
2482                                  &info->rgRDN[i], &size);
2483                                 if (ret)
2484                                 {
2485                                     DWORD nextLen;
2486
2487                                     nextData += size;
2488                                     bytesNeeded -= size;
2489                                     ret = CRYPT_GetLen(ptr,
2490                                      cbEncoded - (ptr - pbEncoded), &nextLen);
2491                                     if (ret)
2492                                         ptr += nextLen + 1 +
2493                                          GET_LEN_BYTES(ptr[1]);
2494                                 }
2495                             }
2496                         }
2497                     }
2498                 }
2499                 else
2500                 {
2501                     SetLastError(CRYPT_E_ASN1_BADTAG);
2502                     ret = FALSE;
2503                 }
2504             }
2505         }
2506     }
2507     __EXCEPT(page_fault)
2508     {
2509         SetLastError(STATUS_ACCESS_VIOLATION);
2510         ret = FALSE;
2511     }
2512     __ENDTRY
2513     return ret;
2514 }
2515
2516 static BOOL WINAPI CRYPT_DecodeBool(const BYTE *pbEncoded, DWORD cbEncoded,
2517  BOOL *val)
2518 {
2519     if (cbEncoded < 3)
2520     {
2521         SetLastError(CRYPT_E_ASN1_CORRUPT);
2522         return FALSE;
2523     }
2524     if (pbEncoded[0] != ASN_BOOL)
2525     {
2526         SetLastError(CRYPT_E_ASN1_BADTAG);
2527         return FALSE;
2528     }
2529     if (GET_LEN_BYTES(pbEncoded[1]) > 1)
2530     {
2531         SetLastError(CRYPT_E_ASN1_CORRUPT);
2532         return FALSE;
2533     }
2534     if (pbEncoded[1] > 1)
2535     {
2536         SetLastError(CRYPT_E_ASN1_CORRUPT);
2537         return FALSE;
2538     }
2539     *val = pbEncoded[2] ? TRUE : FALSE;
2540     return TRUE;
2541 }
2542
2543 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
2544  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2545  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2546 {
2547     BOOL ret;
2548
2549     __TRY
2550     {
2551         if (pbEncoded[0] == ASN_SEQUENCE)
2552         {
2553             DWORD dataLen;
2554
2555             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2556             {
2557                 /* sanity-check length, space enough for 7 bytes of integer and
2558                  * 3 bytes of bool
2559                  */
2560                 if (dataLen > 10)
2561                 {
2562                     SetLastError(CRYPT_E_ASN1_CORRUPT);
2563                     ret = FALSE;
2564                 }
2565                 else
2566                 {
2567                     DWORD bytesNeeded = sizeof(CERT_BASIC_CONSTRAINTS2_INFO);
2568
2569                     if (!pvStructInfo)
2570                         *pcbStructInfo = bytesNeeded;
2571                     else
2572                     {
2573                         BYTE lenBytes;
2574                         CERT_BASIC_CONSTRAINTS2_INFO info = { 0 };
2575
2576                         lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2577                         pbEncoded += 1 + lenBytes;
2578                         cbEncoded -= 1 + lenBytes;
2579                         if (cbEncoded)
2580                         {
2581                             DWORD size;
2582
2583                             if (pbEncoded[0] == ASN_BOOL)
2584                             {
2585                                 ret = CRYPT_DecodeBool(pbEncoded, cbEncoded,
2586                                  &info.fCA);
2587                                 if (ret)
2588                                 {
2589                                     cbEncoded -= 2 + pbEncoded[1];
2590                                     pbEncoded += 2 + pbEncoded[1];
2591                                 }
2592                             }
2593                             if (ret && cbEncoded && pbEncoded[0] == ASN_INTEGER)
2594                             {
2595                                 size = sizeof(info.dwPathLenConstraint);
2596                                 ret = CRYPT_AsnDecodeInt(dwCertEncodingType,
2597                                  X509_INTEGER, pbEncoded, cbEncoded, 0, NULL,
2598                                  &info.dwPathLenConstraint, &size);
2599                                 if (ret)
2600                                 {
2601                                     cbEncoded -= 2 + pbEncoded[1];
2602                                     pbEncoded += 2 + pbEncoded[1];
2603                                     if (cbEncoded)
2604                                     {
2605                                         SetLastError(CRYPT_E_ASN1_CORRUPT);
2606                                         ret = FALSE;
2607                                     }
2608                                     else
2609                                         info.fPathLenConstraint = TRUE;
2610                                 }
2611                             }
2612                         }
2613                         if (ret)
2614                         {
2615                             if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2616                              pDecodePara, pvStructInfo, pcbStructInfo,
2617                              bytesNeeded)))
2618                             {
2619                                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2620                                     pvStructInfo = *(BYTE **)pvStructInfo;
2621                                 memcpy(pvStructInfo, &info,
2622                                  sizeof(CERT_BASIC_CONSTRAINTS2_INFO));
2623                             }
2624                         }
2625                     }
2626                 }
2627             }
2628         }
2629         else
2630         {
2631             SetLastError(CRYPT_E_ASN1_BADTAG);
2632             ret = FALSE;
2633         }
2634     }
2635     __EXCEPT(page_fault)
2636     {
2637         SetLastError(STATUS_ACCESS_VIOLATION);
2638         ret = FALSE;
2639     }
2640     __ENDTRY
2641     return ret;
2642 }
2643
2644 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
2645  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2646  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2647 {
2648     BOOL ret;
2649
2650     __TRY
2651     {
2652         if (pbEncoded[0] == ASN_OCTETSTRING)
2653         {
2654             DWORD bytesNeeded, dataLen;
2655
2656             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2657             {
2658                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2659                     bytesNeeded = sizeof(CRYPT_DATA_BLOB);
2660                 else
2661                     bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
2662                 if (!pvStructInfo)
2663                     *pcbStructInfo = bytesNeeded;
2664                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2665                  pvStructInfo, pcbStructInfo, bytesNeeded)))
2666                 {
2667                     CRYPT_DATA_BLOB *blob;
2668                     BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2669
2670                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2671                         pvStructInfo = *(BYTE **)pvStructInfo;
2672                     blob = (CRYPT_DATA_BLOB *)pvStructInfo;
2673                     blob->cbData = dataLen;
2674                     if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2675                         blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
2676                     else
2677                     {
2678                         blob->pbData = (BYTE *)pvStructInfo +
2679                          sizeof(CRYPT_DATA_BLOB);
2680                         if (blob->cbData)
2681                             memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
2682                              blob->cbData);
2683                     }
2684                 }
2685             }
2686         }
2687         else
2688         {
2689             SetLastError(CRYPT_E_ASN1_BADTAG);
2690             ret = FALSE;
2691         }
2692     }
2693     __EXCEPT(page_fault)
2694     {
2695         SetLastError(STATUS_ACCESS_VIOLATION);
2696         ret = FALSE;
2697     }
2698     __ENDTRY
2699     return ret;
2700 }
2701
2702 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
2703  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2704  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2705 {
2706     BOOL ret;
2707
2708     __TRY
2709     {
2710         if (pbEncoded[0] == ASN_BITSTRING)
2711         {
2712             DWORD bytesNeeded, dataLen;
2713
2714             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2715             {
2716                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2717                     bytesNeeded = sizeof(CRYPT_BIT_BLOB);
2718                 else
2719                     bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
2720                 if (!pvStructInfo)
2721                     *pcbStructInfo = bytesNeeded;
2722                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2723                  pvStructInfo, pcbStructInfo, bytesNeeded)))
2724                 {
2725                     CRYPT_BIT_BLOB *blob;
2726
2727                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2728                         pvStructInfo = *(BYTE **)pvStructInfo;
2729                     blob = (CRYPT_BIT_BLOB *)pvStructInfo;
2730                     blob->cbData = dataLen - 1;
2731                     blob->cUnusedBits = *(pbEncoded + 1 +
2732                      GET_LEN_BYTES(pbEncoded[1]));
2733                     if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2734                         blob->pbData = (BYTE *)pbEncoded + 2 +
2735                          GET_LEN_BYTES(pbEncoded[1]);
2736                     else
2737                     {
2738                         blob->pbData = (BYTE *)pvStructInfo +
2739                          sizeof(CRYPT_BIT_BLOB);
2740                         if (blob->cbData)
2741                         {
2742                             BYTE mask = 0xff << blob->cUnusedBits;
2743
2744                             memcpy(blob->pbData, pbEncoded + 2 +
2745                              GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
2746                             blob->pbData[blob->cbData - 1] &= mask;
2747                         }
2748                     }
2749                 }
2750             }
2751         }
2752         else
2753         {
2754             SetLastError(CRYPT_E_ASN1_BADTAG);
2755             ret = FALSE;
2756         }
2757     }
2758     __EXCEPT(page_fault)
2759     {
2760         SetLastError(STATUS_ACCESS_VIOLATION);
2761         ret = FALSE;
2762     }
2763     __ENDTRY
2764     return ret;
2765 }
2766
2767 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
2768  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2769  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2770 {
2771     BOOL ret;
2772
2773     if (!pvStructInfo)
2774     {
2775         *pcbStructInfo = sizeof(int);
2776         return TRUE;
2777     }
2778     __TRY
2779     {
2780         BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
2781         DWORD size = sizeof(buf);
2782
2783         ret = CRYPT_AsnDecodeInteger(dwCertEncodingType,
2784          X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
2785         if (ret)
2786         {
2787             CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
2788
2789             if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2790              pvStructInfo, pcbStructInfo, sizeof(int))))
2791             {
2792                 int val, i;
2793
2794                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2795                     pvStructInfo = *(BYTE **)pvStructInfo;
2796                 if (blob->pbData[blob->cbData - 1] & 0x80)
2797                 {
2798                     /* initialize to a negative value to sign-extend */
2799                     val = -1;
2800                 }
2801                 else
2802                     val = 0;
2803                 for (i = 0; i < blob->cbData; i++)
2804                 {
2805                     val <<= 8;
2806                     val |= blob->pbData[blob->cbData - i - 1];
2807                 }
2808                 memcpy(pvStructInfo, &val, sizeof(int));
2809             }
2810         }
2811         else if (GetLastError() == ERROR_MORE_DATA)
2812             SetLastError(CRYPT_E_ASN1_LARGE);
2813     }
2814     __EXCEPT(page_fault)
2815     {
2816         SetLastError(STATUS_ACCESS_VIOLATION);
2817         ret = FALSE;
2818     }
2819     __ENDTRY
2820     return ret;
2821 }
2822
2823 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
2824  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2825  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2826 {
2827     BOOL ret;
2828
2829     __TRY
2830     {
2831         if (pbEncoded[0] == ASN_INTEGER)
2832         {
2833             DWORD bytesNeeded, dataLen;
2834
2835             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2836             {
2837                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2838
2839                 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2840                 if (!pvStructInfo)
2841                     *pcbStructInfo = bytesNeeded;
2842                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2843                  pvStructInfo, pcbStructInfo, bytesNeeded)))
2844                 {
2845                     CRYPT_INTEGER_BLOB *blob;
2846
2847                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2848                         pvStructInfo = *(BYTE **)pvStructInfo;
2849                     blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2850                     blob->cbData = dataLen;
2851                     blob->pbData = (BYTE *)pvStructInfo +
2852                      sizeof(CRYPT_INTEGER_BLOB);
2853                     if (blob->cbData)
2854                     {
2855                         DWORD i;
2856
2857                         for (i = 0; i < blob->cbData; i++)
2858                             blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
2859                              dataLen - i - 1);
2860                     }
2861                 }
2862             }
2863         }
2864         else
2865         {
2866             SetLastError(CRYPT_E_ASN1_BADTAG);
2867             ret = FALSE;
2868         }
2869     }
2870     __EXCEPT(page_fault)
2871     {
2872         SetLastError(STATUS_ACCESS_VIOLATION);
2873         ret = FALSE;
2874     }
2875     __ENDTRY
2876     return ret;
2877 }
2878
2879 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
2880  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2881  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2882 {
2883     BOOL ret;
2884
2885     __TRY
2886     {
2887         if (pbEncoded[0] == ASN_INTEGER)
2888         {
2889             DWORD bytesNeeded, dataLen;
2890             CRYPT_INTEGER_BLOB *blob;
2891
2892             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2893             {
2894                 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2895                 if (!pvStructInfo)
2896                     *pcbStructInfo = bytesNeeded;
2897                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2898                  pvStructInfo, pcbStructInfo, bytesNeeded)))
2899                 {
2900                     BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2901
2902                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2903                         pvStructInfo = *(BYTE **)pvStructInfo;
2904                     blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2905                     blob->cbData = dataLen;
2906                     blob->pbData = (BYTE *)pvStructInfo +
2907                      sizeof(CRYPT_INTEGER_BLOB);
2908                     /* remove leading zero byte if it exists */
2909                     if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
2910                     {
2911                         blob->cbData--;
2912                         blob->pbData++;
2913                     }
2914                     if (blob->cbData)
2915                     {
2916                         DWORD i;
2917
2918                         for (i = 0; i < blob->cbData; i++)
2919                             blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
2920                              pbEncoded[1] - i - 1);
2921                     }
2922                 }
2923             }
2924         }
2925         else
2926         {
2927             SetLastError(CRYPT_E_ASN1_BADTAG);
2928             ret = FALSE;
2929         }
2930     }
2931     __EXCEPT(page_fault)
2932     {
2933         SetLastError(STATUS_ACCESS_VIOLATION);
2934         ret = FALSE;
2935     }
2936     __ENDTRY
2937     return ret;
2938 }
2939
2940 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
2941  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2942  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2943 {
2944     BOOL ret;
2945
2946     if (!pvStructInfo)
2947     {
2948         *pcbStructInfo = sizeof(int);
2949         return TRUE;
2950     }
2951     __TRY
2952     {
2953         if (pbEncoded[0] == ASN_ENUMERATED)
2954         {
2955             unsigned int val = 0, i;
2956
2957             if (cbEncoded <= 1)
2958             {
2959                 SetLastError(CRYPT_E_ASN1_EOD);
2960                 ret = FALSE;
2961             }
2962             else if (pbEncoded[1] == 0)
2963             {
2964                 SetLastError(CRYPT_E_ASN1_CORRUPT);
2965                 ret = FALSE;
2966             }
2967             else
2968             {
2969                 /* A little strange looking, but we have to accept a sign byte:
2970                  * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff.  Also,
2971                  * assuming a small length is okay here, it has to be in short
2972                  * form.
2973                  */
2974                 if (pbEncoded[1] > sizeof(unsigned int) + 1)
2975                 {
2976                     SetLastError(CRYPT_E_ASN1_LARGE);
2977                     return FALSE;
2978                 }
2979                 for (i = 0; i < pbEncoded[1]; i++)
2980                 {
2981                     val <<= 8;
2982                     val |= pbEncoded[2 + i];
2983                 }
2984                 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2985                  pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
2986                 {
2987                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2988                         pvStructInfo = *(BYTE **)pvStructInfo;
2989                     memcpy(pvStructInfo, &val, sizeof(unsigned int));
2990                 }
2991             }
2992         }
2993         else
2994         {
2995             SetLastError(CRYPT_E_ASN1_BADTAG);
2996             ret = FALSE;
2997         }
2998     }
2999     __EXCEPT(page_fault)
3000     {
3001         SetLastError(STATUS_ACCESS_VIOLATION);
3002         ret = FALSE;
3003     }
3004     __ENDTRY
3005     return ret;
3006 }
3007
3008 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
3009  * if it fails.
3010  */
3011 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
3012  do { \
3013     BYTE i; \
3014  \
3015     (word) = 0; \
3016     for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
3017     { \
3018         if (!isdigit(*(pbEncoded))) \
3019         { \
3020             SetLastError(CRYPT_E_ASN1_CORRUPT); \
3021             ret = FALSE; \
3022         } \
3023         else \
3024         { \
3025             (word) *= 10; \
3026             (word) += *(pbEncoded)++ - '0'; \
3027         } \
3028     } \
3029  } while (0)
3030
3031 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
3032  SYSTEMTIME *sysTime)
3033 {
3034     BOOL ret = TRUE;
3035
3036     __TRY
3037     {
3038         if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
3039         {
3040             WORD hours, minutes = 0;
3041             BYTE sign = *pbEncoded++;
3042
3043             len--;
3044             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
3045             if (ret && hours >= 24)
3046             {
3047                 SetLastError(CRYPT_E_ASN1_CORRUPT);
3048                 ret = FALSE;
3049             }
3050             else if (len >= 2)
3051             {
3052                 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
3053                 if (ret && minutes >= 60)
3054                 {
3055                     SetLastError(CRYPT_E_ASN1_CORRUPT);
3056                     ret = FALSE;
3057                 }
3058             }
3059             if (ret)
3060             {
3061                 if (sign == '+')
3062                 {
3063                     sysTime->wHour += hours;
3064                     sysTime->wMinute += minutes;
3065                 }
3066                 else
3067                 {
3068                     if (hours > sysTime->wHour)
3069                     {
3070                         sysTime->wDay--;
3071                         sysTime->wHour = 24 - (hours - sysTime->wHour);
3072                     }
3073                     else
3074                         sysTime->wHour -= hours;
3075                     if (minutes > sysTime->wMinute)
3076                     {
3077                         sysTime->wHour--;
3078                         sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
3079                     }
3080                     else
3081                         sysTime->wMinute -= minutes;
3082                 }
3083             }
3084         }
3085     }
3086     __EXCEPT(page_fault)
3087     {
3088         SetLastError(STATUS_ACCESS_VIOLATION);
3089         ret = FALSE;
3090     }
3091     __ENDTRY
3092     return ret;
3093 }
3094
3095 #define MIN_ENCODED_TIME_LENGTH 10
3096
3097 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
3098  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3099  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3100 {
3101     BOOL ret = TRUE;
3102
3103     if (!pvStructInfo)
3104     {
3105         *pcbStructInfo = sizeof(FILETIME);
3106         return TRUE;
3107     }
3108     __TRY
3109     {
3110         if (pbEncoded[0] == ASN_UTCTIME)
3111         {
3112             if (cbEncoded <= 1)
3113             {
3114                 SetLastError(CRYPT_E_ASN1_EOD);
3115                 ret = FALSE;
3116             }
3117             else if (pbEncoded[1] > 0x7f)
3118             {
3119                 /* long-form date strings really can't be valid */
3120                 SetLastError(CRYPT_E_ASN1_CORRUPT);
3121                 ret = FALSE;
3122             }
3123             else
3124             {
3125                 SYSTEMTIME sysTime = { 0 };
3126                 BYTE len = pbEncoded[1];
3127
3128                 if (len < MIN_ENCODED_TIME_LENGTH)
3129                 {
3130                     SetLastError(CRYPT_E_ASN1_CORRUPT);
3131                     ret = FALSE;
3132                 }
3133                 else
3134                 {
3135                     pbEncoded += 2;
3136                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
3137                     if (sysTime.wYear >= 50)
3138                         sysTime.wYear += 1900;
3139                     else
3140                         sysTime.wYear += 2000;
3141                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
3142                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
3143                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
3144                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
3145                     if (ret && len > 0)
3146                     {
3147                         if (len >= 2 && isdigit(*pbEncoded) &&
3148                          isdigit(*(pbEncoded + 1)))
3149                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
3150                              sysTime.wSecond);
3151                         else if (isdigit(*pbEncoded))
3152                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
3153                              sysTime.wSecond);
3154                         if (ret)
3155                             ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
3156                              &sysTime);
3157                     }
3158                     if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
3159                      pDecodePara, pvStructInfo, pcbStructInfo,
3160                      sizeof(FILETIME))))
3161                     {
3162                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3163                             pvStructInfo = *(BYTE **)pvStructInfo;
3164                         ret = SystemTimeToFileTime(&sysTime,
3165                          (FILETIME *)pvStructInfo);
3166                     }
3167                 }
3168             }
3169         }
3170         else
3171         {
3172             SetLastError(CRYPT_E_ASN1_BADTAG);
3173             ret = FALSE;
3174         }
3175     }
3176     __EXCEPT(page_fault)
3177     {
3178         SetLastError(STATUS_ACCESS_VIOLATION);
3179         ret = FALSE;
3180     }
3181     __ENDTRY
3182     return ret;
3183 }
3184
3185 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
3186  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3187  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3188 {
3189     BOOL ret = TRUE;
3190
3191     if (!pvStructInfo)
3192     {
3193         *pcbStructInfo = sizeof(FILETIME);
3194         return TRUE;
3195     }
3196     __TRY
3197     {
3198         if (pbEncoded[0] == ASN_GENERALTIME)
3199         {
3200             if (cbEncoded <= 1)
3201             {
3202                 SetLastError(CRYPT_E_ASN1_EOD);
3203                 ret = FALSE;
3204             }
3205             else if (pbEncoded[1] > 0x7f)
3206             {
3207                 /* long-form date strings really can't be valid */
3208                 SetLastError(CRYPT_E_ASN1_CORRUPT);
3209                 ret = FALSE;
3210             }
3211             else
3212             {
3213                 BYTE len = pbEncoded[1];
3214
3215                 if (len < MIN_ENCODED_TIME_LENGTH)
3216                 {
3217                     SetLastError(CRYPT_E_ASN1_CORRUPT);
3218                     ret = FALSE;
3219                 }
3220                 else
3221                 {
3222                     SYSTEMTIME sysTime = { 0 };
3223
3224                     pbEncoded += 2;
3225                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
3226                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
3227                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
3228                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
3229                     if (ret && len > 0)
3230                     {
3231                         CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
3232                          sysTime.wMinute);
3233                         if (ret && len > 0)
3234                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
3235                              sysTime.wSecond);
3236                         if (ret && len > 0 && (*pbEncoded == '.' ||
3237                          *pbEncoded == ','))
3238                         {
3239                             BYTE digits;
3240
3241                             pbEncoded++;
3242                             len--;
3243                             /* workaround macro weirdness */
3244                             digits = min(len, 3);
3245                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
3246                              sysTime.wMilliseconds);
3247                         }
3248                         if (ret)
3249                             ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
3250                              &sysTime);
3251                     }
3252                     if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
3253                      pDecodePara, pvStructInfo, pcbStructInfo,
3254                      sizeof(FILETIME))))
3255                     {
3256                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3257                             pvStructInfo = *(BYTE **)pvStructInfo;
3258                         ret = SystemTimeToFileTime(&sysTime,
3259                          (FILETIME *)pvStructInfo);
3260                     }
3261                 }
3262             }
3263         }
3264         else
3265         {
3266             SetLastError(CRYPT_E_ASN1_BADTAG);
3267             ret = FALSE;
3268         }
3269     }
3270     __EXCEPT(page_fault)
3271     {
3272         SetLastError(STATUS_ACCESS_VIOLATION);
3273         ret = FALSE;
3274     }
3275     __ENDTRY
3276     return ret;
3277 }
3278
3279 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
3280  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3281  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3282 {
3283     BOOL ret;
3284
3285     if (!pvStructInfo)
3286     {
3287         *pcbStructInfo = sizeof(FILETIME);
3288         return TRUE;
3289     }
3290
3291     __TRY
3292     {
3293         if (pbEncoded[0] == ASN_UTCTIME)
3294             ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
3295              pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
3296              pcbStructInfo);
3297         else if (pbEncoded[0] == ASN_GENERALTIME)
3298             ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
3299              lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
3300              pvStructInfo, pcbStructInfo);
3301         else
3302         {
3303             SetLastError(CRYPT_E_ASN1_BADTAG);
3304             ret = FALSE;
3305         }
3306     }
3307     __EXCEPT(page_fault)
3308     {
3309         SetLastError(STATUS_ACCESS_VIOLATION);
3310         ret = FALSE;
3311     }
3312     __ENDTRY
3313     return ret;
3314 }
3315
3316 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
3317  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3318  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3319 {
3320     BOOL ret = TRUE;
3321
3322     __TRY
3323     {
3324         if (pbEncoded[0] == ASN_SEQUENCEOF)
3325         {
3326             DWORD bytesNeeded, dataLen, remainingLen, cValue;
3327
3328             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3329             {
3330                 BYTE lenBytes;
3331                 const BYTE *ptr;
3332
3333                 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3334                 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
3335                 cValue = 0;
3336                 ptr = pbEncoded + 1 + lenBytes;
3337                 remainingLen = dataLen;
3338                 while (ret && remainingLen)
3339                 {
3340                     DWORD nextLen;
3341
3342                     ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
3343                     if (ret)
3344                     {
3345                         DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
3346
3347                         remainingLen -= 1 + nextLenBytes + nextLen;
3348                         ptr += 1 + nextLenBytes + nextLen;
3349                         bytesNeeded += sizeof(CRYPT_DER_BLOB);
3350                         if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3351                             bytesNeeded += 1 + nextLenBytes + nextLen;
3352                         cValue++;
3353                     }
3354                 }
3355                 if (ret)
3356                 {
3357                     CRYPT_SEQUENCE_OF_ANY *seq;
3358                     BYTE *nextPtr;
3359                     DWORD i;
3360
3361                     if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3362                      pvStructInfo, pcbStructInfo, bytesNeeded)))
3363                     {
3364                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3365                             pvStructInfo = *(BYTE **)pvStructInfo;
3366                         seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
3367                         seq->cValue = cValue;
3368                         seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
3369                          sizeof(*seq));
3370                         nextPtr = (BYTE *)seq->rgValue +
3371                          cValue * sizeof(CRYPT_DER_BLOB);
3372                         ptr = pbEncoded + 1 + lenBytes;
3373                         remainingLen = dataLen;
3374                         i = 0;
3375                         while (ret && remainingLen)
3376                         {
3377                             DWORD nextLen;
3378
3379                             ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
3380                             if (ret)
3381                             {
3382                                 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
3383
3384                                 seq->rgValue[i].cbData = 1 + nextLenBytes +
3385                                  nextLen;
3386                                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3387                                     seq->rgValue[i].pbData = (BYTE *)ptr;
3388                                 else
3389                                 {
3390                                     seq->rgValue[i].pbData = nextPtr;
3391                                     memcpy(nextPtr, ptr, 1 + nextLenBytes +
3392                                      nextLen);
3393                                     nextPtr += 1 + nextLenBytes + nextLen;
3394                                 }
3395                                 remainingLen -= 1 + nextLenBytes + nextLen;
3396                                 ptr += 1 + nextLenBytes + nextLen;
3397                                 i++;
3398                             }
3399                         }
3400                     }
3401                 }
3402             }
3403         }
3404         else
3405         {
3406             SetLastError(CRYPT_E_ASN1_BADTAG);
3407             return FALSE;
3408         }
3409     }
3410     __EXCEPT(page_fault)
3411     {
3412         SetLastError(STATUS_ACCESS_VIOLATION);
3413         ret = FALSE;
3414     }
3415     __ENDTRY
3416     return ret;
3417 }
3418
3419 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
3420  DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
3421
3422 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
3423  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3424  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3425 {
3426     BOOL ret = FALSE;
3427     HMODULE lib = NULL;
3428     CryptDecodeObjectExFunc decodeFunc = NULL;
3429
3430     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
3431      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
3432      "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
3433      pvStructInfo, pcbStructInfo);
3434
3435     if (!pvStructInfo && !pcbStructInfo)
3436     {
3437         SetLastError(ERROR_INVALID_PARAMETER);
3438         return FALSE;
3439     }
3440     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
3441      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
3442     {
3443         SetLastError(ERROR_FILE_NOT_FOUND);
3444         return FALSE;
3445     }
3446     if (!pbEncoded || !cbEncoded)
3447     {
3448         SetLastError(CRYPT_E_ASN1_EOD);
3449         return FALSE;
3450     }
3451     if (cbEncoded > MAX_ENCODED_LEN)
3452     {
3453         SetLastError(CRYPT_E_ASN1_LARGE);
3454         return FALSE;
3455     }
3456
3457     SetLastError(NOERROR);
3458     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
3459         *(BYTE **)pvStructInfo = NULL;
3460     if (!HIWORD(lpszStructType))
3461     {
3462         switch (LOWORD(lpszStructType))
3463         {
3464         case (WORD)X509_EXTENSIONS:
3465             decodeFunc = CRYPT_AsnDecodeExtensions;
3466             break;
3467         case (WORD)X509_NAME:
3468             decodeFunc = CRYPT_AsnDecodeName;
3469             break;
3470         case (WORD)X509_BASIC_CONSTRAINTS2:
3471             decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
3472             break;
3473         case (WORD)X509_OCTET_STRING:
3474             decodeFunc = CRYPT_AsnDecodeOctets;
3475             break;
3476         case (WORD)X509_BITS:
3477         case (WORD)X509_KEY_USAGE:
3478             decodeFunc = CRYPT_AsnDecodeBits;
3479             break;
3480         case (WORD)X509_INTEGER:
3481             decodeFunc = CRYPT_AsnDecodeInt;
3482             break;
3483         case (WORD)X509_MULTI_BYTE_INTEGER:
3484             decodeFunc = CRYPT_AsnDecodeInteger;
3485             break;
3486         case (WORD)X509_MULTI_BYTE_UINT:
3487             decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
3488             break;
3489         case (WORD)X509_ENUMERATED:
3490             decodeFunc = CRYPT_AsnDecodeEnumerated;
3491             break;
3492         case (WORD)X509_CHOICE_OF_TIME:
3493             decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
3494             break;
3495         case (WORD)X509_SEQUENCE_OF_ANY:
3496             decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
3497             break;
3498         case (WORD)PKCS_UTC_TIME:
3499             decodeFunc = CRYPT_AsnDecodeUtcTime;
3500             break;
3501         default:
3502             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
3503         }
3504     }
3505     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
3506         decodeFunc = CRYPT_AsnDecodeExtensions;
3507     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
3508         decodeFunc = CRYPT_AsnDecodeUtcTime;
3509     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
3510         decodeFunc = CRYPT_AsnDecodeEnumerated;
3511     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
3512         decodeFunc = CRYPT_AsnDecodeBits;
3513     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
3514         decodeFunc = CRYPT_AsnDecodeOctets;
3515     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
3516         decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
3517     else
3518         TRACE("OID %s not found or unimplemented, looking for DLL\n",
3519          debugstr_a(lpszStructType));
3520     if (!decodeFunc)
3521         decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
3522          lpszStructType, "CryptDecodeObjectEx", &lib);
3523     if (decodeFunc)
3524         ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
3525          cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
3526     else
3527         SetLastError(ERROR_FILE_NOT_FOUND);
3528     if (lib)
3529         FreeLibrary(lib);
3530     return ret;
3531 }