Add encode/decode support for multi-byte integers.
[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 #include <stdarg.h>
20 #include <stdio.h>
21 #include <stdlib.h>
22 #include "windef.h"
23 #include "winbase.h"
24 #include "wincrypt.h"
25 #include "winreg.h"
26 #include "snmp.h"
27 #include "wine/debug.h"
28
29 /* a few asn.1 tags we need */
30 #define ASN_SETOF           (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
31 #define ASN_NUMERICSTRING   (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
32 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
33 #define ASN_IA5STRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
34 #define ASN_UTCTIME         (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
35 #define ASN_GENERALTIME     (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
36
37 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
38
39 static const WCHAR szDllName[] = { 'D','l','l',0 };
40
41 static char *CRYPT_GetKeyName(DWORD dwEncodingType, LPCSTR pszFuncName,
42  LPCSTR pszOID)
43 {
44     static const char szEncodingTypeFmt[] =
45      "Software\\Microsoft\\Cryptography\\OID\\EncodingType %ld\\%s\\%s";
46     UINT len;
47     char numericOID[7]; /* enough for "#65535" */
48     const char *oid;
49     LPSTR szKey;
50
51     /* MSDN says the encoding type is a mask, but it isn't treated that way.
52      * (E.g., if dwEncodingType were 3, the key names "EncodingType 1" and
53      * "EncodingType 2" would be expected if it were a mask.  Instead native
54      * stores values in "EncodingType 3".
55      */
56     if (!HIWORD(pszOID))
57     {
58         snprintf(numericOID, sizeof(numericOID), "#%d", (int)pszOID);
59         oid = numericOID;
60     }
61     else
62         oid = pszOID;
63
64     /* This is enough: the lengths of the two string parameters are explicitly
65      * counted, and we need up to five additional characters for the encoding
66      * type.  These are covered by the "%d", "%s", and "%s" characters in the
67      * format specifier that are removed by sprintf.
68      */
69     len = sizeof(szEncodingTypeFmt) + lstrlenA(pszFuncName) + lstrlenA(oid);
70     szKey = HeapAlloc(GetProcessHeap(), 0, len);
71     if (szKey)
72         sprintf(szKey, szEncodingTypeFmt, dwEncodingType, pszFuncName, oid);
73     return szKey;
74 }
75
76 BOOL WINAPI CryptRegisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
77                   LPCSTR pszOID, LPCWSTR pwszDll, LPCSTR pszOverrideFuncName)
78 {
79     LONG r;
80     HKEY hKey;
81     LPSTR szKey;
82
83     TRACE("%lx %s %s %s %s\n", dwEncodingType, pszFuncName, pszOID,
84           debugstr_w(pwszDll), pszOverrideFuncName);
85
86     /* This only registers functions for encoding certs, not messages */
87     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
88         return TRUE;
89
90     /* Native does nothing pwszDll is NULL */
91     if (!pwszDll)
92         return TRUE;
93
94     /* I'm not matching MS bug for bug here, because I doubt any app depends on
95      * it:
96      * - native "succeeds" if pszFuncName is NULL, but the nonsensical entry
97      *   it creates would never be used
98      * - native returns an HRESULT rather than a Win32 error if pszOID is NULL.
99      * Instead I disallow both of these with ERROR_INVALID_PARAMETER.
100      */
101     if (!pszFuncName || !pszOID)
102     {
103         SetLastError(ERROR_INVALID_PARAMETER);
104         return FALSE;
105     }
106
107     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
108     TRACE("Key name is %s\n", debugstr_a(szKey));
109
110     if (!szKey)
111         return FALSE;
112
113     r = RegCreateKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
114     HeapFree(GetProcessHeap(), 0, szKey);
115     if(r != ERROR_SUCCESS)
116         return FALSE;
117
118     /* write the values */
119     if (pszOverrideFuncName)
120         RegSetValueExA(hKey, "FuncName", 0, REG_SZ, pszOverrideFuncName,
121          lstrlenA(pszOverrideFuncName) + 1);
122     RegSetValueExW(hKey, szDllName, 0, REG_SZ, (const BYTE*) pwszDll,
123                     (lstrlenW(pwszDll) + 1) * sizeof (WCHAR));
124
125     RegCloseKey(hKey);
126     return TRUE;
127 }
128
129 BOOL WINAPI CryptUnregisterOIDFunction(DWORD dwEncodingType, LPCSTR pszFuncName,
130  LPCSTR pszOID)
131 {
132     LPSTR szKey;
133     LONG rc;
134
135     TRACE("%lx %s %s\n", dwEncodingType, pszFuncName, pszOID);
136
137     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
138         return TRUE;
139
140     if (!pszFuncName || !pszOID)
141     {
142         SetLastError(ERROR_INVALID_PARAMETER);
143         return FALSE;
144     }
145
146     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
147     rc = RegDeleteKeyA(HKEY_LOCAL_MACHINE, szKey);
148     HeapFree(GetProcessHeap(), 0, szKey);
149     if (rc)
150         SetLastError(rc);
151     return rc ? FALSE : TRUE;
152 }
153
154 BOOL WINAPI CryptGetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
155  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD *pdwValueType, BYTE *pbValueData,
156  DWORD *pcbValueData)
157 {
158     LPSTR szKey;
159     LONG rc;
160     HKEY hKey;
161
162     TRACE("%lx %s %s %s %p %p %p\n", dwEncodingType, debugstr_a(pszFuncName),
163      debugstr_a(pszOID), debugstr_w(pwszValueName), pdwValueType, pbValueData,
164      pcbValueData);
165
166     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
167         return TRUE;
168
169     if (!pszFuncName || !pszOID || !pwszValueName)
170     {
171         SetLastError(ERROR_INVALID_PARAMETER);
172         return FALSE;
173     }
174
175     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
176     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
177     HeapFree(GetProcessHeap(), 0, szKey);
178     if (rc)
179         SetLastError(rc);
180     else
181     {
182         rc = RegQueryValueExW(hKey, pwszValueName, NULL, pdwValueType,
183          pbValueData, pcbValueData);
184         if (rc)
185             SetLastError(rc);
186         RegCloseKey(hKey);
187     }
188     return rc ? FALSE : TRUE;
189 }
190
191 BOOL WINAPI CryptSetOIDFunctionValue(DWORD dwEncodingType, LPCSTR pszFuncName,
192  LPCSTR pszOID, LPCWSTR pwszValueName, DWORD dwValueType,
193  const BYTE *pbValueData, DWORD cbValueData)
194 {
195     LPSTR szKey;
196     LONG rc;
197     HKEY hKey;
198
199     TRACE("%lx %s %s %s %ld %p %ld\n", dwEncodingType, debugstr_a(pszFuncName),
200      debugstr_a(pszOID), debugstr_w(pwszValueName), dwValueType, pbValueData,
201      cbValueData);
202
203     if (!GET_CERT_ENCODING_TYPE(dwEncodingType))
204         return TRUE;
205
206     if (!pszFuncName || !pszOID || !pwszValueName)
207     {
208         SetLastError(ERROR_INVALID_PARAMETER);
209         return FALSE;
210     }
211
212     szKey = CRYPT_GetKeyName(dwEncodingType, pszFuncName, pszOID);
213     rc = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
214     HeapFree(GetProcessHeap(), 0, szKey);
215     if (rc)
216         SetLastError(rc);
217     else
218     {
219         rc = RegSetValueExW(hKey, pwszValueName, 0, dwValueType, pbValueData,
220          cbValueData);
221         if (rc)
222             SetLastError(rc);
223         RegCloseKey(hKey);
224     }
225     return rc ? FALSE : TRUE;
226 }
227
228 /* Gets the registered function named szFuncName for dwCertEncodingType and
229  * lpszStructType, or NULL if one could not be found.  *lib will be set to the
230  * handle of the module it's in, or NULL if no module was loaded.  If the
231  * return value is NULL, *lib will also be NULL, to simplify error handling.
232  */
233 static void *CRYPT_GetFunc(DWORD dwCertEncodingType, LPCSTR lpszStructType,
234  LPCSTR szFuncName, HMODULE *lib)
235 {
236     void *ret = NULL;
237     char *szKey = CRYPT_GetKeyName(dwCertEncodingType, szFuncName,
238      lpszStructType);
239     const char *funcName;
240     long r;
241     HKEY hKey;
242     DWORD type, size = 0;
243
244     *lib = NULL;
245     r = RegOpenKeyA(HKEY_LOCAL_MACHINE, szKey, &hKey);
246     HeapFree(GetProcessHeap(), 0, szKey);
247     if(r != ERROR_SUCCESS)
248         return NULL;
249
250     RegQueryValueExA(hKey, "FuncName", NULL, &type, NULL, &size);
251     if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
252     {
253         funcName = HeapAlloc(GetProcessHeap(), 0, size);
254         RegQueryValueExA(hKey, "FuncName", NULL, &type, (LPBYTE)funcName,
255          &size);
256     }
257     else
258         funcName = szFuncName;
259     RegQueryValueExW(hKey, szDllName, NULL, &type, NULL, &size);
260     if (GetLastError() == ERROR_MORE_DATA && type == REG_SZ)
261     {
262         LPWSTR dllName = HeapAlloc(GetProcessHeap(), 0, size);
263
264         RegQueryValueExW(hKey, szDllName, NULL, &type, (LPBYTE)dllName,
265          &size);
266         *lib = LoadLibraryW(dllName);
267         if (*lib)
268         {
269              ret = GetProcAddress(*lib, funcName);
270              if (!ret)
271              {
272                  /* Unload the library, the caller doesn't want to unload it
273                   * when the return value is NULL.
274                   */
275                  FreeLibrary(*lib);
276                  *lib = NULL;
277              }
278         }
279         HeapFree(GetProcessHeap(), 0, dllName);
280     }
281     if (funcName != szFuncName)
282         HeapFree(GetProcessHeap(), 0, (char *)funcName);
283     return ret;
284 }
285
286 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
287  BYTE *, DWORD *);
288
289 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
290  const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
291 {
292     BOOL ret = FALSE;
293     HMODULE lib;
294     CryptEncodeObjectFunc pCryptEncodeObject;
295
296     TRACE("(0x%08lx, %s, %p, %p, %p)\n",
297      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
298      "(integer value)", pvStructInfo, pbEncoded, pcbEncoded);
299
300     if (!pbEncoded && !pcbEncoded)
301     {
302         SetLastError(ERROR_INVALID_PARAMETER);
303         return FALSE;
304     }
305
306     /* Try registered DLL first.. */
307     pCryptEncodeObject =
308      (CryptEncodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
309      lpszStructType, "CryptEncodeObject", &lib);
310     if (pCryptEncodeObject)
311     {
312         ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
313          pvStructInfo, pbEncoded, pcbEncoded);
314         FreeLibrary(lib);
315     }
316     else
317     {
318         /* If not, use CryptEncodeObjectEx */
319         ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
320          pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
321     }
322     return ret;
323 }
324
325 /* Helper function to check *pcbEncoded, set it to the required size, and
326  * optionally to allocate memory.  Assumes pbEncoded is not NULL.
327  * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
328  * pointer to the newly allocated memory.
329  */
330 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
331  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
332  DWORD bytesNeeded)
333 {
334     BOOL ret = TRUE;
335
336     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
337     {
338         if (pEncodePara && pEncodePara->pfnAlloc)
339             *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
340         else
341             *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
342         if (!*(BYTE **)pbEncoded)
343             ret = FALSE;
344         else
345             *pcbEncoded = bytesNeeded;
346     }
347     else if (bytesNeeded > *pcbEncoded)
348     {
349         *pcbEncoded = bytesNeeded;
350         SetLastError(ERROR_MORE_DATA);
351         ret = FALSE;
352     }
353     return ret;
354 }
355
356 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
357  LPCSTR pszObjId, BYTE *pbEncoded, DWORD *pcbEncoded)
358 {
359     DWORD bytesNeeded = 2;
360     BOOL ret = TRUE;
361     int firstPos = 0;
362     BYTE firstByte = 0;
363
364     if (pszObjId)
365     {
366         const char *ptr;
367         int val1, val2;
368
369         if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
370         {
371             SetLastError(CRYPT_E_ASN1_ERROR);
372             return FALSE;
373         }
374         bytesNeeded++;
375         firstByte = val1 * 40 + val2;
376         ptr = pszObjId + firstPos;
377         while (ret && *ptr)
378         {
379             int pos;
380
381             /* note I assume each component is at most 32-bits long in base 2 */
382             if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
383             {
384                 if (val1 >= 0x10000000)
385                     bytesNeeded += 5;
386                 else if (val1 >= 0x200000)
387                     bytesNeeded += 4;
388                 else if (val1 >= 0x4000)
389                     bytesNeeded += 3;
390                 else if (val1 >= 0x80)
391                     bytesNeeded += 2;
392                 else
393                     bytesNeeded += 1;
394                 ptr += pos;
395                 if (*ptr == '.')
396                     ptr++;
397             }
398             else
399             {
400                 SetLastError(CRYPT_E_ASN1_ERROR);
401                 return FALSE;
402             }
403         }
404     }
405     if (pbEncoded)
406     {
407         if (*pbEncoded < bytesNeeded)
408         {
409             SetLastError(ERROR_MORE_DATA);
410             ret = FALSE;
411         }
412         else
413         {
414             *pbEncoded++ = ASN_OBJECTIDENTIFIER;
415             *pbEncoded++ = bytesNeeded - 2;
416             if (pszObjId)
417             {
418                 const char *ptr;
419                 int val, pos;
420
421                 *pbEncoded++ = firstByte;
422                 ptr = pszObjId + firstPos;
423                 while (ret && *ptr)
424                 {
425                     sscanf(ptr, "%d%n", &val, &pos);
426                     {
427                         unsigned char outBytes[5];
428                         int numBytes, i;
429
430                         if (val >= 0x10000000)
431                             numBytes = 5;
432                         else if (val >= 0x200000)
433                             numBytes = 4;
434                         else if (val >= 0x4000)
435                             numBytes = 3;
436                         else if (val >= 0x80)
437                             numBytes = 2;
438                         else
439                             numBytes = 1;
440                         for (i = numBytes; i > 0; i--)
441                         {
442                             outBytes[i - 1] = val & 0x7f;
443                             val >>= 7;
444                         }
445                         for (i = 0; i < numBytes - 1; i++)
446                             *pbEncoded++ = outBytes[i] | 0x80;
447                         *pbEncoded++ = outBytes[i];
448                         ptr += pos;
449                         if (*ptr == '.')
450                             ptr++;
451                     }
452                 }
453             }
454         }
455     }
456     *pcbEncoded = bytesNeeded;
457     return ret;
458 }
459
460 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
461  CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
462 {
463     BYTE tag;
464     DWORD bytesNeeded;
465     BOOL ret = TRUE;
466
467     switch (value->dwValueType)
468     {
469     case CERT_RDN_NUMERIC_STRING:
470         tag = ASN_NUMERICSTRING;
471         bytesNeeded = 2 + value->Value.cbData;
472         break;
473     case CERT_RDN_PRINTABLE_STRING:
474         tag = ASN_PRINTABLESTRING;
475         bytesNeeded = 2 + value->Value.cbData;
476         break;
477     case CERT_RDN_IA5_STRING:
478         tag = ASN_IA5STRING;
479         bytesNeeded = 2 + value->Value.cbData;
480         break;
481     case CERT_RDN_ANY_TYPE:
482         /* explicitly disallowed */
483         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
484         return FALSE;
485     default:
486         FIXME("String type %ld unimplemented\n", value->dwValueType);
487         return FALSE;
488     }
489     if (pbEncoded)
490     {
491         if (*pcbEncoded < bytesNeeded)
492         {
493             SetLastError(ERROR_MORE_DATA);
494             ret = FALSE;
495         }
496         else
497         {
498             *pbEncoded++ = tag;
499             *pbEncoded++ = bytesNeeded - 2;
500             switch (value->dwValueType)
501             {
502             case CERT_RDN_NUMERIC_STRING:
503             case CERT_RDN_PRINTABLE_STRING:
504             case CERT_RDN_IA5_STRING:
505                 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
506             }
507         }
508     }
509     *pcbEncoded = bytesNeeded;
510     return ret;
511 }
512
513 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
514  CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
515 {
516     DWORD bytesNeeded, size;
517     BOOL ret;
518
519     bytesNeeded = 2; /* tag and len */
520     ret = CRYPT_AsnEncodeOid(dwCertEncodingType, attr->pszObjId, NULL, &size);
521     if (ret)
522     {
523         bytesNeeded += size;
524         /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
525          * with dwValueType, so "cast" it to get its encoded size
526          */
527         ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
528          (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
529         if (ret)
530         {
531             bytesNeeded += size;
532             if (pbEncoded)
533             {
534                 if (*pcbEncoded < bytesNeeded)
535                 {
536                     SetLastError(ERROR_MORE_DATA);
537                     ret = FALSE;
538                 }
539                 else
540                 {
541                     *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
542                     *pbEncoded++ = bytesNeeded - 2;
543                     size = bytesNeeded - 2;
544                     ret = CRYPT_AsnEncodeOid(dwCertEncodingType, attr->pszObjId,
545                      pbEncoded, &size);
546                     if (ret)
547                     {
548                         pbEncoded += size;
549                         size = bytesNeeded - 2 - size;
550                         ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
551                          (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
552                          &size);
553                     }
554                 }
555             }
556             *pcbEncoded = bytesNeeded;
557         }
558     }
559     return ret;
560 }
561
562 static int BLOBComp(const void *l, const void *r)
563 {
564     CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
565     int ret;
566
567     if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
568         ret = a->cbData - b->cbData;
569     return ret;
570 }
571
572 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
573  */
574 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
575  BYTE *pbEncoded, DWORD *pcbEncoded)
576 {
577     DWORD bytesNeeded, i;
578     BOOL ret;
579     CRYPT_DER_BLOB *blobs = NULL;
580    
581     ret = TRUE;
582     if (rdn->cRDNAttr)
583     {
584         if (!rdn->rgRDNAttr)
585         {
586             SetLastError(STATUS_ACCESS_VIOLATION);
587             ret = FALSE;
588         }
589         else
590         {
591             blobs = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
592              rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
593             if (!blobs)
594                 ret = FALSE;
595         }
596     }
597     bytesNeeded = 2; /* tag and len */
598     for (i = 0; ret && i < rdn->cRDNAttr; i++)
599     {
600         ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
601          NULL, &blobs[i].cbData);
602         if (ret)
603             bytesNeeded += blobs[i].cbData;
604     }
605     if (ret)
606     {
607         if (pbEncoded)
608         {
609             if (*pcbEncoded < bytesNeeded)
610             {
611                 SetLastError(ERROR_MORE_DATA);
612                 ret = FALSE;
613             }
614             else
615             {
616                 for (i = 0; ret && i < rdn->cRDNAttr; i++)
617                 {
618                     blobs[i].pbData = HeapAlloc(GetProcessHeap(), 0,
619                      blobs[i].cbData);
620                     if (!blobs[i].pbData)
621                         ret = FALSE;
622                     else
623                         ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
624                          &rdn->rgRDNAttr[i], blobs[i].pbData, &blobs[i].cbData);
625                 }
626                 if (ret)
627                 {
628                     qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
629                      BLOBComp);
630                     *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
631                     *pbEncoded++ = (BYTE)bytesNeeded - 2;
632                     for (i = 0; ret && i < rdn->cRDNAttr; i++)
633                     {
634                         memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
635                         pbEncoded += blobs[i].cbData;
636                     }
637                 }
638             }
639         }
640         *pcbEncoded = bytesNeeded;
641     }
642     if (blobs)
643     {
644         for (i = 0; i < rdn->cRDNAttr; i++)
645             HeapFree(GetProcessHeap(), 0, blobs[i].pbData);
646         HeapFree(GetProcessHeap(), 0, blobs);
647     }
648     return ret;
649 }
650
651 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
652  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
653  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
654 {
655     CERT_NAME_INFO *info = (CERT_NAME_INFO *)pvStructInfo;
656     DWORD bytesNeeded, size, i;
657     BOOL ret;
658
659     if (!pvStructInfo)
660     {
661         SetLastError(STATUS_ACCESS_VIOLATION);
662         return FALSE;
663     }
664     if (info->cRDN && !info->rgRDN)
665     {
666         SetLastError(STATUS_ACCESS_VIOLATION);
667         return FALSE;
668     }
669     TRACE("encoding name with %ld RDNs\n", info->cRDN);
670     bytesNeeded = 2; /* tag and len */
671     ret = TRUE;
672     for (i = 0; ret && i < info->cRDN; i++)
673     {
674         ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
675          &size);
676         if (ret)
677             bytesNeeded += size;
678     }
679     if (ret)
680     {
681         if (!pbEncoded)
682         {
683             *pcbEncoded = bytesNeeded;
684             return TRUE;
685         }
686         if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
687          pcbEncoded, bytesNeeded))
688             return FALSE;
689         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
690             pbEncoded = *(BYTE **)pbEncoded;
691         *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SEQUENCE;
692         *pbEncoded++ = (BYTE)bytesNeeded - 2;
693         for (i = 0; ret && i < info->cRDN; i++)
694         {
695             size = bytesNeeded;
696             ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
697              pbEncoded, &size);
698             if (ret)
699             {
700                 pbEncoded += size;
701                 bytesNeeded -= size;
702             }
703         }
704     }
705     return ret;
706 }
707
708 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
709  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
710  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
711 {
712     INT val, i;
713     BYTE significantBytes, padByte = 0, bytesNeeded;
714     BOOL neg = FALSE, pad = FALSE;
715
716     if (!pvStructInfo)
717     {
718         SetLastError(STATUS_ACCESS_VIOLATION);
719         return FALSE;
720     }
721
722     memcpy(&val, pvStructInfo, sizeof(val));
723     /* Count the number of significant bytes.  Temporarily swap sign for
724      * negatives so I count the minimum number of bytes.
725      */
726     if (val < 0)
727     {
728         neg = TRUE;
729         val = -val;
730     }
731     for (significantBytes = sizeof(val); !(val & 0xff000000);
732      val <<= 8, significantBytes--)
733         ;
734     if (neg)
735     {
736         val = -val;
737         if ((val & 0xff000000) < 0x80000000)
738         {
739             padByte = 0xff;
740             pad = TRUE;
741         }
742     }
743     else if ((val & 0xff000000) > 0x7f000000)
744     {
745         padByte = 0;
746         pad = TRUE;
747     }
748     bytesNeeded = 2 + significantBytes;
749     if (pad)
750         bytesNeeded++;
751     if (!pbEncoded)
752     {
753         *pcbEncoded = bytesNeeded;
754         return TRUE;
755     }
756     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
757      bytesNeeded))
758         return FALSE;
759     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
760         pbEncoded = *(BYTE **)pbEncoded;
761     *pbEncoded++ = ASN_INTEGER;
762     if (pad)
763     {
764         *pbEncoded++ = significantBytes + 1;
765         *pbEncoded++ = padByte;
766     }
767     else
768         *pbEncoded++ = significantBytes;
769     for (i = 0; i < significantBytes; i++, val <<= 8)
770         *(pbEncoded + i) = (BYTE)((val & 0xff000000) >> 24);
771     return TRUE;
772 }
773
774 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
775  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
776  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
777 {
778     DWORD significantBytes;
779     BYTE padByte = 0, bytesNeeded;
780     BOOL pad = FALSE;
781     CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
782
783     if (!pvStructInfo)
784     {
785         SetLastError(STATUS_ACCESS_VIOLATION);
786         return FALSE;
787     }
788
789     /* FIXME: use exception handling to protect against bogus pointers */
790     significantBytes = blob->cbData;
791     if (significantBytes)
792     {
793         if (blob->pbData[significantBytes - 1] & 0x80)
794         {
795             /* negative, lop off leading (little-endian) 0xffs */
796             for (; significantBytes > 0 &&
797              blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
798                 ;
799             if (blob->pbData[significantBytes - 1] < 0x80)
800             {
801                 padByte = 0xff;
802                 pad = TRUE;
803             }
804         }
805         else
806         {
807             /* positive, lop off leading (little-endian) zeroes */
808             for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
809              significantBytes--)
810                 ;
811             if (blob->pbData[significantBytes - 1] > 0x7f)
812             {
813                 padByte = 0;
814                 pad = TRUE;
815             }
816         }
817     }
818     bytesNeeded = 2 + significantBytes;
819     if (pad)
820         bytesNeeded++;
821     if (!pbEncoded)
822     {
823         *pcbEncoded = bytesNeeded;
824         return TRUE;
825     }
826     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
827      bytesNeeded))
828         return FALSE;
829     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
830         pbEncoded = *(BYTE **)pbEncoded;
831     *pbEncoded++ = ASN_INTEGER;
832     if (pad)
833     {
834         *pbEncoded++ = significantBytes + 1;
835         *pbEncoded++ = padByte;
836     }
837     else
838         *pbEncoded++ = significantBytes;
839     for (; significantBytes > 0; significantBytes--)
840         *(pbEncoded++) = blob->pbData[significantBytes - 1];
841     return TRUE;
842 }
843
844 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
845  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
846  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
847 {
848     SYSTEMTIME sysTime;
849     /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
850      * temporary buffer because the output buffer is not NULL-terminated.
851      */
852     char buf[16];
853     static const DWORD bytesNeeded = sizeof(buf) - 1;
854
855     if (!pvStructInfo)
856     {
857         SetLastError(STATUS_ACCESS_VIOLATION);
858         return FALSE;
859     }
860     /* Sanity check the year, this is a two-digit year format */
861     if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
862         return FALSE;
863     if (sysTime.wYear < 1950 || sysTime.wYear > 2050)
864     {
865         SetLastError(CRYPT_E_BAD_ENCODE);
866         return FALSE;
867     }
868     if (!pbEncoded)
869     {
870         *pcbEncoded = bytesNeeded;
871         return TRUE;
872     }
873     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
874      bytesNeeded))
875         return FALSE;
876     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
877         pbEncoded = *(BYTE **)pbEncoded;
878     buf[0] = ASN_UTCTIME;
879     buf[1] = bytesNeeded - 2;
880     snprintf(buf + 2, sizeof(buf) - 2, "%02d%02d%02d%02d%02d%02dZ",
881      sysTime.wYear >= 2000 ? sysTime.wYear - 2000 : sysTime.wYear - 1900,
882      sysTime.wDay, sysTime.wMonth, sysTime.wHour, sysTime.wMinute,
883      sysTime.wSecond);
884     memcpy(pbEncoded, buf, bytesNeeded);
885     return TRUE;
886 }
887
888 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
889  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
890  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
891 {
892     SYSTEMTIME sysTime;
893     /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
894      * temporary buffer because the output buffer is not NULL-terminated.
895      */
896     char buf[18];
897     static const DWORD bytesNeeded = sizeof(buf) - 1;
898
899     if (!pvStructInfo)
900     {
901         SetLastError(STATUS_ACCESS_VIOLATION);
902         return FALSE;
903     }
904     if (!pbEncoded)
905     {
906         *pcbEncoded = bytesNeeded;
907         return TRUE;
908     }
909     if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
910         return FALSE;
911     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
912      bytesNeeded))
913         return FALSE;
914     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
915         pbEncoded = *(BYTE **)pbEncoded;
916     buf[0] = ASN_GENERALTIME;
917     buf[1] = bytesNeeded - 2;
918     snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
919      sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
920      sysTime.wMinute, sysTime.wSecond);
921     memcpy(pbEncoded, buf, bytesNeeded);
922     return TRUE;
923 }
924
925 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
926  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
927  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
928 {
929     SYSTEMTIME sysTime;
930     BOOL ret;
931
932     if (!pvStructInfo)
933     {
934         SetLastError(STATUS_ACCESS_VIOLATION);
935         return FALSE;
936     }
937     /* Check the year, if it's in the UTCTime range call that encode func */
938     if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
939         return FALSE;
940     if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
941         ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
942          pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
943     else
944         ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
945          lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
946          pcbEncoded);
947     return ret;
948 }
949
950 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
951  DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
952
953 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
954  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
955  BYTE *pbEncoded, DWORD *pcbEncoded)
956 {
957     BOOL ret = FALSE;
958     HMODULE lib = NULL;
959     CryptEncodeObjectExFunc encodeFunc = NULL;
960
961     TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p): semi-stub\n",
962      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
963      "(integer value)", pvStructInfo, dwFlags, pEncodePara, pbEncoded,
964      pcbEncoded);
965
966     if (!pbEncoded && !pcbEncoded)
967     {
968         SetLastError(ERROR_INVALID_PARAMETER);
969         return FALSE;
970     }
971     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
972      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
973     {
974         SetLastError(ERROR_FILE_NOT_FOUND);
975         return FALSE;
976     }
977
978     SetLastError(NOERROR);
979     if (!HIWORD(lpszStructType))
980     {
981         switch (LOWORD(lpszStructType))
982         {
983         case (WORD)X509_NAME:
984             encodeFunc = CRYPT_AsnEncodeName;
985             break;
986         case (WORD)X509_INTEGER:
987             encodeFunc = CRYPT_AsnEncodeInt;
988             break;
989         case (WORD)X509_MULTI_BYTE_INTEGER:
990             encodeFunc = CRYPT_AsnEncodeInteger;
991             break;
992         case (WORD)X509_CHOICE_OF_TIME:
993             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
994             break;
995         case (WORD)PKCS_UTC_TIME:
996             encodeFunc = CRYPT_AsnEncodeUtcTime;
997             break;
998         default:
999             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1000         }
1001     }
1002     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1003         encodeFunc = CRYPT_AsnEncodeUtcTime;
1004     if (!encodeFunc)
1005         encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1006          lpszStructType, "CryptEncodeObjectEx", &lib);
1007     if (encodeFunc)
1008         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
1009          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1010     else
1011         SetLastError(ERROR_FILE_NOT_FOUND);
1012     if (lib)
1013         FreeLibrary(lib);
1014     return ret;
1015 }
1016
1017 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
1018  DWORD, DWORD, void *, DWORD *);
1019
1020 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1021  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
1022  DWORD *pcbStructInfo)
1023 {
1024     BOOL ret = FALSE;
1025     HMODULE lib;
1026     CryptDecodeObjectFunc pCryptDecodeObject;
1027
1028     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
1029      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1030      "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
1031      pcbStructInfo);
1032
1033     if (!pvStructInfo && !pcbStructInfo)
1034     {
1035         SetLastError(ERROR_INVALID_PARAMETER);
1036         return FALSE;
1037     }
1038
1039     /* Try registered DLL first.. */
1040     pCryptDecodeObject =
1041      (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
1042      lpszStructType, "CryptDecodeObject", &lib);
1043     if (pCryptDecodeObject)
1044     {
1045         ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
1046          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
1047         FreeLibrary(lib);
1048     }
1049     else
1050     {
1051         /* If not, use CryptDecodeObjectEx */
1052         ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
1053          cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
1054     }
1055     return ret;
1056 }
1057
1058 /* Helper function to check *pcbStructInfo, set it to the required size, and
1059  * optionally to allocate memory.  Assumes pvStructInfo is not NULL.
1060  * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
1061  * pointer to the newly allocated memory.
1062  */
1063 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
1064  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
1065  DWORD bytesNeeded)
1066 {
1067     BOOL ret = TRUE;
1068
1069     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1070     {
1071         if (pDecodePara && pDecodePara->pfnAlloc)
1072             *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
1073         else
1074             *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
1075         if (!*(BYTE **)pvStructInfo)
1076             ret = FALSE;
1077         else
1078             *pcbStructInfo = bytesNeeded;
1079     }
1080     else if (*pcbStructInfo < bytesNeeded)
1081     {
1082         *pcbStructInfo = bytesNeeded;
1083         SetLastError(ERROR_MORE_DATA);
1084         ret = FALSE;
1085     }
1086     return ret;
1087 }
1088
1089 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_FLAG. */
1090 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1091  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, LPSTR pszObjId,
1092  DWORD *pcbObjId)
1093 {
1094     BOOL ret = TRUE;
1095     DWORD bytesNeeded;
1096
1097     /* cbEncoded is an upper bound on the number of bytes, not the actual
1098      * count: check the count for sanity.
1099      */
1100     if (cbEncoded <= 1 || pbEncoded[1] > cbEncoded - 2)
1101     {
1102         SetLastError(CRYPT_E_ASN1_EOD);
1103         return FALSE;
1104     }
1105     if (pbEncoded[0] != ASN_OBJECTIDENTIFIER)
1106     {
1107         SetLastError(CRYPT_E_ASN1_BADTAG);
1108         return FALSE;
1109     }
1110     if (pbEncoded[1])
1111     {
1112         /* The largest possible string for the first two components is 2.175
1113          * (= 2 * 40 + 175 = 255), so this is big enough.
1114          */
1115         char firstTwo[6];
1116         const BYTE *ptr;
1117
1118         snprintf(firstTwo, sizeof(firstTwo), "%d.%d", pbEncoded[2] / 40,
1119          pbEncoded[2] - (pbEncoded[2] / 40) * 40);
1120         bytesNeeded = strlen(firstTwo) + 1;
1121         for (ptr = pbEncoded + 3; ret && ptr - pbEncoded - 2 < pbEncoded[1]; )
1122         {
1123             /* large enough for ".4000000" */
1124             char str[9];
1125             int val = 0;
1126
1127             while (ptr - pbEncoded - 2 < pbEncoded[1] && (*ptr & 0x80))
1128             {
1129                 val <<= 7;
1130                 val |= *ptr & 0x7f;
1131                 ptr++;
1132             }
1133             if (ptr - pbEncoded - 2 >= pbEncoded[1] || (*ptr & 0x80))
1134             {
1135                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1136                 ret = FALSE;
1137             }
1138             else
1139             {
1140                 val <<= 7;
1141                 val |= *ptr++;
1142                 snprintf(str, sizeof(str), ".%d", val);
1143                 bytesNeeded += strlen(str);
1144             }
1145         }
1146         if (!pszObjId)
1147             *pcbObjId = bytesNeeded;
1148         else if (*pcbObjId < bytesNeeded)
1149         {
1150             *pcbObjId = bytesNeeded;
1151             SetLastError(ERROR_MORE_DATA);
1152             ret = FALSE;
1153         }
1154         else
1155         {
1156             sprintf(pszObjId, "%d.%d", pbEncoded[2] / 40,
1157              pbEncoded[2] - (pbEncoded[2] / 40) * 40);
1158             pszObjId += strlen(pszObjId);
1159             for (ptr = pbEncoded + 3; ret && ptr - pbEncoded - 2 < pbEncoded[1];
1160              )
1161             {
1162                 int val = 0;
1163
1164                 while (ptr - pbEncoded - 2 < pbEncoded[1] && (*ptr & 0x80))
1165                 {
1166                     val <<= 7;
1167                     val |= *ptr & 0x7f;
1168                     ptr++;
1169                 }
1170                 val <<= 7;
1171                 val |= *ptr++;
1172                 sprintf(pszObjId, ".%d", val);
1173                 pszObjId += strlen(pszObjId);
1174             }
1175         }
1176     }
1177     else
1178         bytesNeeded = 0;
1179     *pcbObjId = bytesNeeded;
1180     return ret;
1181 }
1182
1183 /* Warning: this assumes the address of value->Value.pbData is already set, in
1184  * order to avoid overwriting memory.  (In some cases, it may change it, if it
1185  * doesn't copy anything to memory.)  Be sure to set it correctly!
1186  */
1187 static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
1188  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value,
1189  DWORD *pcbValue)
1190 {
1191     DWORD bytesNeeded;
1192     BOOL ret = TRUE;
1193
1194     /* cbEncoded is an upper bound on the number of bytes, not the actual
1195      * count: check the count for sanity.
1196      */
1197     if (cbEncoded <= 1 || pbEncoded[1] > cbEncoded - 2)
1198     {
1199         SetLastError(CRYPT_E_ASN1_EOD);
1200         return FALSE;
1201     }
1202     switch (pbEncoded[0])
1203     {
1204     case ASN_NUMERICSTRING:
1205     case ASN_PRINTABLESTRING:
1206     case ASN_IA5STRING:
1207         break;
1208     default:
1209         FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
1210         SetLastError(OSS_UNIMPLEMENTED);
1211         return FALSE;
1212     }
1213     bytesNeeded = sizeof(CERT_NAME_VALUE);
1214     if (pbEncoded[1])
1215     {
1216         switch (pbEncoded[0])
1217         {
1218         case ASN_NUMERICSTRING:
1219         case ASN_PRINTABLESTRING:
1220         case ASN_IA5STRING:
1221             if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1222                 bytesNeeded += pbEncoded[1];
1223             break;
1224         }
1225     }
1226     if (!value)
1227     {
1228         *pcbValue = bytesNeeded;
1229         return TRUE;
1230     }
1231     if (*pcbValue < bytesNeeded)
1232     {
1233         *pcbValue = bytesNeeded;
1234         SetLastError(ERROR_MORE_DATA);
1235         return FALSE;
1236     }
1237     *pcbValue = bytesNeeded;
1238     switch (pbEncoded[0])
1239     {
1240     case ASN_NUMERICSTRING:
1241         value->dwValueType = CERT_RDN_NUMERIC_STRING;
1242         break;
1243     case ASN_PRINTABLESTRING:
1244         value->dwValueType = CERT_RDN_PRINTABLE_STRING;
1245         break;
1246     case ASN_IA5STRING:
1247         value->dwValueType = CERT_RDN_IA5_STRING;
1248         break;
1249     }
1250     if (pbEncoded[1])
1251     {
1252         switch (pbEncoded[0])
1253         {
1254         case ASN_NUMERICSTRING:
1255         case ASN_PRINTABLESTRING:
1256         case ASN_IA5STRING:
1257             value->Value.cbData = pbEncoded[1];
1258             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1259                 value->Value.pbData = (BYTE *)pbEncoded + 2;
1260             else
1261             {
1262                 if (!value->Value.pbData)
1263                 {
1264                     SetLastError(CRYPT_E_ASN1_INTERNAL);
1265                     ret = FALSE;
1266                 }
1267                 else
1268                     memcpy(value->Value.pbData, pbEncoded + 2, pbEncoded[1]);
1269             }
1270             break;
1271         }
1272     }
1273     else
1274     {
1275         value->Value.cbData = 0;
1276         value->Value.pbData = NULL;
1277     }
1278     return ret;
1279 }
1280
1281 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
1282  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr,
1283  DWORD *pcbAttr)
1284 {
1285     BOOL ret = TRUE;
1286     DWORD bytesNeeded, size;
1287
1288     /* cbEncoded is an upper bound on the number of bytes, not the actual
1289      * count: check the count for sanity.  It must be at least 6, two for the
1290      * tag and length for the RDN_ATTR, two for the OID, and two for the string.
1291      */
1292     if (cbEncoded < 6 || pbEncoded[1] < 4 || pbEncoded[1] > cbEncoded - 2)
1293     {
1294         SetLastError(CRYPT_E_ASN1_EOD);
1295         return FALSE;
1296     }
1297     if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCE))
1298     {
1299         SetLastError(CRYPT_E_ASN1_BADTAG);
1300         return FALSE;
1301     }
1302     bytesNeeded = sizeof(CERT_RDN_ATTR);
1303     ret = CRYPT_AsnDecodeOid(dwCertEncodingType, pbEncoded + 2,
1304      cbEncoded - 2, dwFlags, NULL, &size);
1305     if (ret)
1306     {
1307         /* ugly: need to know the size of the next element of the sequence,
1308          * so get it directly
1309          */
1310         BYTE objIdLen = pbEncoded[3];
1311
1312         bytesNeeded += size;
1313         /* hack: like encoding, this takes advantage of the fact that the rest
1314          * of the structure is identical to a CERT_NAME_VALUE.
1315          */
1316         ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType, pbEncoded + 4 +
1317          objIdLen, cbEncoded - 4 - objIdLen, dwFlags, NULL, &size);
1318         if (ret)
1319         {
1320             bytesNeeded += size;
1321             if (!attr)
1322                 *pcbAttr = bytesNeeded;
1323             else if (*pcbAttr < bytesNeeded)
1324             {
1325                 *pcbAttr = bytesNeeded;
1326                 SetLastError(ERROR_MORE_DATA);
1327                 ret = FALSE;
1328             }
1329             else
1330             {
1331                 BYTE *originalData = attr->Value.pbData;
1332
1333                 *pcbAttr = bytesNeeded;
1334                 /* strange: decode the value first, because it has a counted
1335                  * size, and we can store the OID after it.  Keep track of the
1336                  * original data pointer, we'll need to know whether it was
1337                  * changed.
1338                  */
1339                 size = bytesNeeded;
1340                 ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType,
1341                  pbEncoded + 4 + objIdLen, cbEncoded - 4 - objIdLen,
1342                  dwFlags, (CERT_NAME_VALUE *)&attr->dwValueType, &size);
1343                 if (ret)
1344                 {
1345                     if (objIdLen)
1346                     {
1347                         /* if the data were copied to the original location,
1348                          * the OID goes after.  Otherwise it goes in the
1349                          * spot originally reserved for the data.
1350                          */
1351                         if (attr->Value.pbData == originalData)
1352                             attr->pszObjId = (LPSTR)(attr->Value.pbData +
1353                              attr->Value.cbData);
1354                         else
1355                             attr->pszObjId = originalData;
1356                         size = bytesNeeded - size;
1357                         ret = CRYPT_AsnDecodeOid(dwCertEncodingType,
1358                          pbEncoded + 2, cbEncoded - 2, dwFlags, attr->pszObjId,
1359                          &size);
1360                     }
1361                     else
1362                         attr->pszObjId = NULL;
1363                 }
1364             }
1365         }
1366     }
1367     return ret;
1368 }
1369
1370 static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
1371  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN *rdn,
1372  DWORD *pcbRdn)
1373 {
1374     BOOL ret = TRUE;
1375     DWORD bytesNeeded, cRDNAttr = 0;
1376
1377     /* cbEncoded is an upper bound on the number of bytes, not the actual
1378      * count: check the count for sanity.
1379      */
1380     if (cbEncoded <= 1 || pbEncoded[1] > cbEncoded - 2)
1381     {
1382         SetLastError(CRYPT_E_ASN1_EOD);
1383         return FALSE;
1384     }
1385     if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SETOF))
1386     {
1387         SetLastError(CRYPT_E_ASN1_BADTAG);
1388         return FALSE;
1389     }
1390     bytesNeeded = sizeof(CERT_RDN);
1391     if (pbEncoded[1])
1392     {
1393         const BYTE *ptr;
1394         DWORD size;
1395
1396         for (ptr = pbEncoded + 2; ret && ptr - pbEncoded - 2 < pbEncoded[1]; )
1397         {
1398             ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1399              cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1400             if (ret)
1401             {
1402                 cRDNAttr++;
1403                 bytesNeeded += size;
1404                 ptr += ptr[1] + 2;
1405             }
1406         }
1407     }
1408     if (ret)
1409     {
1410         if (!rdn)
1411         {
1412             *pcbRdn = bytesNeeded;
1413             return TRUE;
1414         }
1415         if (*pcbRdn < bytesNeeded)
1416         {
1417             *pcbRdn = bytesNeeded;
1418             SetLastError(ERROR_MORE_DATA);
1419             return FALSE;
1420         }
1421         *pcbRdn = bytesNeeded;
1422         rdn->cRDNAttr = cRDNAttr;
1423         if (rdn->cRDNAttr == 0)
1424             rdn->rgRDNAttr = NULL;
1425         else
1426         {
1427             DWORD size, i;
1428             BYTE *nextData;
1429             const BYTE *ptr;
1430
1431             rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn + sizeof(CERT_RDN));
1432             nextData = (BYTE *)rdn->rgRDNAttr +
1433              rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
1434             for (i = 0, ptr = pbEncoded + 2; ret && i < cRDNAttr &&
1435              ptr - pbEncoded - 2 < pbEncoded[1]; i++)
1436             {
1437                 rdn->rgRDNAttr[i].Value.pbData = nextData;
1438                 size = bytesNeeded;
1439                 ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1440                  cbEncoded - (ptr - pbEncoded), dwFlags, &rdn->rgRDNAttr[i],
1441                  &size);
1442                 if (ret)
1443                 {
1444                     bytesNeeded -= size;
1445                     /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the data may not
1446                      * have been copied.
1447                      */
1448                     if (rdn->rgRDNAttr[i].Value.pbData == nextData)
1449                         nextData += rdn->rgRDNAttr[i].Value.cbData;
1450                     /* Ugly: the OID, if copied, is stored in memory after the
1451                      * value, so increment by its string length if it's set and
1452                      * points here.
1453                      */
1454                     if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId == nextData)
1455                         nextData += strlen(rdn->rgRDNAttr[i].pszObjId) + 1;
1456                     ptr += ptr[1] + 2;
1457                 }
1458             }
1459         }
1460     }
1461     return ret;
1462 }
1463
1464 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
1465  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1466  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1467 {
1468     BOOL ret = TRUE;
1469     DWORD bytesNeeded, cRDN = 0;
1470
1471     if (!pbEncoded || !cbEncoded)
1472     {
1473         SetLastError(ERROR_INVALID_PARAMETER);
1474         return FALSE;
1475     }
1476     if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
1477     {
1478         SetLastError(CRYPT_E_ASN1_BADTAG);
1479         return FALSE;
1480     }
1481     if (cbEncoded <= 1)
1482     {
1483         SetLastError(CRYPT_E_ASN1_EOD);
1484         return FALSE;
1485     }
1486     bytesNeeded = sizeof(CERT_NAME_INFO);
1487     if (pbEncoded[1])
1488     {
1489         const BYTE *ptr;
1490         DWORD size;
1491
1492         for (ptr = pbEncoded + 2; ret && ptr - pbEncoded - 2 < pbEncoded[1]; )
1493         {
1494             ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1495              cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1496             if (ret)
1497             {
1498                 cRDN++;
1499                 bytesNeeded += size;
1500                 ptr += ptr[1] + 2;
1501             }
1502         }
1503     }
1504     if (ret)
1505     {
1506         CERT_NAME_INFO *info;
1507
1508         if (!pvStructInfo)
1509         {
1510             *pcbStructInfo = bytesNeeded;
1511             return TRUE;
1512         }
1513         if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1514          pcbStructInfo, bytesNeeded))
1515             return FALSE;
1516         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1517             pvStructInfo = *(BYTE **)pvStructInfo;
1518         info = (CERT_NAME_INFO *)pvStructInfo;
1519         info->cRDN = cRDN;
1520         if (info->cRDN == 0)
1521             info->rgRDN = NULL;
1522         else
1523         {
1524             DWORD size, i;
1525             BYTE *nextData;
1526             const BYTE *ptr;
1527
1528             info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
1529              sizeof(CERT_NAME_INFO));
1530             nextData = (BYTE *)info->rgRDN + info->cRDN * sizeof(CERT_RDN);
1531             for (i = 0, ptr = pbEncoded + 2; ret && i < cRDN &&
1532              ptr - pbEncoded - 2 < pbEncoded[1]; i++)
1533             {
1534                 info->rgRDN[i].rgRDNAttr = (CERT_RDN_ATTR *)nextData;
1535                 size = bytesNeeded;
1536                 ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1537                  cbEncoded - (ptr - pbEncoded), dwFlags, &info->rgRDN[i],
1538                  &size);
1539                 if (ret)
1540                 {
1541                     nextData += size;
1542                     bytesNeeded -= size;
1543                     ptr += ptr[1] + 2;
1544                 }
1545             }
1546         }
1547     }
1548     return ret;
1549 }
1550
1551 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
1552  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1553  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1554 {
1555     int val, i;
1556
1557     if (!pbEncoded || !cbEncoded)
1558     {
1559         SetLastError(CRYPT_E_ASN1_EOD);
1560         return FALSE;
1561     }
1562     if (!pvStructInfo)
1563     {
1564         *pcbStructInfo = sizeof(int);
1565         return TRUE;
1566     }
1567     if (pbEncoded[0] != ASN_INTEGER)
1568     {
1569         SetLastError(CRYPT_E_ASN1_BADTAG);
1570         return FALSE;
1571     }
1572     if (cbEncoded <= 1)
1573     {
1574         SetLastError(CRYPT_E_ASN1_EOD);
1575         return FALSE;
1576     }
1577     if (pbEncoded[1] == 0)
1578     {
1579         SetLastError(CRYPT_E_ASN1_CORRUPT);
1580         return FALSE;
1581     }
1582     if (pbEncoded[1] > sizeof(int))
1583     {
1584         SetLastError(CRYPT_E_ASN1_LARGE);
1585         return FALSE;
1586     }
1587     if (pbEncoded[2] & 0x80)
1588     {
1589         /* initialize to a negative value to sign-extend */
1590         val = -1;
1591     }
1592     else
1593         val = 0;
1594     for (i = 0; i < pbEncoded[1]; i++)
1595     {
1596         val <<= 8;
1597         val |= pbEncoded[2 + i];
1598     }
1599     if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1600      pcbStructInfo, sizeof(int)))
1601         return FALSE;
1602     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1603         pvStructInfo = *(BYTE **)pvStructInfo;
1604     memcpy(pvStructInfo, &val, sizeof(int));
1605     return TRUE;
1606 }
1607
1608 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
1609  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1610  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1611 {
1612     DWORD bytesNeeded;
1613     CRYPT_INTEGER_BLOB *blob;
1614
1615     if (!pbEncoded || !cbEncoded)
1616     {
1617         SetLastError(CRYPT_E_ASN1_EOD);
1618         return FALSE;
1619     }
1620     if (pbEncoded[0] != ASN_INTEGER)
1621     {
1622         SetLastError(CRYPT_E_ASN1_BADTAG);
1623         return FALSE;
1624     }
1625     if (cbEncoded <= 1)
1626     {
1627         SetLastError(CRYPT_E_ASN1_EOD);
1628         return FALSE;
1629     }
1630     if (pbEncoded[1] > cbEncoded)
1631     {
1632         SetLastError(CRYPT_E_ASN1_EOD);
1633         return FALSE;
1634     }
1635     bytesNeeded = pbEncoded[1] + sizeof(CRYPT_INTEGER_BLOB);
1636     if (!pvStructInfo)
1637     {
1638         *pcbStructInfo = bytesNeeded;
1639         return TRUE;
1640     }
1641     if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1642      pcbStructInfo, bytesNeeded))
1643         return FALSE;
1644     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1645         pvStructInfo = *(BYTE **)pvStructInfo;
1646     blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
1647     blob->cbData = pbEncoded[1];
1648     blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_INTEGER_BLOB);
1649     if (blob->cbData)
1650     {
1651         DWORD i;
1652
1653         for (i = 0; i < blob->cbData; i++)
1654             blob->pbData[i] = *(pbEncoded + 2 + pbEncoded[1] - i - 1);
1655     }
1656     return TRUE;
1657 }
1658
1659 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
1660  do { \
1661     BYTE i; \
1662  \
1663     (word) = 0; \
1664     for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
1665     { \
1666         if (!isdigit(*(pbEncoded))) \
1667         { \
1668             SetLastError(CRYPT_E_ASN1_CORRUPT); \
1669             return FALSE; \
1670         } \
1671         (word) *= 10; \
1672         (word) += *(pbEncoded)++ - '0'; \
1673     } \
1674  } while (0)
1675
1676 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
1677  SYSTEMTIME *sysTime)
1678 {
1679     BOOL ret = TRUE;
1680
1681     if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
1682     {
1683         WORD hours, minutes = 0;
1684         BYTE sign = *pbEncoded++;
1685
1686         len--;
1687         CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
1688         if (hours >= 24)
1689         {
1690             SetLastError(CRYPT_E_ASN1_CORRUPT);
1691             ret = FALSE;
1692             goto end;
1693         }
1694         if (len >= 2)
1695         {
1696             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
1697             if (minutes >= 60)
1698             {
1699                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1700                 ret = FALSE;
1701                 goto end;
1702             }
1703         }
1704         if (sign == '+')
1705         {
1706             sysTime->wHour += hours;
1707             sysTime->wMinute += minutes;
1708         }
1709         else
1710         {
1711             if (hours > sysTime->wHour)
1712             {
1713                 sysTime->wDay--;
1714                 sysTime->wHour = 24 - (hours - sysTime->wHour);
1715             }
1716             else
1717                 sysTime->wHour -= hours;
1718             if (minutes > sysTime->wMinute)
1719             {
1720                 sysTime->wHour--;
1721                 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
1722             }
1723             else
1724                 sysTime->wMinute -= minutes;
1725         }
1726     }
1727 end:
1728     return ret;
1729 }
1730
1731 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
1732  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1733  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1734 {
1735     SYSTEMTIME sysTime = { 0 };
1736     BYTE len;
1737     BOOL ret = TRUE;
1738
1739     if (!pbEncoded || !cbEncoded)
1740     {
1741         SetLastError(ERROR_INVALID_PARAMETER);
1742         return FALSE;
1743     }
1744     if (!pvStructInfo)
1745     {
1746         *pcbStructInfo = sizeof(FILETIME);
1747         return TRUE;
1748     }
1749     if (pbEncoded[0] != ASN_UTCTIME)
1750     {
1751         SetLastError(CRYPT_E_ASN1_BADTAG);
1752         return FALSE;
1753     }
1754     if (cbEncoded <= 1)
1755     {
1756         SetLastError(CRYPT_E_ASN1_EOD);
1757         return FALSE;
1758     }
1759     len = pbEncoded[1];
1760     /* FIXME: magic # */
1761     if (len < 10)
1762     {
1763         SetLastError(CRYPT_E_ASN1_CORRUPT);
1764         return FALSE;
1765     }
1766     pbEncoded += 2;
1767     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
1768     if (sysTime.wYear >= 50)
1769         sysTime.wYear += 1900;
1770     else
1771         sysTime.wYear += 2000;
1772     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
1773     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
1774     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
1775     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
1776     if (len > 0)
1777     {
1778         if (len >= 2 && isdigit(*pbEncoded) && isdigit(*(pbEncoded + 1)))
1779             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
1780         else if (isdigit(*pbEncoded))
1781             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, sysTime.wSecond);
1782         ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
1783     }
1784     if (ret)
1785     {
1786         if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1787          pcbStructInfo, sizeof(FILETIME)))
1788             ret = FALSE;
1789         else
1790         {
1791             if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1792                 pvStructInfo = *(BYTE **)pvStructInfo;
1793             ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
1794         }
1795     }
1796     return ret;
1797 }
1798
1799 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
1800  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1801  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1802 {
1803     SYSTEMTIME sysTime = { 0 };
1804     BYTE len;
1805     BOOL ret = TRUE;
1806
1807     if (!pbEncoded || !cbEncoded)
1808     {
1809         SetLastError(ERROR_INVALID_PARAMETER);
1810         return FALSE;
1811     }
1812     if (!pvStructInfo)
1813     {
1814         *pcbStructInfo = sizeof(FILETIME);
1815         return TRUE;
1816     }
1817     if (pbEncoded[0] != ASN_GENERALTIME)
1818     {
1819         SetLastError(CRYPT_E_ASN1_BADTAG);
1820         return FALSE;
1821     }
1822     if (cbEncoded <= 1)
1823     {
1824         SetLastError(CRYPT_E_ASN1_EOD);
1825         return FALSE;
1826     }
1827     len = pbEncoded[1];
1828     /* FIXME: magic # */
1829     if (len < 10)
1830     {
1831         SetLastError(CRYPT_E_ASN1_CORRUPT);
1832         return FALSE;
1833     }
1834     pbEncoded += 2;
1835     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
1836     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
1837     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
1838     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
1839     if (len > 0)
1840     {
1841         CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
1842         if (len > 0)
1843             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
1844         if (len > 0 && (*pbEncoded == '.' || *pbEncoded == ','))
1845         {
1846             BYTE digits;
1847
1848             pbEncoded++;
1849             len--;
1850             digits = min(len, 3); /* workaround macro weirdness */
1851             CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
1852              sysTime.wMilliseconds);
1853         }
1854         ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
1855     }
1856     if (ret)
1857     {
1858         if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1859          pcbStructInfo, sizeof(FILETIME)))
1860             ret = FALSE;
1861         else
1862         {
1863             if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1864                 pvStructInfo = *(BYTE **)pvStructInfo;
1865             ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
1866         }
1867     }
1868     return ret;
1869 }
1870
1871 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
1872  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1873  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1874 {
1875     BOOL ret;
1876
1877     if (!pbEncoded || !cbEncoded)
1878     {
1879         SetLastError(ERROR_INVALID_PARAMETER);
1880         return FALSE;
1881     }
1882     if (!pvStructInfo)
1883     {
1884         *pcbStructInfo = sizeof(FILETIME);
1885         return TRUE;
1886     }
1887
1888     if (pbEncoded[0] == ASN_UTCTIME)
1889         ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
1890          pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
1891          pcbStructInfo);
1892     else if (pbEncoded[0] == ASN_GENERALTIME)
1893         ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
1894          lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
1895          pvStructInfo, pcbStructInfo);
1896     else
1897     {
1898         SetLastError(CRYPT_E_ASN1_BADTAG);
1899         ret = FALSE;
1900     }
1901     return ret;
1902 }
1903
1904 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
1905  DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
1906
1907 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1908  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1909  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1910 {
1911     BOOL ret = FALSE;
1912     HMODULE lib = NULL;
1913     CryptDecodeObjectExFunc decodeFunc = NULL;
1914
1915     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p): semi-stub\n",
1916      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1917      "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
1918      pvStructInfo, pcbStructInfo);
1919
1920     if (!pvStructInfo && !pcbStructInfo)
1921     {
1922         SetLastError(ERROR_INVALID_PARAMETER);
1923         return FALSE;
1924     }
1925     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
1926      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
1927     {
1928         SetLastError(ERROR_FILE_NOT_FOUND);
1929         return FALSE;
1930     }
1931
1932     SetLastError(NOERROR);
1933     if (!HIWORD(lpszStructType))
1934     {
1935         switch (LOWORD(lpszStructType))
1936         {
1937         case (WORD)X509_NAME:
1938             decodeFunc = CRYPT_AsnDecodeName;
1939             break;
1940         case (WORD)X509_INTEGER:
1941             decodeFunc = CRYPT_AsnDecodeInt;
1942             break;
1943         case (WORD)X509_MULTI_BYTE_INTEGER:
1944             decodeFunc = CRYPT_AsnDecodeInteger;
1945             break;
1946         case (WORD)X509_CHOICE_OF_TIME:
1947             decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
1948             break;
1949         case (WORD)PKCS_UTC_TIME:
1950             decodeFunc = CRYPT_AsnDecodeUtcTime;
1951             break;
1952         default:
1953             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1954         }
1955     }
1956     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1957         decodeFunc = CRYPT_AsnDecodeUtcTime;
1958     if (!decodeFunc)
1959         decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1960          lpszStructType, "CryptDecodeObjectEx", &lib);
1961     if (decodeFunc)
1962         ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
1963          cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
1964     else
1965         SetLastError(ERROR_FILE_NOT_FOUND);
1966     if (lib)
1967         FreeLibrary(lib);
1968     return ret;
1969 }