Fixes for -Wmissing-declaration and -Wwrite-string warnings.
[wine] / dlls / crypt32 / encode.c
1 /*
2  * Copyright 2002 Mike McCormack for CodeWeavers
3  * Copyright 2005 Juan Lang
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Lesser General Public
7  * License as published by the Free Software Foundation; either
8  * version 2.1 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Lesser General Public License for more details.
14  *
15  * You should have received a copy of the GNU Lesser General Public
16  * License along with this library; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19 #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_AsnEncodeUtcTime(DWORD dwCertEncodingType,
775  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
776  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
777 {
778     SYSTEMTIME sysTime;
779     /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
780      * temporary buffer because the output buffer is not NULL-terminated.
781      */
782     char buf[16];
783     static const DWORD bytesNeeded = sizeof(buf) - 1;
784
785     if (!pvStructInfo)
786     {
787         SetLastError(STATUS_ACCESS_VIOLATION);
788         return FALSE;
789     }
790     /* Sanity check the year, this is a two-digit year format */
791     if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
792         return FALSE;
793     if (sysTime.wYear < 1950 || sysTime.wYear > 2050)
794     {
795         SetLastError(CRYPT_E_BAD_ENCODE);
796         return FALSE;
797     }
798     if (!pbEncoded)
799     {
800         *pcbEncoded = bytesNeeded;
801         return TRUE;
802     }
803     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
804      bytesNeeded))
805         return FALSE;
806     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
807         pbEncoded = *(BYTE **)pbEncoded;
808     buf[0] = ASN_UTCTIME;
809     buf[1] = bytesNeeded - 2;
810     snprintf(buf + 2, sizeof(buf) - 2, "%02d%02d%02d%02d%02d%02dZ",
811      sysTime.wYear >= 2000 ? sysTime.wYear - 2000 : sysTime.wYear - 1900,
812      sysTime.wDay, sysTime.wMonth, sysTime.wHour, sysTime.wMinute,
813      sysTime.wSecond);
814     memcpy(pbEncoded, buf, bytesNeeded);
815     return TRUE;
816 }
817
818 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
819  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
820  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
821 {
822     SYSTEMTIME sysTime;
823     /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
824      * temporary buffer because the output buffer is not NULL-terminated.
825      */
826     char buf[18];
827     static const DWORD bytesNeeded = sizeof(buf) - 1;
828
829     if (!pvStructInfo)
830     {
831         SetLastError(STATUS_ACCESS_VIOLATION);
832         return FALSE;
833     }
834     if (!pbEncoded)
835     {
836         *pcbEncoded = bytesNeeded;
837         return TRUE;
838     }
839     if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
840         return FALSE;
841     if (!CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded, pcbEncoded,
842      bytesNeeded))
843         return FALSE;
844     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
845         pbEncoded = *(BYTE **)pbEncoded;
846     buf[0] = ASN_GENERALTIME;
847     buf[1] = bytesNeeded - 2;
848     snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
849      sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
850      sysTime.wMinute, sysTime.wSecond);
851     memcpy(pbEncoded, buf, bytesNeeded);
852     return TRUE;
853 }
854
855 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
856  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
857  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
858 {
859     SYSTEMTIME sysTime;
860     BOOL ret;
861
862     if (!pvStructInfo)
863     {
864         SetLastError(STATUS_ACCESS_VIOLATION);
865         return FALSE;
866     }
867     /* Check the year, if it's in the UTCTime range call that encode func */
868     if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
869         return FALSE;
870     if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
871         ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
872          pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
873     else
874         ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
875          lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
876          pcbEncoded);
877     return ret;
878 }
879
880 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
881  DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
882
883 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
884  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
885  BYTE *pbEncoded, DWORD *pcbEncoded)
886 {
887     BOOL ret = FALSE;
888     HMODULE lib = NULL;
889     CryptEncodeObjectExFunc encodeFunc = NULL;
890
891     TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p): semi-stub\n",
892      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
893      "(integer value)", pvStructInfo, dwFlags, pEncodePara, pbEncoded,
894      pcbEncoded);
895
896     if (!pbEncoded && !pcbEncoded)
897     {
898         SetLastError(ERROR_INVALID_PARAMETER);
899         return FALSE;
900     }
901     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
902      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
903     {
904         SetLastError(ERROR_FILE_NOT_FOUND);
905         return FALSE;
906     }
907
908     SetLastError(NOERROR);
909     if (!HIWORD(lpszStructType))
910     {
911         switch (LOWORD(lpszStructType))
912         {
913         case (WORD)X509_NAME:
914             encodeFunc = CRYPT_AsnEncodeName;
915             break;
916         case (WORD)X509_INTEGER:
917             encodeFunc = CRYPT_AsnEncodeInt;
918             break;
919         case (WORD)X509_CHOICE_OF_TIME:
920             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
921             break;
922         case (WORD)PKCS_UTC_TIME:
923             encodeFunc = CRYPT_AsnEncodeUtcTime;
924             break;
925         default:
926             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
927         }
928     }
929     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
930         encodeFunc = CRYPT_AsnEncodeUtcTime;
931     if (!encodeFunc)
932         encodeFunc = (CryptEncodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
933          lpszStructType, "CryptEncodeObjectEx", &lib);
934     if (encodeFunc)
935         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
936          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
937     else
938         SetLastError(ERROR_FILE_NOT_FOUND);
939     if (lib)
940         FreeLibrary(lib);
941     return ret;
942 }
943
944 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
945  DWORD, DWORD, void *, DWORD *);
946
947 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
948  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
949  DWORD *pcbStructInfo)
950 {
951     BOOL ret = FALSE;
952     HMODULE lib;
953     CryptDecodeObjectFunc pCryptDecodeObject;
954
955     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n",
956      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
957      "(integer value)", pbEncoded, cbEncoded, dwFlags, pvStructInfo,
958      pcbStructInfo);
959
960     if (!pvStructInfo && !pcbStructInfo)
961     {
962         SetLastError(ERROR_INVALID_PARAMETER);
963         return FALSE;
964     }
965
966     /* Try registered DLL first.. */
967     pCryptDecodeObject =
968      (CryptDecodeObjectFunc)CRYPT_GetFunc(dwCertEncodingType,
969      lpszStructType, "CryptDecodeObject", &lib);
970     if (pCryptDecodeObject)
971     {
972         ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
973          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
974         FreeLibrary(lib);
975     }
976     else
977     {
978         /* If not, use CryptDecodeObjectEx */
979         ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
980          cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
981     }
982     return ret;
983 }
984
985 /* Helper function to check *pcbStructInfo, set it to the required size, and
986  * optionally to allocate memory.  Assumes pvStructInfo is not NULL.
987  * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
988  * pointer to the newly allocated memory.
989  */
990 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
991  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
992  DWORD bytesNeeded)
993 {
994     BOOL ret = TRUE;
995
996     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
997     {
998         if (pDecodePara && pDecodePara->pfnAlloc)
999             *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
1000         else
1001             *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
1002         if (!*(BYTE **)pvStructInfo)
1003             ret = FALSE;
1004         else
1005             *pcbStructInfo = bytesNeeded;
1006     }
1007     else if (*pcbStructInfo < bytesNeeded)
1008     {
1009         *pcbStructInfo = bytesNeeded;
1010         SetLastError(ERROR_MORE_DATA);
1011         ret = FALSE;
1012     }
1013     return ret;
1014 }
1015
1016 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_FLAG. */
1017 static BOOL WINAPI CRYPT_AsnDecodeOid(DWORD dwCertEncodingType,
1018  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, LPSTR pszObjId,
1019  DWORD *pcbObjId)
1020 {
1021     BOOL ret = TRUE;
1022     DWORD bytesNeeded;
1023
1024     /* cbEncoded is an upper bound on the number of bytes, not the actual
1025      * count: check the count for sanity.
1026      */
1027     if (cbEncoded <= 1 || pbEncoded[1] > cbEncoded - 2)
1028     {
1029         SetLastError(CRYPT_E_ASN1_EOD);
1030         return FALSE;
1031     }
1032     if (pbEncoded[0] != ASN_OBJECTIDENTIFIER)
1033     {
1034         SetLastError(CRYPT_E_ASN1_BADTAG);
1035         return FALSE;
1036     }
1037     if (pbEncoded[1])
1038     {
1039         /* The largest possible string for the first two components is 2.175
1040          * (= 2 * 40 + 175 = 255), so this is big enough.
1041          */
1042         char firstTwo[6];
1043         const BYTE *ptr;
1044
1045         snprintf(firstTwo, sizeof(firstTwo), "%d.%d", pbEncoded[2] / 40,
1046          pbEncoded[2] - (pbEncoded[2] / 40) * 40);
1047         bytesNeeded = strlen(firstTwo) + 1;
1048         for (ptr = pbEncoded + 3; ret && ptr - pbEncoded - 2 < pbEncoded[1]; )
1049         {
1050             /* large enough for ".4000000" */
1051             char str[9];
1052             int val = 0;
1053
1054             while (ptr - pbEncoded - 2 < pbEncoded[1] && (*ptr & 0x80))
1055             {
1056                 val <<= 7;
1057                 val |= *ptr & 0x7f;
1058                 ptr++;
1059             }
1060             if (ptr - pbEncoded - 2 >= pbEncoded[1] || (*ptr & 0x80))
1061             {
1062                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1063                 ret = FALSE;
1064             }
1065             else
1066             {
1067                 val <<= 7;
1068                 val |= *ptr++;
1069                 snprintf(str, sizeof(str), ".%d", val);
1070                 bytesNeeded += strlen(str);
1071             }
1072         }
1073         if (!pszObjId)
1074             *pcbObjId = bytesNeeded;
1075         else if (*pcbObjId < bytesNeeded)
1076         {
1077             *pcbObjId = bytesNeeded;
1078             SetLastError(ERROR_MORE_DATA);
1079             ret = FALSE;
1080         }
1081         else
1082         {
1083             sprintf(pszObjId, "%d.%d", pbEncoded[2] / 40,
1084              pbEncoded[2] - (pbEncoded[2] / 40) * 40);
1085             pszObjId += strlen(pszObjId);
1086             for (ptr = pbEncoded + 3; ret && ptr - pbEncoded - 2 < pbEncoded[1];
1087              )
1088             {
1089                 int val = 0;
1090
1091                 while (ptr - pbEncoded - 2 < pbEncoded[1] && (*ptr & 0x80))
1092                 {
1093                     val <<= 7;
1094                     val |= *ptr & 0x7f;
1095                     ptr++;
1096                 }
1097                 val <<= 7;
1098                 val |= *ptr++;
1099                 sprintf(pszObjId, ".%d", val);
1100                 pszObjId += strlen(pszObjId);
1101             }
1102         }
1103     }
1104     else
1105         bytesNeeded = 0;
1106     *pcbObjId = bytesNeeded;
1107     return ret;
1108 }
1109
1110 /* Warning: this assumes the address of value->Value.pbData is already set, in
1111  * order to avoid overwriting memory.  (In some cases, it may change it, if it
1112  * doesn't copy anything to memory.)  Be sure to set it correctly!
1113  */
1114 static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
1115  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_NAME_VALUE *value,
1116  DWORD *pcbValue)
1117 {
1118     DWORD bytesNeeded;
1119     BOOL ret = TRUE;
1120
1121     /* cbEncoded is an upper bound on the number of bytes, not the actual
1122      * count: check the count for sanity.
1123      */
1124     if (cbEncoded <= 1 || pbEncoded[1] > cbEncoded - 2)
1125     {
1126         SetLastError(CRYPT_E_ASN1_EOD);
1127         return FALSE;
1128     }
1129     switch (pbEncoded[0])
1130     {
1131     case ASN_NUMERICSTRING:
1132     case ASN_PRINTABLESTRING:
1133     case ASN_IA5STRING:
1134         break;
1135     default:
1136         FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
1137         SetLastError(OSS_UNIMPLEMENTED);
1138         return FALSE;
1139     }
1140     bytesNeeded = sizeof(CERT_NAME_VALUE);
1141     if (pbEncoded[1])
1142     {
1143         switch (pbEncoded[0])
1144         {
1145         case ASN_NUMERICSTRING:
1146         case ASN_PRINTABLESTRING:
1147         case ASN_IA5STRING:
1148             if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
1149                 bytesNeeded += pbEncoded[1];
1150             break;
1151         }
1152     }
1153     if (!value)
1154     {
1155         *pcbValue = bytesNeeded;
1156         return TRUE;
1157     }
1158     if (*pcbValue < bytesNeeded)
1159     {
1160         *pcbValue = bytesNeeded;
1161         SetLastError(ERROR_MORE_DATA);
1162         return FALSE;
1163     }
1164     *pcbValue = bytesNeeded;
1165     switch (pbEncoded[0])
1166     {
1167     case ASN_NUMERICSTRING:
1168         value->dwValueType = CERT_RDN_NUMERIC_STRING;
1169         break;
1170     case ASN_PRINTABLESTRING:
1171         value->dwValueType = CERT_RDN_PRINTABLE_STRING;
1172         break;
1173     case ASN_IA5STRING:
1174         value->dwValueType = CERT_RDN_IA5_STRING;
1175         break;
1176     }
1177     if (pbEncoded[1])
1178     {
1179         switch (pbEncoded[0])
1180         {
1181         case ASN_NUMERICSTRING:
1182         case ASN_PRINTABLESTRING:
1183         case ASN_IA5STRING:
1184             value->Value.cbData = pbEncoded[1];
1185             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
1186                 value->Value.pbData = (BYTE *)pbEncoded + 2;
1187             else
1188             {
1189                 if (!value->Value.pbData)
1190                 {
1191                     SetLastError(CRYPT_E_ASN1_INTERNAL);
1192                     ret = FALSE;
1193                 }
1194                 else
1195                     memcpy(value->Value.pbData, pbEncoded + 2, pbEncoded[1]);
1196             }
1197             break;
1198         }
1199     }
1200     else
1201     {
1202         value->Value.cbData = 0;
1203         value->Value.pbData = NULL;
1204     }
1205     return ret;
1206 }
1207
1208 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
1209  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN_ATTR *attr,
1210  DWORD *pcbAttr)
1211 {
1212     BOOL ret = TRUE;
1213     DWORD bytesNeeded, size;
1214
1215     /* cbEncoded is an upper bound on the number of bytes, not the actual
1216      * count: check the count for sanity.  It must be at least 6, two for the
1217      * tag and length for the RDN_ATTR, two for the OID, and two for the string.
1218      */
1219     if (cbEncoded < 6 || pbEncoded[1] < 4 || pbEncoded[1] > cbEncoded - 2)
1220     {
1221         SetLastError(CRYPT_E_ASN1_EOD);
1222         return FALSE;
1223     }
1224     if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCE))
1225     {
1226         SetLastError(CRYPT_E_ASN1_BADTAG);
1227         return FALSE;
1228     }
1229     bytesNeeded = sizeof(CERT_RDN_ATTR);
1230     ret = CRYPT_AsnDecodeOid(dwCertEncodingType, pbEncoded + 2,
1231      cbEncoded - 2, dwFlags, NULL, &size);
1232     if (ret)
1233     {
1234         /* ugly: need to know the size of the next element of the sequence,
1235          * so get it directly
1236          */
1237         BYTE objIdLen = pbEncoded[3];
1238
1239         bytesNeeded += size;
1240         /* hack: like encoding, this takes advantage of the fact that the rest
1241          * of the structure is identical to a CERT_NAME_VALUE.
1242          */
1243         ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType, pbEncoded + 4 +
1244          objIdLen, cbEncoded - 4 - objIdLen, dwFlags, NULL, &size);
1245         if (ret)
1246         {
1247             bytesNeeded += size;
1248             if (!attr)
1249                 *pcbAttr = bytesNeeded;
1250             else if (*pcbAttr < bytesNeeded)
1251             {
1252                 *pcbAttr = bytesNeeded;
1253                 SetLastError(ERROR_MORE_DATA);
1254                 ret = FALSE;
1255             }
1256             else
1257             {
1258                 BYTE *originalData = attr->Value.pbData;
1259
1260                 *pcbAttr = bytesNeeded;
1261                 /* strange: decode the value first, because it has a counted
1262                  * size, and we can store the OID after it.  Keep track of the
1263                  * original data pointer, we'll need to know whether it was
1264                  * changed.
1265                  */
1266                 size = bytesNeeded;
1267                 ret = CRYPT_AsnDecodeNameValue(dwCertEncodingType,
1268                  pbEncoded + 4 + objIdLen, cbEncoded - 4 - objIdLen,
1269                  dwFlags, (CERT_NAME_VALUE *)&attr->dwValueType, &size);
1270                 if (ret)
1271                 {
1272                     if (objIdLen)
1273                     {
1274                         /* if the data were copied to the original location,
1275                          * the OID goes after.  Otherwise it goes in the
1276                          * spot originally reserved for the data.
1277                          */
1278                         if (attr->Value.pbData == originalData)
1279                             attr->pszObjId = (LPSTR)(attr->Value.pbData +
1280                              attr->Value.cbData);
1281                         else
1282                             attr->pszObjId = originalData;
1283                         size = bytesNeeded - size;
1284                         ret = CRYPT_AsnDecodeOid(dwCertEncodingType,
1285                          pbEncoded + 2, cbEncoded - 2, dwFlags, attr->pszObjId,
1286                          &size);
1287                     }
1288                     else
1289                         attr->pszObjId = NULL;
1290                 }
1291             }
1292         }
1293     }
1294     return ret;
1295 }
1296
1297 static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
1298  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, CERT_RDN *rdn,
1299  DWORD *pcbRdn)
1300 {
1301     BOOL ret = TRUE;
1302     DWORD bytesNeeded, cRDNAttr = 0;
1303
1304     /* cbEncoded is an upper bound on the number of bytes, not the actual
1305      * count: check the count for sanity.
1306      */
1307     if (cbEncoded <= 1 || pbEncoded[1] > cbEncoded - 2)
1308     {
1309         SetLastError(CRYPT_E_ASN1_EOD);
1310         return FALSE;
1311     }
1312     if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SETOF))
1313     {
1314         SetLastError(CRYPT_E_ASN1_BADTAG);
1315         return FALSE;
1316     }
1317     bytesNeeded = sizeof(CERT_RDN);
1318     if (pbEncoded[1])
1319     {
1320         const BYTE *ptr;
1321         DWORD size;
1322
1323         for (ptr = pbEncoded + 2; ret && ptr - pbEncoded - 2 < pbEncoded[1]; )
1324         {
1325             ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1326              cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1327             if (ret)
1328             {
1329                 cRDNAttr++;
1330                 bytesNeeded += size;
1331                 ptr += ptr[1] + 2;
1332             }
1333         }
1334     }
1335     if (ret)
1336     {
1337         if (!rdn)
1338         {
1339             *pcbRdn = bytesNeeded;
1340             return TRUE;
1341         }
1342         if (*pcbRdn < bytesNeeded)
1343         {
1344             *pcbRdn = bytesNeeded;
1345             SetLastError(ERROR_MORE_DATA);
1346             return FALSE;
1347         }
1348         *pcbRdn = bytesNeeded;
1349         rdn->cRDNAttr = cRDNAttr;
1350         if (rdn->cRDNAttr == 0)
1351             rdn->rgRDNAttr = NULL;
1352         else
1353         {
1354             DWORD size, i;
1355             BYTE *nextData;
1356             const BYTE *ptr;
1357
1358             rdn->rgRDNAttr = (CERT_RDN_ATTR *)((BYTE *)rdn + sizeof(CERT_RDN));
1359             nextData = (BYTE *)rdn->rgRDNAttr +
1360              rdn->cRDNAttr * sizeof(CERT_RDN_ATTR);
1361             for (i = 0, ptr = pbEncoded + 2; ret && i < cRDNAttr &&
1362              ptr - pbEncoded - 2 < pbEncoded[1]; i++)
1363             {
1364                 rdn->rgRDNAttr[i].Value.pbData = nextData;
1365                 size = bytesNeeded;
1366                 ret = CRYPT_AsnDecodeRdnAttr(dwCertEncodingType, ptr,
1367                  cbEncoded - (ptr - pbEncoded), dwFlags, &rdn->rgRDNAttr[i],
1368                  &size);
1369                 if (ret)
1370                 {
1371                     bytesNeeded -= size;
1372                     /* If dwFlags & CRYPT_DECODE_NOCOPY_FLAG, the data may not
1373                      * have been copied.
1374                      */
1375                     if (rdn->rgRDNAttr[i].Value.pbData == nextData)
1376                         nextData += rdn->rgRDNAttr[i].Value.cbData;
1377                     /* Ugly: the OID, if copied, is stored in memory after the
1378                      * value, so increment by its string length if it's set and
1379                      * points here.
1380                      */
1381                     if ((const BYTE *)rdn->rgRDNAttr[i].pszObjId == nextData)
1382                         nextData += strlen(rdn->rgRDNAttr[i].pszObjId) + 1;
1383                     ptr += ptr[1] + 2;
1384                 }
1385             }
1386         }
1387     }
1388     return ret;
1389 }
1390
1391 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
1392  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1393  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1394 {
1395     BOOL ret = TRUE;
1396     DWORD bytesNeeded, cRDN = 0;
1397
1398     if (!pbEncoded || !cbEncoded)
1399     {
1400         SetLastError(ERROR_INVALID_PARAMETER);
1401         return FALSE;
1402     }
1403     if (pbEncoded[0] != (ASN_CONSTRUCTOR | ASN_SEQUENCEOF))
1404     {
1405         SetLastError(CRYPT_E_ASN1_BADTAG);
1406         return FALSE;
1407     }
1408     if (cbEncoded <= 1)
1409     {
1410         SetLastError(CRYPT_E_ASN1_EOD);
1411         return FALSE;
1412     }
1413     bytesNeeded = sizeof(CERT_NAME_INFO);
1414     if (pbEncoded[1])
1415     {
1416         const BYTE *ptr;
1417         DWORD size;
1418
1419         for (ptr = pbEncoded + 2; ret && ptr - pbEncoded - 2 < pbEncoded[1]; )
1420         {
1421             ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1422              cbEncoded - (ptr - pbEncoded), dwFlags, NULL, &size);
1423             if (ret)
1424             {
1425                 cRDN++;
1426                 bytesNeeded += size;
1427                 ptr += ptr[1] + 2;
1428             }
1429         }
1430     }
1431     if (ret)
1432     {
1433         CERT_NAME_INFO *info;
1434
1435         if (!pvStructInfo)
1436         {
1437             *pcbStructInfo = bytesNeeded;
1438             return TRUE;
1439         }
1440         if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1441          pcbStructInfo, bytesNeeded))
1442             return FALSE;
1443         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1444             pvStructInfo = *(BYTE **)pvStructInfo;
1445         info = (CERT_NAME_INFO *)pvStructInfo;
1446         info->cRDN = cRDN;
1447         if (info->cRDN == 0)
1448             info->rgRDN = NULL;
1449         else
1450         {
1451             DWORD size, i;
1452             BYTE *nextData;
1453             const BYTE *ptr;
1454
1455             info->rgRDN = (CERT_RDN *)((BYTE *)pvStructInfo +
1456              sizeof(CERT_NAME_INFO));
1457             nextData = (BYTE *)info->rgRDN + info->cRDN * sizeof(CERT_RDN);
1458             for (i = 0, ptr = pbEncoded + 2; ret && i < cRDN &&
1459              ptr - pbEncoded - 2 < pbEncoded[1]; i++)
1460             {
1461                 info->rgRDN[i].rgRDNAttr = (CERT_RDN_ATTR *)nextData;
1462                 size = bytesNeeded;
1463                 ret = CRYPT_AsnDecodeRdn(dwCertEncodingType, ptr,
1464                  cbEncoded - (ptr - pbEncoded), dwFlags, &info->rgRDN[i],
1465                  &size);
1466                 if (ret)
1467                 {
1468                     nextData += size;
1469                     bytesNeeded -= size;
1470                     ptr += ptr[1] + 2;
1471                 }
1472             }
1473         }
1474     }
1475     return ret;
1476 }
1477
1478 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
1479  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1480  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1481 {
1482     int val, i;
1483
1484     if (!pbEncoded || !cbEncoded)
1485     {
1486         SetLastError(CRYPT_E_ASN1_EOD);
1487         return FALSE;
1488     }
1489     if (!pvStructInfo)
1490     {
1491         *pcbStructInfo = sizeof(int);
1492         return TRUE;
1493     }
1494     if (pbEncoded[0] != ASN_INTEGER)
1495     {
1496         SetLastError(CRYPT_E_ASN1_BADTAG);
1497         return FALSE;
1498     }
1499     if (cbEncoded <= 1)
1500     {
1501         SetLastError(CRYPT_E_ASN1_EOD);
1502         return FALSE;
1503     }
1504     if (pbEncoded[1] == 0)
1505     {
1506         SetLastError(CRYPT_E_ASN1_CORRUPT);
1507         return FALSE;
1508     }
1509     if (pbEncoded[1] > sizeof(int))
1510     {
1511         SetLastError(CRYPT_E_ASN1_LARGE);
1512         return FALSE;
1513     }
1514     if (pbEncoded[2] & 0x80)
1515     {
1516         /* initialize to a negative value to sign-extend */
1517         val = -1;
1518     }
1519     else
1520         val = 0;
1521     for (i = 0; i < pbEncoded[1]; i++)
1522     {
1523         val <<= 8;
1524         val |= pbEncoded[2 + i];
1525     }
1526     if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1527      pcbStructInfo, sizeof(int)))
1528         return FALSE;
1529     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1530         pvStructInfo = *(BYTE **)pvStructInfo;
1531     *pcbStructInfo = sizeof(int);
1532     memcpy(pvStructInfo, &val, sizeof(int));
1533     return TRUE;
1534 }
1535
1536 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
1537  do { \
1538     BYTE i; \
1539  \
1540     (word) = 0; \
1541     for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
1542     { \
1543         if (!isdigit(*(pbEncoded))) \
1544         { \
1545             SetLastError(CRYPT_E_ASN1_CORRUPT); \
1546             return FALSE; \
1547         } \
1548         (word) *= 10; \
1549         (word) += *(pbEncoded)++ - '0'; \
1550     } \
1551  } while (0)
1552
1553 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
1554  SYSTEMTIME *sysTime)
1555 {
1556     BOOL ret = TRUE;
1557
1558     if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
1559     {
1560         WORD hours, minutes = 0;
1561         BYTE sign = *pbEncoded++;
1562
1563         len--;
1564         CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
1565         if (hours >= 24)
1566         {
1567             SetLastError(CRYPT_E_ASN1_CORRUPT);
1568             ret = FALSE;
1569             goto end;
1570         }
1571         if (len >= 2)
1572         {
1573             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
1574             if (minutes >= 60)
1575             {
1576                 SetLastError(CRYPT_E_ASN1_CORRUPT);
1577                 ret = FALSE;
1578                 goto end;
1579             }
1580         }
1581         if (sign == '+')
1582         {
1583             sysTime->wHour += hours;
1584             sysTime->wMinute += minutes;
1585         }
1586         else
1587         {
1588             if (hours > sysTime->wHour)
1589             {
1590                 sysTime->wDay--;
1591                 sysTime->wHour = 24 - (hours - sysTime->wHour);
1592             }
1593             else
1594                 sysTime->wHour -= hours;
1595             if (minutes > sysTime->wMinute)
1596             {
1597                 sysTime->wHour--;
1598                 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
1599             }
1600             else
1601                 sysTime->wMinute -= minutes;
1602         }
1603     }
1604 end:
1605     return ret;
1606 }
1607
1608 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
1609  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1610  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1611 {
1612     SYSTEMTIME sysTime = { 0 };
1613     BYTE len;
1614     BOOL ret = TRUE;
1615
1616     if (!pbEncoded || !cbEncoded)
1617     {
1618         SetLastError(ERROR_INVALID_PARAMETER);
1619         return FALSE;
1620     }
1621     if (!pvStructInfo)
1622     {
1623         *pcbStructInfo = sizeof(FILETIME);
1624         return TRUE;
1625     }
1626     if (pbEncoded[0] != ASN_UTCTIME)
1627     {
1628         SetLastError(CRYPT_E_ASN1_BADTAG);
1629         return FALSE;
1630     }
1631     if (cbEncoded <= 1)
1632     {
1633         SetLastError(CRYPT_E_ASN1_EOD);
1634         return FALSE;
1635     }
1636     len = pbEncoded[1];
1637     /* FIXME: magic # */
1638     if (len < 10)
1639     {
1640         SetLastError(CRYPT_E_ASN1_CORRUPT);
1641         return FALSE;
1642     }
1643     pbEncoded += 2;
1644     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
1645     if (sysTime.wYear >= 50)
1646         sysTime.wYear += 1900;
1647     else
1648         sysTime.wYear += 2000;
1649     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
1650     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
1651     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
1652     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
1653     if (len > 0)
1654     {
1655         if (len >= 2 && isdigit(*pbEncoded) && isdigit(*(pbEncoded + 1)))
1656             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
1657         else if (isdigit(*pbEncoded))
1658             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1, sysTime.wSecond);
1659         ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
1660     }
1661     if (ret)
1662     {
1663         if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1664          pcbStructInfo, sizeof(FILETIME)))
1665             ret = FALSE;
1666         else
1667         {
1668             if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1669                 pvStructInfo = *(BYTE **)pvStructInfo;
1670             *pcbStructInfo = sizeof(FILETIME);
1671             ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
1672         }
1673     }
1674     return ret;
1675 }
1676
1677 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
1678  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1679  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1680 {
1681     SYSTEMTIME sysTime = { 0 };
1682     BYTE len;
1683     BOOL ret = TRUE;
1684
1685     if (!pbEncoded || !cbEncoded)
1686     {
1687         SetLastError(ERROR_INVALID_PARAMETER);
1688         return FALSE;
1689     }
1690     if (!pvStructInfo)
1691     {
1692         *pcbStructInfo = sizeof(FILETIME);
1693         return TRUE;
1694     }
1695     if (pbEncoded[0] != ASN_GENERALTIME)
1696     {
1697         SetLastError(CRYPT_E_ASN1_BADTAG);
1698         return FALSE;
1699     }
1700     if (cbEncoded <= 1)
1701     {
1702         SetLastError(CRYPT_E_ASN1_EOD);
1703         return FALSE;
1704     }
1705     len = pbEncoded[1];
1706     /* FIXME: magic # */
1707     if (len < 10)
1708     {
1709         SetLastError(CRYPT_E_ASN1_CORRUPT);
1710         return FALSE;
1711     }
1712     pbEncoded += 2;
1713     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
1714     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
1715     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
1716     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
1717     if (len > 0)
1718     {
1719         CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
1720         if (len > 0)
1721             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wSecond);
1722         if (len > 0 && (*pbEncoded == '.' || *pbEncoded == ','))
1723         {
1724             BYTE digits;
1725
1726             pbEncoded++;
1727             len--;
1728             digits = min(len, 3); /* workaround macro weirdness */
1729             CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
1730              sysTime.wMilliseconds);
1731         }
1732         ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len, &sysTime);
1733     }
1734     if (ret)
1735     {
1736         if (!CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
1737          pcbStructInfo, sizeof(FILETIME)))
1738             ret = FALSE;
1739         else
1740         {
1741             if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
1742                 pvStructInfo = *(BYTE **)pvStructInfo;
1743             *pcbStructInfo = sizeof(FILETIME);
1744             ret = SystemTimeToFileTime(&sysTime, (FILETIME *)pvStructInfo);
1745         }
1746     }
1747     return ret;
1748 }
1749
1750 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
1751  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1752  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1753 {
1754     BOOL ret;
1755
1756     if (!pbEncoded || !cbEncoded)
1757     {
1758         SetLastError(ERROR_INVALID_PARAMETER);
1759         return FALSE;
1760     }
1761     if (!pvStructInfo)
1762     {
1763         *pcbStructInfo = sizeof(FILETIME);
1764         return TRUE;
1765     }
1766
1767     if (pbEncoded[0] == ASN_UTCTIME)
1768         ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
1769          pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
1770          pcbStructInfo);
1771     else if (pbEncoded[0] == ASN_GENERALTIME)
1772         ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
1773          lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
1774          pvStructInfo, pcbStructInfo);
1775     else
1776     {
1777         SetLastError(CRYPT_E_ASN1_BADTAG);
1778         ret = FALSE;
1779     }
1780     return ret;
1781 }
1782
1783 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
1784  DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
1785
1786 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
1787  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
1788  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
1789 {
1790     BOOL ret = FALSE;
1791     HMODULE lib = NULL;
1792     CryptDecodeObjectExFunc decodeFunc = NULL;
1793
1794     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p): semi-stub\n",
1795      dwCertEncodingType, HIWORD(lpszStructType) ? debugstr_a(lpszStructType) :
1796      "(integer value)", pbEncoded, cbEncoded, dwFlags, pDecodePara,
1797      pvStructInfo, pcbStructInfo);
1798
1799     if (!pvStructInfo && !pcbStructInfo)
1800     {
1801         SetLastError(ERROR_INVALID_PARAMETER);
1802         return FALSE;
1803     }
1804     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
1805      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
1806     {
1807         SetLastError(ERROR_FILE_NOT_FOUND);
1808         return FALSE;
1809     }
1810
1811     SetLastError(NOERROR);
1812     if (!HIWORD(lpszStructType))
1813     {
1814         switch (LOWORD(lpszStructType))
1815         {
1816         case (WORD)X509_NAME:
1817             decodeFunc = CRYPT_AsnDecodeName;
1818             break;
1819         case (WORD)X509_INTEGER:
1820             decodeFunc = CRYPT_AsnDecodeInt;
1821             break;
1822         case (WORD)X509_CHOICE_OF_TIME:
1823             decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
1824             break;
1825         case (WORD)PKCS_UTC_TIME:
1826             decodeFunc = CRYPT_AsnDecodeUtcTime;
1827             break;
1828         default:
1829             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
1830         }
1831     }
1832     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
1833         decodeFunc = CRYPT_AsnDecodeUtcTime;
1834     if (!decodeFunc)
1835         decodeFunc = (CryptDecodeObjectExFunc)CRYPT_GetFunc(dwCertEncodingType,
1836          lpszStructType, "CryptDecodeObjectEx", &lib);
1837     if (decodeFunc)
1838         ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
1839          cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
1840     else
1841         SetLastError(ERROR_FILE_NOT_FOUND);
1842     if (lib)
1843         FreeLibrary(lib);
1844     return ret;
1845 }