Make tabs work in msi dialogs.
[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 "wincrypt.h"
40 #include "winreg.h"
41 #include "snmp.h"
42 #include "wine/debug.h"
43
44 /* a few asn.1 tags we need */
45 #define ASN_BITSTRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
46 #define ASN_OCTETSTRING     (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x04)
47 #define ASN_ENUMERATED      (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
48 #define ASN_SETOF           (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
49 #define ASN_NUMERICSTRING   (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
50 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
51 #define ASN_IA5STRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
52 #define ASN_UTCTIME         (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
53 #define ASN_GENERALTIME     (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
54
55 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
56
57 static const WCHAR szDllName[] = { 'D','l','l',0 };
58
59 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
60  LPCSTR pszOID)
61 {
62     static const char szEncodingTypeFmt[] =
63      "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
64     UINT len;
65     char numericOID[7]; /* enough for "#65535" */
66     const char *oid;
67     LPSTR szKey;
68
69     /* MSDN says the encoding type is a mask, but it isn't treated that way.
70      * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
71      * "EncodingType 2" would be expected if it were a mask.  Instead native
72      * stores values in "EncodingType 3".
73      */
74     if (!HIWORD(pszOID))
75     {
76         snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
77         oid = numericOID;
78     }
79     else
80         oid = pszOID;
81
82     /* This is enough: the lengths of the two string parameters are explicitly
83      * counted, and we need up to five additional characters for the encoding
84      * type.  These are covered by the "%d", "%s", and "%s" characters in the
85      * format specifier that are removed by sprintf.
86      */
87     len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
88     szKey = HeapAlloc(GetProcessHeap(), 0, len);
89     if (szKey)
90         sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
91     return szKey;
92 }
93
94 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
95                   LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
96 {
97     LONG r;
98     HKEY hKey;
99     LPSTR szKey;
100
101     TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
102           debugstr_w(pwszDll), pszOverrideFuncName);
103
104     /* This only registers functions for encoding certs, not messages */
105     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
106         return TRUE;
107
108     /* Native does nothing pwszDll is NULL */
109     if (!pwszDll)
110         return TRUE;
111
112     /* I'm not matching MS bug for bug here, because I doubt any app depends on
113      * it:
114      * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
115      *   it creates would never be used
116      * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
117      * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
118      */
119     if (!pszFuncName || !pszOID)
120     {
121         SetLastError(ERROR_INVALID_PARAMETER);
122         return FALSE;
123     }
124
125     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
126     TRACE("Key name is %s\n", debugstr_a(szKey));
127
128     if (!szKey)
129         return FALSE;
130
131     r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
132     HeapFree(GetProcessHeap(), 0, szKey);
133     if(r != ERROR_SUCCESS)
134         return FALSE;
135
136     /* write the values */
137     if (pszOverrideFuncName)
138         RegSetValueExA(hKey, "FuncName", 0, REG_SZ, pszOverrideFuncName,
139          lstrlenA(pszOverrideFuncName) + 1);
140     RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
141                     (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
142
143     RegCloseKey(hKey);
144     return TRUE;
145 }
146
147 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
148  LPCSTR pszOID)
149 {
150     LPSTR szKey;
151     LONG rc;
152
153     TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
154
155     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
156         return TRUE;
157
158     if (!pszFuncName || !pszOID)
159     {
160         SetLastError(ERROR_INVALID_PARAMETER);
161         return FALSE;
162     }
163
164     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
165     rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
166     HeapFree(GetProcessHeap(), 0, szKey);
167     if (rc)
168         SetLastError(rc);
169     return rc ? FALSE : TRUE;
170 }
171
172 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
173  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
174  DWORD *pcbValueData)
175 {
176     LPSTR szKey;
177     LONG rc;
178     HKEY hKey;
179
180     TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
181      debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
182      pcbValueData);
183
184     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
185         return TRUE;
186
187     if (!pszFuncName || !pszOID || !pwszValueName)
188     {
189         SetLastError(ERROR_INVALID_PARAMETER);
190         return FALSE;
191     }
192
193     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
194     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
195     HeapFree(GetProcessHeap(), 0, szKey);
196     if (rc)
197         SetLastError(rc);
198     else
199     {
200         rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
201          pbValueData, pcbValueData);
202         if (rc)
203             SetLastError(rc);
204         RegCloseKey(hKey);
205     }
206     return rc ? FALSE : TRUE;
207 }
208
209 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
210  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
211  const BYTE *pbValueData, DWORD cbValueData)
212 {
213     LPSTR szKey;
214     LONG rc;
215     HKEY hKey;
216
217     TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
218      debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
219      cbValueData);
220
221     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
222         return TRUE;
223
224     if (!pszFuncName || !pszOID || !pwszValueName)
225     {
226         SetLastError(ERROR_INVALID_PARAMETER);
227         return FALSE;
228     }
229
230     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
231     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
232     HeapFree(GetProcessHeap(), 0, szKey);
233     if (rc)
234         SetLastError(rc);
235     else
236     {
237         rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
238          cbValueData);
239         if (rc)
240             SetLastError(rc);
241         RegCloseKey(hKey);
242     }
243     return rc ? FALSE : TRUE;
244 }
245
246 /* Gets the registered function named szFuncName for dwCertEncodingType and
247  * lpszStructType, or NULL if one could not be found.  *lib will be set to the
248  * handle of the module it's in, or NULL if no module was loaded.  If the
249  * return value is NULL, *lib will also be NULL, to simplify error handling.
250  */
251 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
252  LPCSTR szFuncName, HMODULE *lib)
253 {
254     void *ret = NULL;
255     char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
256      lpszStructType);
257     const char *funcName;
258     long r;
259     HKEY hKey;
260     DWORD type, size = 0;
261
262     TRACE("(%08lx %s %s %p)\n", dwCertEncodingType, debugstr_a(lpszStructType),
263      debugstr_a(szFuncName), lib);
264
265     *lib = NULL;
266     r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
267     HeapFree(GetProcessHeap(), 0, szKey);
268     if(r != ERROR_SUCCESS)
269         return NULL;
270
271     RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
272     if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
273     {
274         funcName = HeapAlloc(GetProcessHeap(), 0, size);
275         RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
276          &size);
277     }
278     else
279         funcName = szFuncName;
280     RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
281     if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
282     {
283         LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
284
285         RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
286          &size);
287         *lib = LoadLibraryW(dllName);
288         if (*lib)
289         {
290              ret = GetProcAddress(*lib, funcName);
291              if (!ret)
292              {
293                  /* Unload the library, the caller doesn't want to unload it
294                   * when the return value is NULL.
295                   */
296                  FreeLibrary(*lib);
297                  *lib = NULL;
298              }
299         }
300         HeapFree(GetProcessHeap(), 0, dllName);
301     }
302     if (funcName != szFuncName)
303         HeapFree(GetProcessHeap(), 0, (char *)funcName);
304     TRACE("returning %p\n", ret);
305     return ret;
306 }
307
308 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
309  BYTE *, DWORD *);
310
311 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
312  const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
313 {
314     BOOL ret = FALSE;
315     HMODULE lib;
316     CryptEncodeObjectFunc pCryptEncodeObject;
317
318     TRACE("(0x%08lx, %s, %p, %p, %p)\n",
319      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
320      "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
321
322     if (!pbEncoded && !pcbEncoded)
323     {
324         SetLastError(ERROR_INVALID_PARAMETER);
325         return FALSE;
326     }
327
328     /* Try registered DLL first.. */
329     pCryptEncodeObject =
330      (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
331      lpszStructType, "CryptEncodeObject", &lib);
332     if (pCryptEncodeObject)
333     {
334         ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
335          pvStructInfo, pbEncoded, pcbEncoded);
336         FreeLibrary(lib);
337     }
338     else
339     {
340         /* If not, use CryptEncodeObjectEx */
341         ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
342          pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
343     }
344     return ret;
345 }
346
347 /* Helper function to check *pcbEncoded, set it to the required size, and
348  * optionally to allocate memory.  Assumes pbEncoded is not NULL.
349  * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
350  * pointer to the newly allocated memory.
351  */
352 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
353  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
354  DWORD bytesNeeded)
355 {
356     BOOL ret = TRUE;
357
358     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
359     {
360         if (pEncodePara && pEncodePara->pfnAlloc)
361             *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
362         else
363             *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
364         if (!*(BYTE **)pbEncoded)
365             ret = FALSE;
366         else
367             *pcbEncoded = bytesNeeded;
368     }
369     else if (bytesNeeded > *pcbEncoded)
370     {
371         *pcbEncoded = bytesNeeded;
372         SetLastError(ERROR_MORE_DATA);
373         ret = FALSE;
374     }
375     return ret;
376 }
377
378 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
379 {
380     DWORD bytesNeeded, significantBytes = 0;
381
382     if (len <= 0x7f)
383         bytesNeeded = 1;
384     else
385     {
386         DWORD temp;
387
388         for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
389          temp <<= 8, significantBytes--)
390             ;
391         bytesNeeded = significantBytes + 1;
392     }
393     if (!pbEncoded)
394     {
395         *pcbEncoded = bytesNeeded;
396         return TRUE;
397     }
398     if (*pcbEncoded < bytesNeeded)
399     {
400         SetLastError(ERROR_MORE_DATA);
401         return FALSE;
402     }
403     if (len <= 0x7f)
404         *pbEncoded = (BYTE)len;
405     else
406     {
407         DWORD i;
408
409         *pbEncoded++ = significantBytes | 0x80;
410         for (i = 0; i < significantBytes; i++)
411         {
412             *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
413             len >>= 8;
414         }
415     }
416     *pcbEncoded = bytesNeeded;
417     return TRUE;
418 }
419
420 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
421  LPCSTR pszObjId, BYTE *pbEncoded, DWORD *pcbEncoded)
422 {
423     DWORD bytesNeeded = 0, lenBytes;
424     BOOL ret = TRUE;
425     int firstPos = 0;
426     BYTE firstByte = 0;
427
428     if (pszObjId)
429     {
430         const char *ptr;
431         int val1, val2;
432
433         if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
434         {
435             SetLastError(CRYPT_E_ASN1_ERROR);
436             return FALSE;
437         }
438         bytesNeeded++;
439         firstByte = val1 * 40 + val2;
440         ptr = pszObjId + firstPos;
441         while (ret && *ptr)
442         {
443             int pos;
444
445             /* note I assume each component is at most 32-bits long in base 2 */
446             if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
447             {
448                 if (val1 >= 0x10000000)
449                     bytesNeeded += 5;
450                 else if (val1 >= 0x200000)
451                     bytesNeeded += 4;
452                 else if (val1 >= 0x4000)
453                     bytesNeeded += 3;
454                 else if (val1 >= 0x80)
455                     bytesNeeded += 2;
456                 else
457                     bytesNeeded += 1;
458                 ptr += pos;
459                 if (*ptr == '.')
460                     ptr++;
461             }
462             else
463             {
464                 SetLastError(CRYPT_E_ASN1_ERROR);
465                 return FALSE;
466             }
467         }
468         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
469     }
470     else
471         lenBytes = 1;
472     bytesNeeded += 1 + lenBytes;
473     if (pbEncoded)
474     {
475         if (*pbEncoded < bytesNeeded)
476         {
477             SetLastError(ERROR_MORE_DATA);
478             ret = FALSE;
479         }
480         else
481         {
482             *pbEncoded++ = ASN_OBJECTIDENTIFIER;
483             CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
484             pbEncoded += lenBytes;
485             if (pszObjId)
486             {
487                 const char *ptr;
488                 int val, pos;
489
490                 *pbEncoded++ = firstByte;
491                 ptr = pszObjId + firstPos;
492                 while (ret && *ptr)
493                 {
494                     sscanf(ptr, "%d%n", &val, &pos);
495                     {
496                         unsigned char outBytes[5];
497                         int numBytes, i;
498
499                         if (val >= 0x10000000)
500                             numBytes = 5;
501                         else if (val >= 0x200000)
502                             numBytes = 4;
503                         else if (val >= 0x4000)
504                             numBytes = 3;
505                         else if (val >= 0x80)
506                             numBytes = 2;
507                         else
508                             numBytes = 1;
509                         for (i = numBytes; i > 0; i--)
510                         {
511                             outBytes[i - 1] = val & 0x7f;
512                             val >>= 7;
513                         }
514                         for (i = 0; i < numBytes - 1; i++)
515                             *pbEncoded++ = outBytes[i] | 0x80;
516                         *pbEncoded++ = outBytes[i];
517                         ptr += pos;
518                         if (*ptr == '.')
519                             ptr++;
520                     }
521                 }
522             }
523         }
524     }
525     *pcbEncoded = bytesNeeded;
526     return ret;
527 }
528
529 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
530  CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
531 {
532     BYTE tag;
533     DWORD bytesNeeded, lenBytes, encodedLen;
534     BOOL ret = TRUE;
535
536     switch (value->dwValueType)
537     {
538     case CERT_RDN_NUMERIC_STRING:
539         tag = ASN_NUMERICSTRING;
540         encodedLen = value->Value.cbData;
541         break;
542     case CERT_RDN_PRINTABLE_STRING:
543         tag = ASN_PRINTABLESTRING;
544         encodedLen = value->Value.cbData;
545         break;
546     case CERT_RDN_IA5_STRING:
547         tag = ASN_IA5STRING;
548         encodedLen = value->Value.cbData;
549         break;
550     case CERT_RDN_ANY_TYPE:
551         /* explicitly disallowed */
552         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
553         return FALSE;
554     default:
555         FIXME("String type %ld unimplemented\n", value->dwValueType);
556         return FALSE;
557     }
558     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
559     bytesNeeded = 1 + lenBytes + encodedLen;
560     if (pbEncoded)
561     {
562         if (*pcbEncoded < bytesNeeded)
563         {
564             SetLastError(ERROR_MORE_DATA);
565             ret = FALSE;
566         }
567         else
568         {
569             *pbEncoded++ = tag;
570             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
571             pbEncoded += lenBytes;
572             switch (value->dwValueType)
573             {
574             case CERT_RDN_NUMERIC_STRING:
575             case CERT_RDN_PRINTABLE_STRING:
576             case CERT_RDN_IA5_STRING:
577                 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
578             }
579         }
580     }
581     *pcbEncoded = bytesNeeded;
582     return ret;
583 }
584
585 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
586  CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
587 {
588     DWORD bytesNeeded = 0, lenBytes, size;
589     BOOL ret;
590
591     ret = CRYPT_AsnEncodeOid(dwCertEncodingType, attr->pszObjId, NULL, &size);
592     if (ret)
593     {
594         bytesNeeded += size;
595         /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
596          * with dwValueType, so "cast" it to get its encoded size
597          */
598         ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
599          (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
600         if (ret)
601         {
602             bytesNeeded += size;
603             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
604             bytesNeeded += 1 + lenBytes;
605             if (pbEncoded)
606             {
607                 if (*pcbEncoded < bytesNeeded)
608                 {
609                     SetLastError(ERROR_MORE_DATA);
610                     ret = FALSE;
611                 }
612                 else
613                 {
614                     *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
615                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
616                      &lenBytes);
617                     pbEncoded += lenBytes;
618                     size = bytesNeeded - 1 - lenBytes;
619                     ret = CRYPT_AsnEncodeOid(dwCertEncodingType, attr->pszObjId,
620                      pbEncoded, &size);
621                     if (ret)
622                     {
623                         pbEncoded += size;
624                         size = bytesNeeded - 1 - lenBytes - size;
625                         ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
626                          (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
627                          &size);
628                     }
629                 }
630             }
631             *pcbEncoded = bytesNeeded;
632         }
633     }
634     return ret;
635 }
636
637 static int BLOBComp(const void *l, const void *r)
638 {
639     CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
640     int ret;
641
642     if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
643         ret = a->cbData - b->cbData;
644     return ret;
645 }
646
647 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
648  */
649 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
650  BYTE *pbEncoded, DWORD *pcbEncoded)
651 {
652     DWORD bytesNeeded = 0, lenBytes, i;
653     BOOL ret;
654     CRYPT_DER_BLOB *blobs = NULL;
655    
656     ret = TRUE;
657     if (rdn->cRDNAttr)
658     {
659         if (!rdn->rgRDNAttr)
660         {
661             SetLastError(STATUS_ACCESS_VIOLATION);
662             ret = FALSE;
663         }
664         else
665         {
666             blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
667              rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
668             if (!blobs)
669                 ret = FALSE;
670         }
671     }
672     for (i = 0; ret && i < rdn->cRDNAttr; i++)
673     {
674         ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
675          NULL, &blobs[i].cbData);
676         if (ret)
677             bytesNeeded += blobs[i].cbData;
678     }
679     CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
680     bytesNeeded += 1 + lenBytes;
681     if (ret)
682     {
683         if (pbEncoded)
684         {
685             if (*pcbEncoded < bytesNeeded)
686             {
687                 SetLastError(ERROR_MORE_DATA);
688                 ret = FALSE;
689             }
690             else
691             {
692                 for (i = 0; ret && i < rdn->cRDNAttr; i++)
693                 {
694                     blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
695                      blobs[i].cbData);
696                     if (!blobs[i].pbData)
697                         ret = FALSE;
698                     else
699                         ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
700                          &rdn->rgRDNAttr[i], blobs[i].pbData, &blobs[i].cbData);
701                 }
702                 if (ret)
703                 {
704                     qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
705                      BLOBComp);
706                     *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
707                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
708                      &lenBytes);
709                     pbEncoded += lenBytes;
710                     for (i = 0; ret && i < rdn->cRDNAttr; i++)
711                     {
712                         memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
713                         pbEncoded += blobs[i].cbData;
714                     }
715                 }
716             }
717         }
718         *pcbEncoded = bytesNeeded;
719     }
720     if (blobs)
721     {
722         for (i = 0; i < rdn->cRDNAttr; i++)
723             HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
724         HeapFree(GetProcessHeap(), 0, blobs);
725     }
726     return ret;
727 }
728
729 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
730  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
731  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
732 {
733     CERT_NAME_INFO *info = (CERT_NAME_INFO *)pvStructInfo;
734     DWORD bytesNeeded = 0, lenBytes, size, i;
735     BOOL ret;
736
737     if (!pvStructInfo)
738     {
739         SetLastError(STATUS_ACCESS_VIOLATION);
740         return FALSE;
741     }
742     if (info->cRDN && !info->rgRDN)
743     {
744         SetLastError(STATUS_ACCESS_VIOLATION);
745         return FALSE;
746     }
747     TRACE("encoding name with %ld RDNs\n", info->cRDN);
748     ret = TRUE;
749     for (i = 0; ret && i < info->cRDN; i++)
750     {
751         ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
752          &size);
753         if (ret)
754             bytesNeeded += size;
755     }
756     CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
757     bytesNeeded += 1 + lenBytes;
758     if (ret)
759     {
760         if (!pbEncoded)
761         {
762             *pcbEncoded = bytesNeeded;
763             return TRUE;
764         }
765         if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
766          pcbEncoded, bytesNeeded))
767             return FALSE;
768         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
769             pbEncoded = *(BYTE **)pbEncoded;
770         /* FIXME: could this be encoded using X509_SEQUENCE_OF_ANY? */
771         *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCEOF;
772         CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, &size);
773         pbEncoded += size;
774         for (i = 0; ret && i < info->cRDN; i++)
775         {
776             size = bytesNeeded;
777             ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
778              pbEncoded, &size);
779             if (ret)
780             {
781                 pbEncoded += size;
782                 bytesNeeded -= size;
783             }
784         }
785     }
786     return ret;
787 }
788
789 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
790  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
791  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
792 {
793     CRYPT_DATA_BLOB *blob = (CRYPT_DATA_BLOB *)pvStructInfo;
794     DWORD bytesNeeded, lenBytes;
795
796     if (!pvStructInfo)
797     {
798         SetLastError(STATUS_ACCESS_VIOLATION);
799         return FALSE;
800     }
801     /* FIXME: use exception handling to catch bogus pointers */
802     CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
803     bytesNeeded = 1 + lenBytes + blob->cbData;
804     if (!pbEncoded)
805     {
806         *pcbEncoded = bytesNeeded;
807         return TRUE;
808     }
809     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
810      bytesNeeded))
811         return FALSE;
812     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
813         pbEncoded = *(BYTE **)pbEncoded;
814     *pbEncoded++ = ASN_OCTETSTRING;
815     CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
816     pbEncoded += lenBytes;
817     if (blob->cbData)
818         memcpy(pbEncoded, blob->pbData, blob->cbData);
819     return TRUE;
820 }
821
822 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
823  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
824  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
825 {
826     CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
827     DWORD bytesNeeded, lenBytes, dataBytes;
828     BYTE unusedBits;
829
830     if (!pvStructInfo)
831     {
832         SetLastError(STATUS_ACCESS_VIOLATION);
833         return FALSE;
834     }
835     /* FIXME: use exception handling to catch bogus pointers */
836     /* yep, MS allows cUnusedBits to be >= 8 */
837     if (blob->cbData * 8 > blob->cUnusedBits)
838     {
839         dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
840         unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
841          blob->cUnusedBits;
842     }
843     else
844     {
845         dataBytes = 0;
846         unusedBits = 0;
847     }
848     CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
849     bytesNeeded = 1 + lenBytes + dataBytes + 1;
850     if (!pbEncoded)
851     {
852         *pcbEncoded = bytesNeeded;
853         return TRUE;
854     }
855     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
856      bytesNeeded))
857         return FALSE;
858     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
859         pbEncoded = *(BYTE **)pbEncoded;
860     *pbEncoded++ = ASN_BITSTRING;
861     CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
862     pbEncoded += lenBytes;
863     *pbEncoded++ = unusedBits;
864     if (dataBytes)
865     {
866         BYTE mask = 0xff << unusedBits;
867
868         if (dataBytes > 1)
869         {
870             memcpy(pbEncoded, blob->pbData, dataBytes - 1);
871             pbEncoded += dataBytes - 1;
872         }
873         *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
874     }
875     return TRUE;
876 }
877
878 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
879  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
880  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
881 {
882     INT val, i;
883     BYTE significantBytes, padByte = 0, bytesNeeded;
884     BOOL neg = FALSE, pad = FALSE;
885
886     if (!pvStructInfo)
887     {
888         SetLastError(STATUS_ACCESS_VIOLATION);
889         return FALSE;
890     }
891
892     memcpy(&val, pvStructInfo, sizeof(val));
893     /* Count the number of significant bytes.  Temporarily swap sign for
894      * negatives so I count the minimum number of bytes.
895      */
896     if (val < 0)
897     {
898         neg = TRUE;
899         val = -val;
900     }
901     for (significantBytes = sizeof(val); !(val & 0xff000000);
902      val <<= 8, significantBytes--)
903         ;
904     if (neg)
905     {
906         val = -val;
907         if ((val & 0xff000000) < 0x80000000)
908         {
909             padByte = 0xff;
910             pad = TRUE;
911         }
912     }
913     else if ((val & 0xff000000) > 0x7f000000)
914     {
915         padByte = 0;
916         pad = TRUE;
917     }
918     bytesNeeded = 2 + significantBytes;
919     if (pad)
920         bytesNeeded++;
921     if (!pbEncoded)
922     {
923         *pcbEncoded = bytesNeeded;
924         return TRUE;
925     }
926     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
927      bytesNeeded))
928         return FALSE;
929     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
930         pbEncoded = *(BYTE **)pbEncoded;
931     *pbEncoded++ = ASN_INTEGER;
932     if (pad)
933     {
934         *pbEncoded++ = significantBytes + 1;
935         *pbEncoded++ = padByte;
936     }
937     else
938         *pbEncoded++ = significantBytes;
939     for (i = 0; i < significantBytes; i++, val <<= 8)
940         *(pbEncoded + i) = (BYTE)((val & 0xff000000) >> 24);
941     return TRUE;
942 }
943
944 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
945  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
946  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
947 {
948     DWORD significantBytes, lenBytes;
949     BYTE padByte = 0, bytesNeeded;
950     BOOL pad = FALSE;
951     CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
952
953     if (!pvStructInfo)
954     {
955         SetLastError(STATUS_ACCESS_VIOLATION);
956         return FALSE;
957     }
958
959     /* FIXME: use exception handling to protect against bogus pointers */
960     significantBytes = blob->cbData;
961     if (significantBytes)
962     {
963         if (blob->pbData[significantBytes - 1] & 0x80)
964         {
965             /* negative, lop off leading (little-endian) 0xffs */
966             for (; significantBytes > 0 &&
967              blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
968                 ;
969             if (blob->pbData[significantBytes - 1] < 0x80)
970             {
971                 padByte = 0xff;
972                 pad = TRUE;
973             }
974         }
975         else
976         {
977             /* positive, lop off leading (little-endian) zeroes */
978             for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
979              significantBytes--)
980                 ;
981             if (blob->pbData[significantBytes - 1] > 0x7f)
982             {
983                 padByte = 0;
984                 pad = TRUE;
985             }
986         }
987     }
988     if (pad)
989         CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
990     else
991         CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
992     bytesNeeded = 1 + lenBytes + significantBytes;
993     if (pad)
994         bytesNeeded++;
995     if (!pbEncoded)
996     {
997         *pcbEncoded = bytesNeeded;
998         return TRUE;
999     }
1000     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
1001      bytesNeeded))
1002         return FALSE;
1003     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1004         pbEncoded = *(BYTE **)pbEncoded;
1005     *pbEncoded++ = ASN_INTEGER;
1006     if (pad)
1007     {
1008         CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1009         pbEncoded += lenBytes;
1010         *pbEncoded++ = padByte;
1011     }
1012     else
1013     {
1014         CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1015         pbEncoded += lenBytes;
1016     }
1017     for (; significantBytes > 0; significantBytes--)
1018         *(pbEncoded++) = blob->pbData[significantBytes - 1];
1019     return TRUE;
1020 }
1021
1022 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1023  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1024  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1025 {
1026     DWORD significantBytes, lenBytes;
1027     BYTE bytesNeeded;
1028     BOOL pad = FALSE;
1029     CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
1030
1031     if (!pvStructInfo)
1032     {
1033         SetLastError(STATUS_ACCESS_VIOLATION);
1034         return FALSE;
1035     }
1036
1037     /* FIXME: use exception handling to protect against bogus pointers */
1038     significantBytes = blob->cbData;
1039     if (significantBytes)
1040     {
1041         /* positive, lop off leading (little-endian) zeroes */
1042         for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1043          significantBytes--)
1044             ;
1045         if (blob->pbData[significantBytes - 1] > 0x7f)
1046             pad = TRUE;
1047     }
1048     if (pad)
1049         CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1050     else
1051         CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1052     bytesNeeded = 1 + lenBytes + significantBytes;
1053     if (pad)
1054         bytesNeeded++;
1055     if (!pbEncoded)
1056     {
1057         *pcbEncoded = bytesNeeded;
1058         return TRUE;
1059     }
1060     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
1061      bytesNeeded))
1062         return FALSE;
1063     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1064         pbEncoded = *(BYTE **)pbEncoded;
1065     *pbEncoded++ = ASN_INTEGER;
1066     if (pad)
1067     {
1068         CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1069         pbEncoded += lenBytes;
1070         *pbEncoded++ = 0;
1071     }
1072     else
1073     {
1074         CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1075         pbEncoded += lenBytes;
1076     }
1077     for (; significantBytes > 0; significantBytes--)
1078         *(pbEncoded++) = blob->pbData[significantBytes - 1];
1079     return TRUE;
1080 }
1081
1082 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
1083  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1084  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1085 {
1086     CRYPT_INTEGER_BLOB blob;
1087     BOOL ret;
1088
1089     /* Encode as an unsigned integer, then change the tag to enumerated */
1090     blob.cbData = sizeof(DWORD);
1091     blob.pbData = (BYTE *)pvStructInfo;
1092     ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
1093      X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1094     if (ret && pbEncoded)
1095     {
1096         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1097             pbEncoded = *(BYTE **)pbEncoded;
1098         pbEncoded[0] = ASN_ENUMERATED;
1099     }
1100     return ret;
1101 }
1102
1103 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
1104  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1105  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1106 {
1107     SYSTEMTIME sysTime;
1108     /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
1109      * temporary buffer because the output buffer is not NULL-terminated.
1110      */
1111     char buf[16];
1112     static const DWORD bytesNeeded = sizeof(buf) - 1;
1113
1114     if (!pvStructInfo)
1115     {
1116         SetLastError(STATUS_ACCESS_VIOLATION);
1117         return FALSE;
1118     }
1119     /* Sanity check the year, this is a two-digit year format */
1120     if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1121         return FALSE;
1122     if (sysTime.wYear < 1950 || sysTime.wYear > 2050)
1123     {
1124         SetLastError(CRYPT_E_BAD_ENCODE);
1125         return FALSE;
1126     }
1127     if (!pbEncoded)
1128     {
1129         *pcbEncoded = bytesNeeded;
1130         return TRUE;
1131     }
1132     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
1133      bytesNeeded))
1134         return FALSE;
1135     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1136         pbEncoded = *(BYTE **)pbEncoded;
1137     buf[0] = ASN_UTCTIME;
1138     buf[1] = bytesNeeded - 2;
1139     snprintf(buf + 2, sizeof(buf) - 2, "%02d%02d%02d%02d%02d%02dZ",
1140      sysTime.wYear >= 2000 ? sysTime.wYear - 2000 : sysTime.wYear - 1900,
1141      sysTime.wDay, sysTime.wMonth, sysTime.wHour, sysTime.wMinute,
1142      sysTime.wSecond);
1143     memcpy(pbEncoded, buf, bytesNeeded);
1144     return TRUE;
1145 }
1146
1147 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
1148  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1149  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1150 {
1151     SYSTEMTIME sysTime;
1152     /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
1153      * temporary buffer because the output buffer is not NULL-terminated.
1154      */
1155     char buf[18];
1156     static const DWORD bytesNeeded = sizeof(buf) - 1;
1157
1158     if (!pvStructInfo)
1159     {
1160         SetLastError(STATUS_ACCESS_VIOLATION);
1161         return FALSE;
1162     }
1163     if (!pbEncoded)
1164     {
1165         *pcbEncoded = bytesNeeded;
1166         return TRUE;
1167     }
1168     if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1169         return FALSE;
1170     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
1171      bytesNeeded))
1172         return FALSE;
1173     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1174         pbEncoded = *(BYTE **)pbEncoded;
1175     buf[0] = ASN_GENERALTIME;
1176     buf[1] = bytesNeeded - 2;
1177     snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
1178      sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1179      sysTime.wMinute, sysTime.wSecond);
1180     memcpy(pbEncoded, buf, bytesNeeded);
1181     return TRUE;
1182 }
1183
1184 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
1185  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1186  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1187 {
1188     SYSTEMTIME sysTime;
1189     BOOL ret;
1190
1191     if (!pvStructInfo)
1192     {
1193         SetLastError(STATUS_ACCESS_VIOLATION);
1194         return FALSE;
1195     }
1196     /* Check the year, if it's in the UTCTime range call that encode func */
1197     if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1198         return FALSE;
1199     if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
1200         ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
1201          pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1202     else
1203         ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
1204          lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1205          pcbEncoded);
1206     return ret;
1207 }
1208
1209 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
1210  DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
1211
1212 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1213  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
1214  void *pvEncoded, DWORD *pcbEncoded)
1215 {
1216     BOOL ret = FALSE;
1217     HMODULE lib = NULL;
1218     CryptEncodeObjectExFunc encodeFunc = NULL;
1219
1220     TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n",
1221      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1222      "(integer value)", pvStructInfo, dwFlags, pEncodePara, pvEncoded,
1223      pcbEncoded);
1224
1225     if (!pvEncoded && !pcbEncoded)
1226     {
1227         SetLastError(ERROR_INVALID_PARAMETER);
1228         return FALSE;
1229     }
1230     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
1231      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
1232     {
1233         SetLastError(ERROR_FILE_NOT_FOUND);
1234         return FALSE;
1235     }
1236
1237     SetLastError(NOERROR);
1238     if (!HIWORD(lpszStructType))
1239     {
1240         switch (LOWORD(lpszStructType))
1241         {
1242         case (WORD)X509_NAME:
1243             encodeFunc = CRYPT_AsnEncodeName;
1244             break;
1245         case (WORD)X509_OCTET_STRING:
1246             encodeFunc = CRYPT_AsnEncodeOctets;
1247             break;
1248         case (WORD)X509_BITS:
1249         case (WORD)X509_KEY_USAGE:
1250             encodeFunc = CRYPT_AsnEncodeBits;
1251             break;
1252         case (WORD)X509_INTEGER:
1253             encodeFunc = CRYPT_AsnEncodeInt;
1254             break;
1255         case (WORD)X509_MULTI_BYTE_INTEGER:
1256             encodeFunc = CRYPT_AsnEncodeInteger;
1257             break;
1258         case (WORD)X509_MULTI_BYTE_UINT:
1259             encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
1260             break;
1261         case (WORD)X509_ENUMERATED:
1262             encodeFunc = CRYPT_AsnEncodeEnumerated;
1263             break;
1264         case (WORD)X509_CHOICE_OF_TIME:
1265             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
1266             break;
1267         case (WORD)PKCS_UTC_TIME:
1268             encodeFunc = CRYPT_AsnEncodeUtcTime;
1269             break;
1270         default:
1271             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1272         }
1273     }
1274     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1275         encodeFunc = CRYPT_AsnEncodeUtcTime;
1276     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
1277         encodeFunc = CRYPT_AsnEncodeEnumerated;
1278     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
1279         encodeFunc = CRYPT_AsnEncodeBits;
1280     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
1281         encodeFunc = CRYPT_AsnEncodeOctets;
1282     else
1283         TRACE("OID %s not found or unimplemented, looking for DLL\n",
1284          debugstr_a(lpszStructType));
1285     if (!encodeFunc)
1286         encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1287          lpszStructType, "CryptEncodeObjectEx", &lib);
1288     if (encodeFunc)
1289         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
1290          dwFlags, pEncodePara, pvEncoded, pcbEncoded);
1291     else
1292         SetLastError(ERROR_FILE_NOT_FOUND);
1293     if (lib)
1294         FreeLibrary(lib);
1295     return ret;
1296 }
1297
1298 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1299  DWORD, DWORD, void *, DWORD *);
1300
1301 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1302  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
1303  DWORD *pcbStructInfo)
1304 {
1305     BOOL ret = FALSE;
1306     HMODULE lib;
1307     CryptDecodeObjectFunc pCryptDecodeObject;
1308
1309     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
1310      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1311      "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1312      pcbStructInfo);
1313
1314     if (!pvStructInfo && !pcbStructInfo)
1315     {
1316         SetLastError(ERROR_INVALID_PARAMETER);
1317         return FALSE;
1318     }
1319
1320     /* Try registered DLL first.. */
1321     pCryptDecodeObject =
1322      (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
1323      lpszStructType, "CryptDecodeObject", &lib);
1324     if (pCryptDecodeObject)
1325     {
1326         ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
1327          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1328         FreeLibrary(lib);
1329     }
1330     else
1331     {
1332         /* If not, use CryptDecodeObjectEx */
1333         ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
1334          cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
1335     }
1336     return ret;
1337 }
1338
1339 /* Gets the number of length bytes from the given (leading) length byte */
1340 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
1341
1342 /* Helper function to get the encoded length of the data starting at pbEncoded,
1343  * where pbEncoded[0] is the tag.  If the data are too short to contain a
1344  * length or if the length is too large for cbEncoded, sets an appropriate
1345  * error code and returns FALSE.
1346  */
1347 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
1348  DWORD *len)
1349 {
1350     BOOL ret;
1351
1352     if (cbEncoded <= 1)
1353     {
1354         SetLastError(CRYPT_E_ASN1_EOD);
1355         ret = FALSE;
1356     }
1357     else if (pbEncoded[1] <= 0x7f)
1358     {
1359         *len = pbEncoded[1];
1360         ret = TRUE;
1361     }
1362     else
1363     {
1364         BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
1365
1366         if (lenLen > sizeof(DWORD))
1367         {
1368             SetLastError(CRYPT_E_ASN1_LARGE);
1369             ret = FALSE;
1370         }
1371         else if (lenLen + 2 > cbEncoded)
1372         {
1373             SetLastError(CRYPT_E_ASN1_CORRUPT);
1374             ret = FALSE;
1375         }
1376         else
1377         {
1378             DWORD out = 0;
1379
1380             pbEncoded += 2;
1381             while (lenLen--)
1382             {
1383                 out <<= 8;
1384                 out |= *pbEncoded++;
1385             }
1386             if (out + lenLen + 1 > cbEncoded)
1387             {
1388                 SetLastError(CRYPT_E_ASN1_EOD);
1389                 ret = FALSE;
1390             }
1391             else
1392             {
1393                 *len = out;
1394                 ret = TRUE;
1395             }
1396         }
1397     }
1398     return ret;
1399 }
1400
1401 /* Helper function to check *pcbStructInfo, set it to the required size, and
1402  * optionally to allocate memory.  Assumes pvStructInfo is not NULL.
1403  * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
1404  * pointer to the newly allocated memory.
1405  */
1406 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
1407  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
1408  DWORD bytesNeeded)
1409 {
1410     BOOL ret = TRUE;
1411
1412     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1413     {
1414         if (pDecodePara && pDecodePara->pfnAlloc)
1415             *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
1416         else
1417             *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
1418         if (!*(BYTE **)pvStructInfo)
1419             ret = FALSE;
1420         else
1421             *pcbStructInfo = bytesNeeded;
1422     }
1423     else if (*pcbStructInfo < bytesNeeded)
1424     {
1425         *pcbStructInfo = bytesNeeded;
1426         SetLastError(ERROR_MORE_DATA);
1427         ret = FALSE;
1428     }
1429     return ret;
1430 }
1431
1432 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_FLAG. */
1433 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1434  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, LPSTR pszObjId,
1435  DWORD *pcbObjId)
1436 {
1437     BOOL ret = TRUE;
1438     DWORD bytesNeeded, dataLen;
1439     BYTE lenBytes;
1440
1441     if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1442         return FALSE;
1443     if (pbEncoded[0] != ASN_OBJECTIDENTIFIER)
1444     {
1445         SetLastError(CRYPT_E_ASN1_BADTAG);
1446         return FALSE;
1447     }
1448     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1449     if (dataLen)
1450     {
1451         /* The largest possible string for the first two components is 2.175
1452          * (= 2 * 40 + 175 = 255), so this is big enough.
1453          */
1454         char firstTwo[6];
1455         const BYTE *ptr;
1456
1457         snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
1458          pbEncoded[1 + lenBytes] / 40,
1459          pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40) * 40);
1460         bytesNeeded = strlen(firstTwo) + 1;
1461         for (ptr = pbEncoded + 2 + lenBytes; ret &&
1462          ptr - pbEncoded - 1 - lenBytes < dataLen; )
1463         {
1464             /* large enough for ".4000000" */
1465             char str[9];
1466             int val = 0;
1467
1468             while (ptr - pbEncoded - 1 - lenBytes < dataLen && (*ptr & 0x80))
1469             {
1470                 val <<= 7;
1471                 val |= *ptr & 0x7f;
1472                 ptr++;
1473             }
1474             if (ptr - pbEncoded - 1 - lenBytes >= dataLen || (*ptr & 0x80))
1475             {
1476                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1477                 ret = FALSE;
1478             }
1479             else
1480             {
1481                 val <<= 7;
1482                 val |= *ptr++;
1483                 snprintf(str, sizeof(str), ".%d", val);
1484                 bytesNeeded += strlen(str);
1485             }
1486         }
1487         if (!pszObjId)
1488             *pcbObjId = bytesNeeded;
1489         else if (*pcbObjId < bytesNeeded)
1490         {
1491             *pcbObjId = bytesNeeded;
1492             SetLastError(ERROR_MORE_DATA);
1493             ret = FALSE;
1494         }
1495         else
1496         {
1497             sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
1498              pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40) * 40);
1499             pszObjId += strlen(pszObjId);
1500             for (ptr = pbEncoded + 2 + lenBytes; ret &&
1501              ptr - pbEncoded - 1 - lenBytes < dataLen; )
1502             {
1503                 int val = 0;
1504
1505                 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
1506                  (*ptr & 0x80))
1507                 {
1508                     val <<= 7;
1509                     val |= *ptr & 0x7f;
1510                     ptr++;
1511                 }
1512                 val <<= 7;
1513                 val |= *ptr++;
1514                 sprintf(pszObjId, ".%d", val);
1515                 pszObjId += strlen(pszObjId);
1516             }
1517         }
1518     }
1519     else
1520         bytesNeeded = 0;
1521     *pcbObjId = bytesNeeded;
1522     return ret;
1523 }
1524
1525 /* Warning: this assumes the address of value->Value.pbData is already set, in
1526  * order to avoid overwriting memory.  (In some cases, it may change it, if it
1527  * doesn't copy anything to memory.)  Be sure to set it correctly!
1528  */
1529 static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
1530  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value,
1531  DWORD *pcbValue)
1532 {
1533     DWORD bytesNeeded, dataLen;
1534     BOOL ret = TRUE;
1535     BYTE lenBytes;
1536
1537     if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1538         return FALSE;
1539     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1540     switch (pbEncoded[0])
1541     {
1542     case ASN_NUMERICSTRING:
1543     case ASN_PRINTABLESTRING:
1544     case ASN_IA5STRING:
1545         break;
1546     default:
1547         FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
1548         SetLastError(OSS_UNIMPLEMENTED);
1549         return FALSE;
1550     }
1551     bytesNeeded = sizeof(CERT_NAME_VALUE);
1552     if (dataLen)
1553     {
1554         switch (pbEncoded[0])
1555         {
1556         case ASN_NUMERICSTRING:
1557         case ASN_PRINTABLESTRING:
1558         case ASN_IA5STRING:
1559             if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1560                 bytesNeeded += dataLen;
1561             break;
1562         }
1563     }
1564     if (!value)
1565     {
1566         *pcbValue = bytesNeeded;
1567         return TRUE;
1568     }
1569     if (*pcbValue < bytesNeeded)
1570     {
1571         *pcbValue = bytesNeeded;
1572         SetLastError(ERROR_MORE_DATA);
1573         return FALSE;
1574     }
1575     *pcbValue = bytesNeeded;
1576     switch (pbEncoded[0])
1577     {
1578     case ASN_NUMERICSTRING:
1579         value->dwValueType = CERT_RDN_NUMERIC_STRING;
1580         break;
1581     case ASN_PRINTABLESTRING:
1582         value->dwValueType = CERT_RDN_PRINTABLE_STRING;
1583         break;
1584     case ASN_IA5STRING:
1585         value->dwValueType = CERT_RDN_IA5_STRING;
1586         break;
1587     }
1588     if (dataLen)
1589     {
1590         switch (pbEncoded[0])
1591         {
1592         case ASN_NUMERICSTRING:
1593         case ASN_PRINTABLESTRING:
1594         case ASN_IA5STRING:
1595             value->Value.cbData = dataLen;
1596             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1597                 value->Value.pbData = (BYTE *)pbEncoded + 1 + lenBytes;
1598             else
1599             {
1600                 if (!value->Value.pbData)
1601                 {
1602                     SetLastError(CRYPT_E_ASN1_INTERNAL);
1603                     ret = FALSE;
1604                 }
1605                 else
1606                     memcpy(value->Value.pbData, pbEncoded + 1 + lenBytes,
1607                      dataLen);
1608             }
1609             break;
1610         }
1611     }
1612     else
1613     {
1614         value->Value.cbData = 0;
1615         value->Value.pbData = NULL;
1616     }
1617     return ret;
1618 }
1619
1620 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
1621  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr,
1622  DWORD *pcbAttr)
1623 {
1624     BOOL ret = TRUE;
1625     DWORD bytesNeeded, dataLen, size;
1626     BYTE lenBytes;
1627
1628     if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1629         return FALSE;
1630     /* The data length must be at least 4, two for the tag and length for the
1631      * OID, and two for the string (assuming both have short-form lengths.)
1632      */
1633     if (dataLen < 4)
1634     {
1635         SetLastError(CRYPT_E_ASN1_EOD);
1636         return FALSE;
1637     }
1638     if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCE))
1639     {
1640         SetLastError(CRYPT_E_ASN1_BADTAG);
1641         return FALSE;
1642     }
1643     bytesNeeded = sizeof(CERT_RDN_ATTR);
1644     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1645     ret = CRYPT_AsnDecodeOid(dwCertEncodingType, pbEncoded + 1 + lenBytes,
1646      cbEncoded - 1 - lenBytes, dwFlags, NULL, &size);
1647     if (ret)
1648     {
1649         /* ugly: need to know the size of the next element of the sequence,
1650          * so get it directly
1651          */
1652         DWORD objIdOfset = 1 + lenBytes, objIdLen, nameValueOffset = 0;
1653
1654         ret = CRYPT_GetLen(pbEncoded + objIdOfset, cbEncoded - objIdOfset,
1655          &objIdLen);
1656         bytesNeeded += size;
1657         /* hack: like encoding, this takes advantage of the fact that the rest
1658          * of the structure is identical to a CERT_NAME_VALUE.
1659          */
1660         if (ret)
1661         {
1662             nameValueOffset = objIdOfset + objIdLen + 1 +
1663              GET_LEN_BYTES(pbEncoded[objIdOfset]);
1664             ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType,
1665              pbEncoded + nameValueOffset, cbEncoded - nameValueOffset, dwFlags,
1666              NULL, &size);
1667         }
1668         if (ret)
1669         {
1670             bytesNeeded += size;
1671             if (!attr)
1672                 *pcbAttr = bytesNeeded;
1673             else if (*pcbAttr < bytesNeeded)
1674             {
1675                 *pcbAttr = bytesNeeded;
1676                 SetLastError(ERROR_MORE_DATA);
1677                 ret = FALSE;
1678             }
1679             else
1680             {
1681                 BYTE *originalData = attr->Value.pbData;
1682
1683                 *pcbAttr = bytesNeeded;
1684                 /* strange: decode the value first, because it has a counted
1685                  * size, and we can store the OID after it.  Keep track of the
1686                  * original data pointer, we'll need to know whether it was
1687                  * changed.
1688                  */
1689                 size = bytesNeeded;
1690                 ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType,
1691                  pbEncoded + nameValueOffset, cbEncoded - nameValueOffset,
1692                  dwFlags, (CERT_NAME_VALUE *)&attr->dwValueType, &size);
1693                 if (ret)
1694                 {
1695                     if (objIdLen)
1696                     {
1697                         /* if the data were copied to the original location,
1698                          * the OID goes after.  Otherwise it goes in the
1699                          * spot originally reserved for the data.
1700                          */
1701                         if (attr->Value.pbData == originalData)
1702                             attr->pszObjId = (LPSTR)(attr->Value.pbData +
1703                              attr->Value.cbData);
1704                         else
1705                             attr->pszObjId = originalData;
1706                         size = bytesNeeded - size;
1707                         ret = CRYPT_AsnDecodeOid(dwCertEncodingType,
1708                          pbEncoded + objIdOfset, cbEncoded - objIdOfset,
1709                          dwFlags, attr->pszObjId, &size);
1710                     }
1711                     else
1712                         attr->pszObjId = NULL;
1713                 }
1714             }
1715         }
1716     }
1717     return ret;
1718 }
1719
1720 static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
1721  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN *rdn,
1722  DWORD *pcbRdn)
1723 {
1724     BOOL ret = TRUE;
1725     DWORD bytesNeeded, dataLen, cRDNAttr = 0;
1726     BYTE lenBytes;
1727
1728     if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1729         return FALSE;
1730     if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SETOF))
1731     {
1732         SetLastError(CRYPT_E_ASN1_BADTAG);
1733         return FALSE;
1734     }
1735     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1736     bytesNeeded = sizeof(CERT_RDN);
1737     if (dataLen)
1738     {
1739         const BYTE *ptr;
1740         DWORD size;
1741
1742         for (ptr = pbEncoded + 1 + lenBytes; ret &&
1743          ptr - pbEncoded - 1 - lenBytes < dataLen; )
1744         {
1745             ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1746              cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1747             if (ret)
1748             {
1749                 DWORD nextLen;
1750
1751                 cRDNAttr++;
1752                 bytesNeeded += size;
1753                 ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1754                  &nextLen);
1755                 if (ret)
1756                     ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1757             }
1758         }
1759     }
1760     if (ret)
1761     {
1762         if (!rdn)
1763         {
1764             *pcbRdn = bytesNeeded;
1765             return TRUE;
1766         }
1767         if (*pcbRdn < bytesNeeded)
1768         {
1769             *pcbRdn = bytesNeeded;
1770             SetLastError(ERROR_MORE_DATA);
1771             return FALSE;
1772         }
1773         *pcbRdn = bytesNeeded;
1774         rdn->cRDNAttr = cRDNAttr;
1775         if (rdn->cRDNAttr == 0)
1776             rdn->rgRDNAttr = NULL;
1777         else
1778         {
1779             DWORD size, i;
1780             BYTE *nextData;
1781             const BYTE *ptr;
1782
1783             rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn + sizeof(CERT_RDN));
1784             nextData = (BYTE *)rdn->rgRDNAttr +
1785              rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
1786             for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret && i < cRDNAttr &&
1787              ptr - pbEncoded - 1 - lenBytes < dataLen; i++)
1788             {
1789                 rdn->rgRDNAttr[i].Value.pbData = nextData;
1790                 size = bytesNeeded;
1791                 ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1792                  cbEncoded - (ptr - pbEncoded), dwFlags, &rdn->rgRDNAttr[i],
1793                  &size);
1794                 if (ret)
1795                 {
1796                     DWORD nextLen;
1797
1798                     bytesNeeded -= size;
1799                     /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the data may not
1800                      * have been copied.
1801                      */
1802                     if (rdn->rgRDNAttr[i].Value.pbData == nextData)
1803                         nextData += rdn->rgRDNAttr[i].Value.cbData;
1804                     /* Ugly: the OID, if copied, is stored in memory after the
1805                      * value, so increment by its string length if it's set and
1806                      * points here.
1807                      */
1808                     if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId == nextData)
1809                         nextData += strlen(rdn->rgRDNAttr[i].pszObjId) + 1;
1810                     ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1811                      &nextLen);
1812                     if (ret)
1813                         ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1814                 }
1815             }
1816         }
1817     }
1818     return ret;
1819 }
1820
1821 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
1822  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1823  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1824 {
1825     BOOL ret = TRUE;
1826     DWORD bytesNeeded, dataLen, cRDN = 0;
1827     BYTE lenBytes;
1828
1829     if (!pbEncoded)
1830     {
1831         SetLastError(CRYPT_E_ASN1_EOD);
1832         return FALSE;
1833     }
1834     if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1835         return FALSE;
1836     if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
1837     {
1838         SetLastError(CRYPT_E_ASN1_BADTAG);
1839         return FALSE;
1840     }
1841     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
1842     bytesNeeded = sizeof(CERT_NAME_INFO);
1843     if (dataLen)
1844     {
1845         const BYTE *ptr;
1846         DWORD size;
1847
1848         for (ptr = pbEncoded + 1 + lenBytes; ret && ptr - pbEncoded - 1 -
1849          lenBytes < dataLen; )
1850         {
1851             ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1852              cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1853             if (ret)
1854             {
1855                 DWORD nextLen;
1856
1857                 cRDN++;
1858                 bytesNeeded += size;
1859                 ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1860                  &nextLen);
1861                 if (ret)
1862                     ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1863             }
1864         }
1865     }
1866     if (ret)
1867     {
1868         CERT_NAME_INFO *info;
1869
1870         if (!pvStructInfo)
1871         {
1872             *pcbStructInfo = bytesNeeded;
1873             return TRUE;
1874         }
1875         if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1876          pcbStructInfo, bytesNeeded))
1877             return FALSE;
1878         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1879             pvStructInfo = *(BYTE **)pvStructInfo;
1880         info = (CERT_NAME_INFO *)pvStructInfo;
1881         info->cRDN = cRDN;
1882         if (info->cRDN == 0)
1883             info->rgRDN = NULL;
1884         else
1885         {
1886             DWORD size, i;
1887             BYTE *nextData;
1888             const BYTE *ptr;
1889
1890             info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
1891              sizeof(CERT_NAME_INFO));
1892             nextData = (BYTE *)info->rgRDN + info->cRDN * sizeof(CERT_RDN);
1893             for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret && i < cRDN &&
1894              ptr - pbEncoded - 1 - lenBytes < dataLen; i++)
1895             {
1896                 info->rgRDN[i].rgRDNAttr = (CERT_RDN_ATTR *)nextData;
1897                 size = bytesNeeded;
1898                 ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1899                  cbEncoded - (ptr - pbEncoded), dwFlags, &info->rgRDN[i],
1900                  &size);
1901                 if (ret)
1902                 {
1903                     DWORD nextLen;
1904
1905                     nextData += size;
1906                     bytesNeeded -= size;
1907                     ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
1908                      &nextLen);
1909                     if (ret)
1910                         ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
1911                 }
1912             }
1913         }
1914     }
1915     return ret;
1916 }
1917
1918 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
1919  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1920  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1921 {
1922     CRYPT_DATA_BLOB *blob;
1923     DWORD bytesNeeded, dataLen;
1924
1925     if (!pbEncoded)
1926     {
1927         SetLastError(CRYPT_E_ASN1_EOD);
1928         return FALSE;
1929     }
1930     if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1931         return FALSE;
1932     if (pbEncoded[0] != ASN_OCTETSTRING)
1933     {
1934         SetLastError(CRYPT_E_ASN1_BADTAG);
1935         return FALSE;
1936     }
1937     if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1938         bytesNeeded = sizeof(CRYPT_DATA_BLOB);
1939     else
1940         bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
1941     if (!pvStructInfo)
1942     {
1943         *pcbStructInfo = bytesNeeded;
1944         return TRUE;
1945     }
1946     if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1947      pcbStructInfo, bytesNeeded))
1948         return FALSE;
1949     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1950         pvStructInfo = *(BYTE **)pvStructInfo;
1951     blob = (CRYPT_DATA_BLOB *)pvStructInfo;
1952     blob->cbData = dataLen;
1953     if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1954         blob->pbData = (BYTE *)pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]);
1955     else
1956     {
1957         blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB);
1958         if (blob->cbData)
1959             memcpy(blob->pbData, pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]),
1960              blob->cbData);
1961     }
1962     return TRUE;
1963 }
1964
1965 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
1966  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1967  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1968 {
1969     CRYPT_BIT_BLOB *blob;
1970     DWORD bytesNeeded, dataLen;
1971
1972     if (!pbEncoded)
1973     {
1974         SetLastError(CRYPT_E_ASN1_EOD);
1975         return FALSE;
1976     }
1977     if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
1978         return FALSE;
1979     if (pbEncoded[0] != ASN_BITSTRING)
1980     {
1981         SetLastError(CRYPT_E_ASN1_BADTAG);
1982         return FALSE;
1983     }
1984     if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1985         bytesNeeded = sizeof(CRYPT_BIT_BLOB);
1986     else
1987         bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
1988     if (!pvStructInfo)
1989     {
1990         *pcbStructInfo = bytesNeeded;
1991         return TRUE;
1992     }
1993     if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1994      pcbStructInfo, bytesNeeded))
1995         return FALSE;
1996     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1997         pvStructInfo = *(BYTE **)pvStructInfo;
1998     blob = (CRYPT_BIT_BLOB *)pvStructInfo;
1999     blob->cbData = dataLen - 1;
2000     blob->cUnusedBits = *(pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]));
2001     if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2002         blob->pbData = (BYTE *)pbEncoded + 2 + GET_LEN_BYTES(pbEncoded[1]);
2003     else
2004     {
2005         blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
2006         if (blob->cbData)
2007         {
2008             BYTE mask = 0xff << blob->cUnusedBits;
2009
2010             memcpy(blob->pbData, pbEncoded + 2 + GET_LEN_BYTES(pbEncoded[1]),
2011              blob->cbData);
2012             blob->pbData[blob->cbData - 1] &= mask;
2013         }
2014     }
2015     return TRUE;
2016 }
2017
2018 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
2019  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2020  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2021 {
2022     int val, i;
2023
2024     if (!pbEncoded || !cbEncoded)
2025     {
2026         SetLastError(CRYPT_E_ASN1_EOD);
2027         return FALSE;
2028     }
2029     if (!pvStructInfo)
2030     {
2031         *pcbStructInfo = sizeof(int);
2032         return TRUE;
2033     }
2034     if (pbEncoded[0] != ASN_INTEGER)
2035     {
2036         SetLastError(CRYPT_E_ASN1_BADTAG);
2037         return FALSE;
2038     }
2039     if (cbEncoded <= 1)
2040     {
2041         SetLastError(CRYPT_E_ASN1_EOD);
2042         return FALSE;
2043     }
2044     if (pbEncoded[1] == 0)
2045     {
2046         SetLastError(CRYPT_E_ASN1_CORRUPT);
2047         return FALSE;
2048     }
2049     if (pbEncoded[1] > sizeof(int))
2050     {
2051         SetLastError(CRYPT_E_ASN1_LARGE);
2052         return FALSE;
2053     }
2054     if (pbEncoded[2] & 0x80)
2055     {
2056         /* initialize to a negative value to sign-extend */
2057         val = -1;
2058     }
2059     else
2060         val = 0;
2061     for (i = 0; i < pbEncoded[1]; i++)
2062     {
2063         val <<= 8;
2064         val |= pbEncoded[2 + i];
2065     }
2066     if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2067      pcbStructInfo, sizeof(int)))
2068         return FALSE;
2069     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2070         pvStructInfo = *(BYTE **)pvStructInfo;
2071     memcpy(pvStructInfo, &val, sizeof(int));
2072     return TRUE;
2073 }
2074
2075 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
2076  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2077  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2078 {
2079     DWORD bytesNeeded, dataLen;
2080     BYTE lenBytes;
2081     CRYPT_INTEGER_BLOB *blob;
2082
2083     if (!pbEncoded)
2084     {
2085         SetLastError(CRYPT_E_ASN1_EOD);
2086         return FALSE;
2087     }
2088     if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
2089         return FALSE;
2090     if (pbEncoded[0] != ASN_INTEGER)
2091     {
2092         SetLastError(CRYPT_E_ASN1_BADTAG);
2093         return FALSE;
2094     }
2095     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2096     bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2097     if (!pvStructInfo)
2098     {
2099         *pcbStructInfo = bytesNeeded;
2100         return TRUE;
2101     }
2102     if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2103      pcbStructInfo, bytesNeeded))
2104         return FALSE;
2105     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2106         pvStructInfo = *(BYTE **)pvStructInfo;
2107     blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2108     blob->cbData = dataLen;
2109     blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_INTEGER_BLOB);
2110     if (blob->cbData)
2111     {
2112         DWORD i;
2113
2114         for (i = 0; i < blob->cbData; i++)
2115             blob->pbData[i] = *(pbEncoded + 1 + lenBytes + dataLen - i - 1);
2116     }
2117     return TRUE;
2118 }
2119
2120 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
2121  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2122  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2123 {
2124     DWORD bytesNeeded, dataLen;
2125     BYTE lenBytes;
2126     CRYPT_INTEGER_BLOB *blob;
2127
2128     if (!pbEncoded)
2129     {
2130         SetLastError(CRYPT_E_ASN1_EOD);
2131         return FALSE;
2132     }
2133     if (!CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen))
2134         return FALSE;
2135     if (pbEncoded[0] != ASN_INTEGER)
2136     {
2137         SetLastError(CRYPT_E_ASN1_BADTAG);
2138         return FALSE;
2139     }
2140     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2141     bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
2142     if (!pvStructInfo)
2143     {
2144         *pcbStructInfo = bytesNeeded;
2145         return TRUE;
2146     }
2147     if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2148      pcbStructInfo, bytesNeeded))
2149         return FALSE;
2150     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2151         pvStructInfo = *(BYTE **)pvStructInfo;
2152     blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
2153     blob->cbData = dataLen;
2154     blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_INTEGER_BLOB);
2155     /* remove leading zero byte if it exists */
2156     if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
2157     {
2158         blob->cbData--;
2159         blob->pbData++;
2160     }
2161     if (blob->cbData)
2162     {
2163         DWORD i;
2164
2165         for (i = 0; i < blob->cbData; i++)
2166             blob->pbData[i] = *(pbEncoded + 1 + lenBytes + pbEncoded[1] - i -
2167              1);
2168     }
2169     return TRUE;
2170 }
2171
2172 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
2173  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2174  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2175 {
2176     unsigned int val = 0, i;
2177
2178     /* Based on CRYPT_AsnDecodeInt, but interprets as unsigned */
2179     if (!pbEncoded || !cbEncoded)
2180     {
2181         SetLastError(CRYPT_E_ASN1_EOD);
2182         return FALSE;
2183     }
2184     if (!pvStructInfo)
2185     {
2186         *pcbStructInfo = sizeof(int);
2187         return TRUE;
2188     }
2189     if (pbEncoded[0] != ASN_ENUMERATED)
2190     {
2191         SetLastError(CRYPT_E_ASN1_BADTAG);
2192         return FALSE;
2193     }
2194     if (cbEncoded <= 1)
2195     {
2196         SetLastError(CRYPT_E_ASN1_EOD);
2197         return FALSE;
2198     }
2199     if (pbEncoded[1] == 0)
2200     {
2201         SetLastError(CRYPT_E_ASN1_CORRUPT);
2202         return FALSE;
2203     }
2204     /* A little strange looking, but we have to accept a sign byte: 0xffffffff
2205      * gets encoded as 0a 05 00 ff ff ff ff.  Also, assuming a small length is
2206      * okay here, it has to be in short form.
2207      */
2208     if (pbEncoded[1] > sizeof(unsigned int) + 1)
2209     {
2210         SetLastError(CRYPT_E_ASN1_LARGE);
2211         return FALSE;
2212     }
2213     for (i = 0; i < pbEncoded[1]; i++)
2214     {
2215         val <<= 8;
2216         val |= pbEncoded[2 + i];
2217     }
2218     if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2219      pcbStructInfo, sizeof(unsigned int)))
2220         return FALSE;
2221     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2222         pvStructInfo = *(BYTE **)pvStructInfo;
2223     memcpy(pvStructInfo, &val, sizeof(unsigned int));
2224     return TRUE;
2225 }
2226
2227 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
2228  do { \
2229     BYTE i; \
2230  \
2231     (word) = 0; \
2232     for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
2233     { \
2234         if (!isdigit(*(pbEncoded))) \
2235         { \
2236             SetLastError(CRYPT_E_ASN1_CORRUPT); \
2237             return FALSE; \
2238         } \
2239         (word) *= 10; \
2240         (word) += *(pbEncoded)++ - '0'; \
2241     } \
2242  } while (0)
2243
2244 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
2245  SYSTEMTIME *sysTime)
2246 {
2247     BOOL ret = TRUE;
2248
2249     if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
2250     {
2251         WORD hours, minutes = 0;
2252         BYTE sign = *pbEncoded++;
2253
2254         len--;
2255         CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
2256         if (hours >= 24)
2257         {
2258             SetLastError(CRYPT_E_ASN1_CORRUPT);
2259             ret = FALSE;
2260             goto end;
2261         }
2262         if (len >= 2)
2263         {
2264             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
2265             if (minutes >= 60)
2266             {
2267                 SetLastError(CRYPT_E_ASN1_CORRUPT);
2268                 ret = FALSE;
2269                 goto end;
2270             }
2271         }
2272         if (sign == '+')
2273         {
2274             sysTime->wHour += hours;
2275             sysTime->wMinute += minutes;
2276         }
2277         else
2278         {
2279             if (hours > sysTime->wHour)
2280             {
2281                 sysTime->wDay--;
2282                 sysTime->wHour = 24 - (hours - sysTime->wHour);
2283             }
2284             else
2285                 sysTime->wHour -= hours;
2286             if (minutes > sysTime->wMinute)
2287             {
2288                 sysTime->wHour--;
2289                 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
2290             }
2291             else
2292                 sysTime->wMinute -= minutes;
2293         }
2294     }
2295 end:
2296     return ret;
2297 }
2298
2299 #define MIN_ENCODED_TIME_LENGTH 10
2300
2301 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
2302  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2303  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2304 {
2305     SYSTEMTIME sysTime = { 0 };
2306     BYTE len;
2307     BOOL ret = TRUE;
2308
2309     if (!pbEncoded || !cbEncoded)
2310     {
2311         SetLastError(CRYPT_E_ASN1_EOD);
2312         return FALSE;
2313     }
2314     if (!pvStructInfo)
2315     {
2316         *pcbStructInfo = sizeof(FILETIME);
2317         return TRUE;
2318     }
2319     if (pbEncoded[0] != ASN_UTCTIME)
2320     {
2321         SetLastError(CRYPT_E_ASN1_BADTAG);
2322         return FALSE;
2323     }
2324     if (cbEncoded <= 1)
2325     {
2326         SetLastError(CRYPT_E_ASN1_EOD);
2327         return FALSE;
2328     }
2329     if (pbEncoded[1] > 0x7f)
2330     {
2331         /* long-form date strings really can't be valid */
2332         SetLastError(CRYPT_E_ASN1_CORRUPT);
2333         return FALSE;
2334     }
2335     len = pbEncoded[1];
2336     if (len < MIN_ENCODED_TIME_LENGTH)
2337     {
2338         SetLastError(CRYPT_E_ASN1_CORRUPT);
2339         return FALSE;
2340     }
2341     pbEncoded += 2;
2342     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
2343     if (sysTime.wYear >= 50)
2344         sysTime.wYear += 1900;
2345     else
2346         sysTime.wYear += 2000;
2347     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
2348     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
2349     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
2350     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
2351     if (len > 0)
2352     {
2353         if (len >= 2 && isdigit(*pbEncoded) && isdigit(*(pbEncoded + 1)))
2354             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
2355         else if (isdigit(*pbEncoded))
2356             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, sysTime.wSecond);
2357         ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
2358     }
2359     if (ret)
2360     {
2361         if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2362          pcbStructInfo, sizeof(FILETIME)))
2363             ret = FALSE;
2364         else
2365         {
2366             if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2367                 pvStructInfo = *(BYTE **)pvStructInfo;
2368             ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
2369         }
2370     }
2371     return ret;
2372 }
2373
2374 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
2375  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2376  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2377 {
2378     SYSTEMTIME sysTime = { 0 };
2379     BYTE len;
2380     BOOL ret = TRUE;
2381
2382     if (!pbEncoded || !cbEncoded)
2383     {
2384         SetLastError(CRYPT_E_ASN1_EOD);
2385         return FALSE;
2386     }
2387     if (!pvStructInfo)
2388     {
2389         *pcbStructInfo = sizeof(FILETIME);
2390         return TRUE;
2391     }
2392     if (pbEncoded[0] != ASN_GENERALTIME)
2393     {
2394         SetLastError(CRYPT_E_ASN1_BADTAG);
2395         return FALSE;
2396     }
2397     if (cbEncoded <= 1)
2398     {
2399         SetLastError(CRYPT_E_ASN1_EOD);
2400         return FALSE;
2401     }
2402     if (pbEncoded[1] > 0x7f)
2403     {
2404         /* long-form date strings really can't be valid */
2405         SetLastError(CRYPT_E_ASN1_CORRUPT);
2406         return FALSE;
2407     }
2408     len = pbEncoded[1];
2409     if (len < MIN_ENCODED_TIME_LENGTH)
2410     {
2411         SetLastError(CRYPT_E_ASN1_CORRUPT);
2412         return FALSE;
2413     }
2414     pbEncoded += 2;
2415     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
2416     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
2417     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
2418     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
2419     if (len > 0)
2420     {
2421         CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
2422         if (len > 0)
2423             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
2424         if (len > 0 && (*pbEncoded == '.' || *pbEncoded == ','))
2425         {
2426             BYTE digits;
2427
2428             pbEncoded++;
2429             len--;
2430             digits = min(len, 3); /* workaround macro weirdness */
2431             CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
2432              sysTime.wMilliseconds);
2433         }
2434         ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
2435     }
2436     if (ret)
2437     {
2438         if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
2439          pcbStructInfo, sizeof(FILETIME)))
2440             ret = FALSE;
2441         else
2442         {
2443             if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2444                 pvStructInfo = *(BYTE **)pvStructInfo;
2445             ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
2446         }
2447     }
2448     return ret;
2449 }
2450
2451 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
2452  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2453  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2454 {
2455     BOOL ret;
2456
2457     if (!pbEncoded || !cbEncoded)
2458     {
2459         SetLastError(CRYPT_E_ASN1_EOD);
2460         return FALSE;
2461     }
2462     if (!pvStructInfo)
2463     {
2464         *pcbStructInfo = sizeof(FILETIME);
2465         return TRUE;
2466     }
2467
2468     if (pbEncoded[0] == ASN_UTCTIME)
2469         ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
2470          pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
2471          pcbStructInfo);
2472     else if (pbEncoded[0] == ASN_GENERALTIME)
2473         ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
2474          lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
2475          pvStructInfo, pcbStructInfo);
2476     else
2477     {
2478         SetLastError(CRYPT_E_ASN1_BADTAG);
2479         ret = FALSE;
2480     }
2481     return ret;
2482 }
2483
2484 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
2485  DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
2486
2487 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2488  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2489  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2490 {
2491     BOOL ret = FALSE;
2492     HMODULE lib = NULL;
2493     CryptDecodeObjectExFunc decodeFunc = NULL;
2494
2495     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
2496      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
2497      "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
2498      pvStructInfo, pcbStructInfo);
2499
2500     if (!pvStructInfo && !pcbStructInfo)
2501     {
2502         SetLastError(ERROR_INVALID_PARAMETER);
2503         return FALSE;
2504     }
2505     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2506      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2507     {
2508         SetLastError(ERROR_FILE_NOT_FOUND);
2509         return FALSE;
2510     }
2511
2512     SetLastError(NOERROR);
2513     if (!HIWORD(lpszStructType))
2514     {
2515         switch (LOWORD(lpszStructType))
2516         {
2517         case (WORD)X509_NAME:
2518             decodeFunc = CRYPT_AsnDecodeName;
2519             break;
2520         case (WORD)X509_OCTET_STRING:
2521             decodeFunc = CRYPT_AsnDecodeOctets;
2522             break;
2523         case (WORD)X509_BITS:
2524         case (WORD)X509_KEY_USAGE:
2525             decodeFunc = CRYPT_AsnDecodeBits;
2526             break;
2527         case (WORD)X509_INTEGER:
2528             decodeFunc = CRYPT_AsnDecodeInt;
2529             break;
2530         case (WORD)X509_MULTI_BYTE_INTEGER:
2531             decodeFunc = CRYPT_AsnDecodeInteger;
2532             break;
2533         case (WORD)X509_MULTI_BYTE_UINT:
2534             decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
2535             break;
2536         case (WORD)X509_ENUMERATED:
2537             decodeFunc = CRYPT_AsnDecodeEnumerated;
2538             break;
2539         case (WORD)X509_CHOICE_OF_TIME:
2540             decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
2541             break;
2542         case (WORD)PKCS_UTC_TIME:
2543             decodeFunc = CRYPT_AsnDecodeUtcTime;
2544             break;
2545         default:
2546             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2547         }
2548     }
2549     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2550         decodeFunc = CRYPT_AsnDecodeUtcTime;
2551     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2552         decodeFunc = CRYPT_AsnDecodeEnumerated;
2553     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2554         decodeFunc = CRYPT_AsnDecodeBits;
2555     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2556         decodeFunc = CRYPT_AsnDecodeOctets;
2557     else
2558         TRACE("OID %s not found or unimplemented, looking for DLL\n",
2559          debugstr_a(lpszStructType));
2560     if (!decodeFunc)
2561         decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
2562          lpszStructType, "CryptDecodeObjectEx", &lib);
2563     if (decodeFunc)
2564         ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
2565          cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
2566     else
2567         SetLastError(ERROR_FILE_NOT_FOUND);
2568     if (lib)
2569         FreeLibrary(lib);
2570     return ret;
2571 }