ntdll: Implemented IOCTL purge for serial objects.
[wine] / dlls / crypt32 / encode.c
1 /*
2  * Copyright 2005 Juan Lang
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
17  *
18  * This file implements ASN.1 DER encoding and decoding of a limited set of
19  * types.  It isn't a full ASN.1 implementation.  Microsoft implements BER
20  * encoding of many of the basic types in msasn1.dll, but that interface is
21  * undocumented, so I implement them here.
22  *
23  * References:
24  * "A Layman's Guide to a Subset of ASN.1, BER, and DER", by Burton Kaliski
25  * (available online, look for a PDF copy as the HTML versions tend to have
26  * translation errors.)
27  *
28  * RFC3280, http://www.faqs.org/rfcs/rfc3280.html
29  *
30  * MSDN, especially:
31  * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
32  */
33 #include <assert.h>
34 #include <stdarg.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37
38 #define NONAMELESSUNION
39
40 #include "windef.h"
41 #include "winbase.h"
42 #include "excpt.h"
43 #include "wincrypt.h"
44 #include "winreg.h"
45 #include "snmp.h"
46 #include "wine/debug.h"
47 #include "wine/exception.h"
48 #include "crypt32_private.h"
49
50 /* This is a bit arbitrary, but to set some limit: */
51 #define MAX_ENCODED_LEN 0x02000000
52
53 /* a few asn.1 tags we need */
54 #define ASN_BOOL            (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
55 #define ASN_BITSTRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
56 #define ASN_ENUMERATED      (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
57 #define ASN_SETOF           (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
58 #define ASN_NUMERICSTRING   (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
59 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
60 #define ASN_IA5STRING       (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
61 #define ASN_UTCTIME         (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
62 #define ASN_GENERALTIME     (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
63
64 #define ASN_FLAGS_MASK 0xe0
65 #define ASN_TYPE_MASK  0x1f
66
67 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
68
69 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
70  BYTE *, DWORD *);
71 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
72  DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
73 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
74  DWORD, DWORD, void *, DWORD *);
75 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
76  DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
77
78 /* Prototypes for built-in encoders/decoders.  They follow the Ex style
79  * prototypes.  The dwCertEncodingType and lpszStructType are ignored by the
80  * built-in functions, but the parameters are retained to simplify
81  * CryptEncodeObjectEx/CryptDecodeObjectEx, since they must call functions in
82  * external DLLs that follow these signatures.
83  * FIXME: some built-in functions are suitable to be called directly by
84  * CryptEncodeObjectEx/CryptDecodeObjectEx (they implement exception handling
85  * and memory allocation if requested), others are only suitable to be called
86  * internally.  Comment which are which.
87  */
88 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
89  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
90  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
91 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
92  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
93  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
94 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
95  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
96  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
97 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
98  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
99  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
100 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
101  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
102  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
103 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
104  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
105  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
106 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
107  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
108  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
109 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
110  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
111  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
112 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
113  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
114  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
115 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
116  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
117  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
118 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
119  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
120  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
121
122 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
123  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
124  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
125 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
126  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
127  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
128 /* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of
129  * time, doesn't do memory allocation, and doesn't do exception handling.
130  * (This isn't intended to be the externally-called one.)
131  */
132 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
133  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
134  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
135 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
136  DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
137 /* Assumes algo->Parameters.pbData is set ahead of time.  Internal func. */
138 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
139  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
140  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
141 /* Internal function */
142 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
143  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
144  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
145 /* Assumes the CRYPT_DATA_BLOB's pbData member has been initialized */
146 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
147  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
148  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
149 /* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
150  * member has been initialized, doesn't do exception handling, and doesn't do
151  * memory allocation.
152  */
153 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
154  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
155  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
156 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
157  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
158  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
159 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
160  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
161  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
162 /* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
163  * member has been initialized, doesn't do exception handling, and doesn't do
164  * memory allocation.
165  */
166 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
167  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
168  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
169 /* Like CRYPT_AsnDecodeInteger, but unsigned.  */
170 static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
171  DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
172  DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
173  void *pvStructInfo, DWORD *pcbStructInfo);
174
175 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
176  const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
177 {
178     static HCRYPTOIDFUNCSET set = NULL;
179     BOOL ret = FALSE;
180     HCRYPTOIDFUNCADDR hFunc;
181     CryptEncodeObjectFunc pCryptEncodeObject;
182
183     TRACE("(0x%08lx, %s, %p, %p, %p)\n", dwCertEncodingType,
184      debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
185      pcbEncoded);
186
187     if (!pbEncoded && !pcbEncoded)
188     {
189         SetLastError(ERROR_INVALID_PARAMETER);
190         return FALSE;
191     }
192
193     /* Try registered DLL first.. */
194     if (!set)
195         set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_FUNC, 0);
196     CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
197      (void **)&pCryptEncodeObject, &hFunc);
198     if (pCryptEncodeObject)
199     {
200         ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
201          pvStructInfo, pbEncoded, pcbEncoded);
202         CryptFreeOIDFunctionAddress(hFunc, 0);
203     }
204     else
205     {
206         /* If not, use CryptEncodeObjectEx */
207         ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
208          pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
209     }
210     return ret;
211 }
212
213 /* Helper function to check *pcbEncoded, set it to the required size, and
214  * optionally to allocate memory.  Assumes pbEncoded is not NULL.
215  * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
216  * pointer to the newly allocated memory.
217  */
218 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
219  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
220  DWORD bytesNeeded)
221 {
222     BOOL ret = TRUE;
223
224     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
225     {
226         if (pEncodePara && pEncodePara->pfnAlloc)
227             *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
228         else
229             *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
230         if (!*(BYTE **)pbEncoded)
231             ret = FALSE;
232         else
233             *pcbEncoded = bytesNeeded;
234     }
235     else if (bytesNeeded > *pcbEncoded)
236     {
237         *pcbEncoded = bytesNeeded;
238         SetLastError(ERROR_MORE_DATA);
239         ret = FALSE;
240     }
241     return ret;
242 }
243
244 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
245 {
246     DWORD bytesNeeded, significantBytes = 0;
247
248     if (len <= 0x7f)
249         bytesNeeded = 1;
250     else
251     {
252         DWORD temp;
253
254         for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
255          temp <<= 8, significantBytes--)
256             ;
257         bytesNeeded = significantBytes + 1;
258     }
259     if (!pbEncoded)
260     {
261         *pcbEncoded = bytesNeeded;
262         return TRUE;
263     }
264     if (*pcbEncoded < bytesNeeded)
265     {
266         SetLastError(ERROR_MORE_DATA);
267         return FALSE;
268     }
269     if (len <= 0x7f)
270         *pbEncoded = (BYTE)len;
271     else
272     {
273         DWORD i;
274
275         *pbEncoded++ = significantBytes | 0x80;
276         for (i = 0; i < significantBytes; i++)
277         {
278             *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
279             len >>= 8;
280         }
281     }
282     *pcbEncoded = bytesNeeded;
283     return TRUE;
284 }
285
286 struct AsnEncodeSequenceItem
287 {
288     const void             *pvStructInfo;
289     CryptEncodeObjectExFunc encodeFunc;
290     DWORD                   size; /* used during encoding, not for your use */
291 };
292
293 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
294  struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
295  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
296 {
297     BOOL ret;
298     DWORD i, dataLen = 0;
299
300     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", items, cItem, dwFlags, pEncodePara,
301      pbEncoded, *pcbEncoded);
302     for (i = 0, ret = TRUE; ret && i < cItem; i++)
303     {
304         ret = items[i].encodeFunc(dwCertEncodingType, NULL,
305          items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
306          NULL, &items[i].size);
307         /* Some functions propagate their errors through the size */
308         if (!ret)
309             *pcbEncoded = items[i].size;
310         dataLen += items[i].size;
311     }
312     if (ret)
313     {
314         DWORD lenBytes, bytesNeeded;
315
316         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
317         bytesNeeded = 1 + lenBytes + dataLen;
318         if (!pbEncoded)
319             *pcbEncoded = bytesNeeded;
320         else
321         {
322             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
323              pcbEncoded, bytesNeeded)))
324             {
325                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
326                     pbEncoded = *(BYTE **)pbEncoded;
327                 *pbEncoded++ = ASN_SEQUENCE;
328                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
329                 pbEncoded += lenBytes;
330                 for (i = 0; ret && i < cItem; i++)
331                 {
332                     ret = items[i].encodeFunc(dwCertEncodingType, NULL,
333                      items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
334                      NULL, pbEncoded, &items[i].size);
335                     /* Some functions propagate their errors through the size */
336                     if (!ret)
337                         *pcbEncoded = items[i].size;
338                     pbEncoded += items[i].size;
339                 }
340             }
341         }
342     }
343     TRACE("returning %d (%08lx)\n", ret, GetLastError());
344     return ret;
345 }
346
347 struct AsnConstructedItem
348 {
349     BYTE                    tag;
350     const void             *pvStructInfo;
351     CryptEncodeObjectExFunc encodeFunc;
352 };
353
354 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
355  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
356  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
357 {
358     BOOL ret;
359     const struct AsnConstructedItem *item =
360      (const struct AsnConstructedItem *)pvStructInfo;
361     DWORD len;
362
363     if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
364      item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
365     {
366         DWORD dataLen, bytesNeeded;
367
368         CRYPT_EncodeLen(len, NULL, &dataLen);
369         bytesNeeded = 1 + dataLen + len;
370         if (!pbEncoded)
371             *pcbEncoded = bytesNeeded;
372         else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
373          pbEncoded, pcbEncoded, bytesNeeded)))
374         {
375             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
376                 pbEncoded = *(BYTE **)pbEncoded;
377             *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
378             CRYPT_EncodeLen(len, pbEncoded, &dataLen);
379             pbEncoded += dataLen;
380             ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
381              item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
382              pbEncoded, &len);
383             if (!ret)
384             {
385                 /* Some functions propagate their errors through the size */
386                 *pcbEncoded = len;
387             }
388         }
389     }
390     else
391     {
392         /* Some functions propagate their errors through the size */
393         *pcbEncoded = len;
394     }
395     return ret;
396 }
397
398 struct AsnEncodeTagSwappedItem
399 {
400     BYTE                    tag;
401     const void             *pvStructInfo;
402     CryptEncodeObjectExFunc encodeFunc;
403 };
404
405 /* Sort of a wacky hack, it encodes something using the struct
406  * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag
407  * given in the struct AsnEncodeTagSwappedItem.
408  */
409 static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
410  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
411  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
412 {
413     BOOL ret;
414     const struct AsnEncodeTagSwappedItem *item =
415      (const struct AsnEncodeTagSwappedItem *)pvStructInfo;
416
417     ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
418      item->pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
419     if (ret && pbEncoded)
420         *pbEncoded = item->tag;
421     return ret;
422 }
423
424 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
425  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
426  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
427 {
428     const DWORD *ver = (const DWORD *)pvStructInfo;
429     BOOL ret;
430
431     /* CERT_V1 is not encoded */
432     if (*ver == CERT_V1)
433     {
434         *pcbEncoded = 0;
435         ret = TRUE;
436     }
437     else
438     {
439         struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
440
441         ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
442          &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
443     }
444     return ret;
445 }
446
447 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
448  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
449  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
450 {
451     const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
452     BOOL ret;
453
454     if (!pbEncoded)
455     {
456         *pcbEncoded = blob->cbData;
457         ret = TRUE;
458     }
459     else if (*pcbEncoded < blob->cbData)
460     {
461         *pcbEncoded = blob->cbData;
462         SetLastError(ERROR_MORE_DATA);
463         ret = FALSE;
464     }
465     else
466     {
467         if (blob->cbData)
468             memcpy(pbEncoded, blob->pbData, blob->cbData);
469         *pcbEncoded = blob->cbData;
470         ret = TRUE;
471     }
472     return ret;
473 }
474
475 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
476  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
477  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
478 {
479     BOOL ret;
480     /* This has two filetimes in a row, a NotBefore and a NotAfter */
481     const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
482     struct AsnEncodeSequenceItem items[] = {
483      { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
484      { timePtr,   CRYPT_AsnEncodeChoiceOfTime, 0 },
485     };
486
487     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, 
488      sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
489      pcbEncoded);
490     return ret;
491 }
492
493 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
494  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
495  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
496  DWORD *pcbEncoded)
497 {
498     const CRYPT_ALGORITHM_IDENTIFIER *algo =
499      (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
500     BOOL ret;
501     struct AsnEncodeSequenceItem items[] = {
502      { algo->pszObjId,    CRYPT_AsnEncodeOid, 0 },
503      { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
504     };
505
506     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
507      sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
508      pcbEncoded);
509     return ret;
510 }
511
512 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
513  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
514  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
515 {
516     BOOL ret;
517
518     __TRY
519     {
520         const CERT_PUBLIC_KEY_INFO *info =
521          (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
522         struct AsnEncodeSequenceItem items[] = {
523          { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
524          { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
525         };
526
527         TRACE("Encoding public key with OID %s\n",
528          debugstr_a(info->Algorithm.pszObjId));
529         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
530          sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
531          pcbEncoded);
532     }
533     __EXCEPT_PAGE_FAULT
534     {
535         SetLastError(STATUS_ACCESS_VIOLATION);
536         ret = FALSE;
537     }
538     __ENDTRY
539     return ret;
540 }
541
542 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
543  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
544  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
545 {
546     BOOL ret;
547
548     __TRY
549     {
550         const CERT_SIGNED_CONTENT_INFO *info =
551          (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
552         struct AsnEncodeSequenceItem items[] = {
553          { &info->ToBeSigned,         CRYPT_CopyEncodedBlob, 0 },
554          { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
555          { &info->Signature,          CRYPT_AsnEncodeBitsSwapBytes, 0 },
556         };
557
558         if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
559             items[2].encodeFunc = CRYPT_AsnEncodeBits;
560         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, 
561          sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
562          pcbEncoded);
563     }
564     __EXCEPT_PAGE_FAULT
565     {
566         SetLastError(STATUS_ACCESS_VIOLATION);
567         ret = FALSE;
568     }
569     __ENDTRY
570     return ret;
571 }
572
573 /* Like in Windows, this blithely ignores the validity of the passed-in
574  * CERT_INFO, and just encodes it as-is.  The resulting encoded data may not
575  * decode properly, see CRYPT_AsnDecodeCertInfo.
576  */
577 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
578  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
579  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
580 {
581     BOOL ret;
582
583     __TRY
584     {
585         const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
586         struct AsnEncodeSequenceItem items[10] = {
587          { &info->dwVersion,            CRYPT_AsnEncodeCertVersion, 0 },
588          { &info->SerialNumber,         CRYPT_AsnEncodeInteger, 0 },
589          { &info->SignatureAlgorithm,   CRYPT_AsnEncodeAlgorithmId, 0 },
590          { &info->Issuer,               CRYPT_CopyEncodedBlob, 0 },
591          { &info->NotBefore,            CRYPT_AsnEncodeValidity, 0 },
592          { &info->Subject,              CRYPT_CopyEncodedBlob, 0 },
593          { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
594          { 0 }
595         };
596         struct AsnConstructedItem constructed[3] = { { 0 } };
597         DWORD cItem = 7, cConstructed = 0;
598
599         if (info->IssuerUniqueId.cbData)
600         {
601             constructed[cConstructed].tag = 1;
602             constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
603             constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
604             items[cItem].pvStructInfo = &constructed[cConstructed];
605             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
606             cConstructed++;
607             cItem++;
608         }
609         if (info->SubjectUniqueId.cbData)
610         {
611             constructed[cConstructed].tag = 2;
612             constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
613             constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
614             items[cItem].pvStructInfo = &constructed[cConstructed];
615             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
616             cConstructed++;
617             cItem++;
618         }
619         if (info->cExtension)
620         {
621             constructed[cConstructed].tag = 3;
622             constructed[cConstructed].pvStructInfo = &info->cExtension;
623             constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
624             items[cItem].pvStructInfo = &constructed[cConstructed];
625             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
626             cConstructed++;
627             cItem++;
628         }
629
630         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
631          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
632     }
633     __EXCEPT_PAGE_FAULT
634     {
635         SetLastError(STATUS_ACCESS_VIOLATION);
636         ret = FALSE;
637     }
638     __ENDTRY
639     return ret;
640 }
641
642 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
643  BYTE *pbEncoded, DWORD *pcbEncoded)
644 {
645     struct AsnEncodeSequenceItem items[3] = {
646      { &entry->SerialNumber,   CRYPT_AsnEncodeInteger, 0 },
647      { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
648      { 0 }
649     };
650     DWORD cItem = 2;
651     BOOL ret;
652
653     TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
654
655     if (entry->cExtension)
656     {
657         items[cItem].pvStructInfo = &entry->cExtension;
658         items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
659         cItem++;
660     }
661
662     ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
663      pbEncoded, pcbEncoded);
664
665     TRACE("returning %d (%08lx)\n", ret, GetLastError());
666     return ret;
667 }
668
669 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
670  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
671  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
672 {
673     DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
674     DWORD bytesNeeded, dataLen, lenBytes, i;
675     const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY **)
676      ((const BYTE *)pvStructInfo + sizeof(DWORD));
677     BOOL ret = TRUE;
678
679     for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
680     {
681         DWORD size;
682
683         ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
684         if (ret)
685             dataLen += size;
686     }
687     CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
688     bytesNeeded = 1 + lenBytes + dataLen;
689     if (!pbEncoded)
690         *pcbEncoded = bytesNeeded;
691     else
692     {
693         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
694          pcbEncoded, bytesNeeded)))
695         {
696             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
697                 pbEncoded = *(BYTE **)pbEncoded;
698             *pbEncoded++ = ASN_SEQUENCEOF;
699             CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
700             pbEncoded += lenBytes;
701             for (i = 0; i < cCRLEntry; i++)
702             {
703                 DWORD size = dataLen;
704
705                 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
706                 pbEncoded += size;
707                 dataLen -= size;
708             }
709         }
710     }
711     return ret;
712 }
713
714 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
715  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
716  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
717 {
718     const DWORD *ver = (const DWORD *)pvStructInfo;
719     BOOL ret;
720
721     /* CRL_V1 is not encoded */
722     if (*ver == CRL_V1)
723     {
724         *pcbEncoded = 0;
725         ret = TRUE;
726     }
727     else
728         ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
729          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
730     return ret;
731 }
732
733 /* Like in Windows, this blithely ignores the validity of the passed-in
734  * CRL_INFO, and just encodes it as-is.  The resulting encoded data may not
735  * decode properly, see CRYPT_AsnDecodeCRLInfo.
736  */
737 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
738  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
739  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
740 {
741     BOOL ret;
742
743     __TRY
744     {
745         const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
746         struct AsnEncodeSequenceItem items[7] = {
747          { &info->dwVersion,          CRYPT_AsnEncodeCRLVersion, 0 },
748          { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
749          { &info->Issuer,             CRYPT_CopyEncodedBlob, 0 },
750          { &info->ThisUpdate,         CRYPT_AsnEncodeChoiceOfTime, 0 },
751          { 0 }
752         };
753         DWORD cItem = 4;
754
755         if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
756         {
757             items[cItem].pvStructInfo = &info->NextUpdate;
758             items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
759             cItem++;
760         }
761         if (info->cCRLEntry)
762         {
763             items[cItem].pvStructInfo = &info->cCRLEntry;
764             items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
765             cItem++;
766         }
767         if (info->cExtension)
768         {
769             items[cItem].pvStructInfo = &info->cExtension;
770             items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
771             cItem++;
772         }
773
774         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
775          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
776     }
777     __EXCEPT_PAGE_FAULT
778     {
779         SetLastError(STATUS_ACCESS_VIOLATION);
780         ret = FALSE;
781     }
782     __ENDTRY
783     return ret;
784 }
785
786 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
787  DWORD *pcbEncoded)
788 {
789     BOOL ret;
790     struct AsnEncodeSequenceItem items[3] = {
791      { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
792      { NULL, NULL, 0 },
793      { NULL, NULL, 0 },
794     };
795     DWORD cItem = 1;
796
797     TRACE("%p, %p, %ld\n", ext, pbEncoded, *pcbEncoded);
798
799     if (ext->fCritical)
800     {
801         items[cItem].pvStructInfo = &ext->fCritical;
802         items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
803         cItem++;
804     }
805     items[cItem].pvStructInfo = &ext->Value;
806     items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
807     cItem++;
808
809     ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
810      pbEncoded, pcbEncoded);
811     TRACE("returning %d (%08lx)\n", ret, GetLastError());
812     return ret;
813 }
814
815 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
816  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
817  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
818 {
819     BOOL ret;
820
821     __TRY
822     {
823         DWORD bytesNeeded, dataLen, lenBytes, i;
824         const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
825
826         ret = TRUE;
827         for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
828         {
829             DWORD size;
830
831             ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
832             if (ret)
833                 dataLen += size;
834         }
835         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
836         bytesNeeded = 1 + lenBytes + dataLen;
837         if (!pbEncoded)
838             *pcbEncoded = bytesNeeded;
839         else
840         {
841             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
842              pcbEncoded, bytesNeeded)))
843             {
844                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
845                     pbEncoded = *(BYTE **)pbEncoded;
846                 *pbEncoded++ = ASN_SEQUENCEOF;
847                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
848                 pbEncoded += lenBytes;
849                 for (i = 0; i < exts->cExtension; i++)
850                 {
851                     DWORD size = dataLen;
852
853                     ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
854                      pbEncoded, &size);
855                     pbEncoded += size;
856                     dataLen -= size;
857                 }
858             }
859         }
860     }
861     __EXCEPT_PAGE_FAULT
862     {
863         SetLastError(STATUS_ACCESS_VIOLATION);
864         ret = FALSE;
865     }
866     __ENDTRY
867     return ret;
868 }
869
870 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
871  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
872  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
873 {
874     LPCSTR pszObjId = (LPCSTR)pvStructInfo;
875     DWORD bytesNeeded = 0, lenBytes;
876     BOOL ret = TRUE;
877     int firstPos = 0;
878     BYTE firstByte = 0;
879
880     TRACE("%s\n", debugstr_a(pszObjId));
881
882     if (pszObjId)
883     {
884         const char *ptr;
885         int val1, val2;
886
887         if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
888         {
889             SetLastError(CRYPT_E_ASN1_ERROR);
890             return FALSE;
891         }
892         bytesNeeded++;
893         firstByte = val1 * 40 + val2;
894         ptr = pszObjId + firstPos;
895         while (ret && *ptr)
896         {
897             int pos;
898
899             /* note I assume each component is at most 32-bits long in base 2 */
900             if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
901             {
902                 if (val1 >= 0x10000000)
903                     bytesNeeded += 5;
904                 else if (val1 >= 0x200000)
905                     bytesNeeded += 4;
906                 else if (val1 >= 0x4000)
907                     bytesNeeded += 3;
908                 else if (val1 >= 0x80)
909                     bytesNeeded += 2;
910                 else
911                     bytesNeeded += 1;
912                 ptr += pos;
913                 if (*ptr == '.')
914                     ptr++;
915             }
916             else
917             {
918                 SetLastError(CRYPT_E_ASN1_ERROR);
919                 return FALSE;
920             }
921         }
922         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
923     }
924     else
925         lenBytes = 1;
926     bytesNeeded += 1 + lenBytes;
927     if (pbEncoded)
928     {
929         if (*pcbEncoded < bytesNeeded)
930         {
931             SetLastError(ERROR_MORE_DATA);
932             ret = FALSE;
933         }
934         else
935         {
936             *pbEncoded++ = ASN_OBJECTIDENTIFIER;
937             CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
938             pbEncoded += lenBytes;
939             if (pszObjId)
940             {
941                 const char *ptr;
942                 int val, pos;
943
944                 *pbEncoded++ = firstByte;
945                 ptr = pszObjId + firstPos;
946                 while (ret && *ptr)
947                 {
948                     sscanf(ptr, "%d%n", &val, &pos);
949                     {
950                         unsigned char outBytes[5];
951                         int numBytes, i;
952
953                         if (val >= 0x10000000)
954                             numBytes = 5;
955                         else if (val >= 0x200000)
956                             numBytes = 4;
957                         else if (val >= 0x4000)
958                             numBytes = 3;
959                         else if (val >= 0x80)
960                             numBytes = 2;
961                         else
962                             numBytes = 1;
963                         for (i = numBytes; i > 0; i--)
964                         {
965                             outBytes[i - 1] = val & 0x7f;
966                             val >>= 7;
967                         }
968                         for (i = 0; i < numBytes - 1; i++)
969                             *pbEncoded++ = outBytes[i] | 0x80;
970                         *pbEncoded++ = outBytes[i];
971                         ptr += pos;
972                         if (*ptr == '.')
973                             ptr++;
974                     }
975                 }
976             }
977         }
978     }
979     *pcbEncoded = bytesNeeded;
980     return ret;
981 }
982
983 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
984  CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
985 {
986     BYTE tag;
987     DWORD bytesNeeded, lenBytes, encodedLen;
988     BOOL ret = TRUE;
989
990     switch (value->dwValueType)
991     {
992     case CERT_RDN_NUMERIC_STRING:
993         tag = ASN_NUMERICSTRING;
994         encodedLen = value->Value.cbData;
995         break;
996     case CERT_RDN_PRINTABLE_STRING:
997         tag = ASN_PRINTABLESTRING;
998         encodedLen = value->Value.cbData;
999         break;
1000     case CERT_RDN_IA5_STRING:
1001         tag = ASN_IA5STRING;
1002         encodedLen = value->Value.cbData;
1003         break;
1004     case CERT_RDN_ANY_TYPE:
1005         /* explicitly disallowed */
1006         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1007         return FALSE;
1008     default:
1009         FIXME("String type %ld unimplemented\n", value->dwValueType);
1010         return FALSE;
1011     }
1012     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1013     bytesNeeded = 1 + lenBytes + encodedLen;
1014     if (pbEncoded)
1015     {
1016         if (*pcbEncoded < bytesNeeded)
1017         {
1018             SetLastError(ERROR_MORE_DATA);
1019             ret = FALSE;
1020         }
1021         else
1022         {
1023             *pbEncoded++ = tag;
1024             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1025             pbEncoded += lenBytes;
1026             switch (value->dwValueType)
1027             {
1028             case CERT_RDN_NUMERIC_STRING:
1029             case CERT_RDN_PRINTABLE_STRING:
1030             case CERT_RDN_IA5_STRING:
1031                 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
1032             }
1033         }
1034     }
1035     *pcbEncoded = bytesNeeded;
1036     return ret;
1037 }
1038
1039 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1040  CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
1041 {
1042     DWORD bytesNeeded = 0, lenBytes, size;
1043     BOOL ret;
1044
1045     ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1046      0, NULL, NULL, &size);
1047     if (ret)
1048     {
1049         bytesNeeded += size;
1050         /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1051          * with dwValueType, so "cast" it to get its encoded size
1052          */
1053         ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1054          (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
1055         if (ret)
1056         {
1057             bytesNeeded += size;
1058             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1059             bytesNeeded += 1 + lenBytes;
1060             if (pbEncoded)
1061             {
1062                 if (*pcbEncoded < bytesNeeded)
1063                 {
1064                     SetLastError(ERROR_MORE_DATA);
1065                     ret = FALSE;
1066                 }
1067                 else
1068                 {
1069                     *pbEncoded++ = ASN_SEQUENCE;
1070                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1071                      &lenBytes);
1072                     pbEncoded += lenBytes;
1073                     size = bytesNeeded - 1 - lenBytes;
1074                     ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1075                      attr->pszObjId, 0, NULL, pbEncoded, &size);
1076                     if (ret)
1077                     {
1078                         pbEncoded += size;
1079                         size = bytesNeeded - 1 - lenBytes - size;
1080                         ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1081                          (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
1082                          &size);
1083                     }
1084                 }
1085             }
1086             *pcbEncoded = bytesNeeded;
1087         }
1088     }
1089     return ret;
1090 }
1091
1092 static int BLOBComp(const void *l, const void *r)
1093 {
1094     CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
1095     int ret;
1096
1097     if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1098         ret = a->cbData - b->cbData;
1099     return ret;
1100 }
1101
1102 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1103  */
1104 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1105  BYTE *pbEncoded, DWORD *pcbEncoded)
1106 {
1107     BOOL ret;
1108     CRYPT_DER_BLOB *blobs = NULL;
1109
1110     __TRY
1111     {
1112         DWORD bytesNeeded = 0, lenBytes, i;
1113
1114         blobs = NULL;
1115         ret = TRUE;
1116         if (rdn->cRDNAttr)
1117         {
1118             blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1119             if (!blobs)
1120                 ret = FALSE;
1121             else
1122                 memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1123         }
1124         for (i = 0; ret && i < rdn->cRDNAttr; i++)
1125         {
1126             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1127              NULL, &blobs[i].cbData);
1128             if (ret)
1129                 bytesNeeded += blobs[i].cbData;
1130         }
1131         if (ret)
1132         {
1133             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1134             bytesNeeded += 1 + lenBytes;
1135             if (pbEncoded)
1136             {
1137                 if (*pcbEncoded < bytesNeeded)
1138                 {
1139                     SetLastError(ERROR_MORE_DATA);
1140                     ret = FALSE;
1141                 }
1142                 else
1143                 {
1144                     for (i = 0; ret && i < rdn->cRDNAttr; i++)
1145                     {
1146                         blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
1147                         if (!blobs[i].pbData)
1148                             ret = FALSE;
1149                         else
1150                             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1151                              &rdn->rgRDNAttr[i], blobs[i].pbData,
1152                              &blobs[i].cbData);
1153                     }
1154                     if (ret)
1155                     {
1156                         qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1157                          BLOBComp);
1158                         *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1159                         CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1160                          &lenBytes);
1161                         pbEncoded += lenBytes;
1162                         for (i = 0; ret && i < rdn->cRDNAttr; i++)
1163                         {
1164                             memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1165                             pbEncoded += blobs[i].cbData;
1166                         }
1167                     }
1168                 }
1169             }
1170             *pcbEncoded = bytesNeeded;
1171         }
1172         if (blobs)
1173         {
1174             for (i = 0; i < rdn->cRDNAttr; i++)
1175                 CryptMemFree(blobs[i].pbData);
1176         }
1177     }
1178     __EXCEPT_PAGE_FAULT
1179     {
1180         SetLastError(STATUS_ACCESS_VIOLATION);
1181         ret = FALSE;
1182     }
1183     __ENDTRY
1184     CryptMemFree(blobs);
1185     return ret;
1186 }
1187
1188 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1189  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1190  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1191 {
1192     BOOL ret;
1193
1194     __TRY
1195     {
1196         const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1197         DWORD bytesNeeded = 0, lenBytes, size, i;
1198
1199         TRACE("encoding name with %ld RDNs\n", info->cRDN);
1200         ret = TRUE;
1201         for (i = 0; ret && i < info->cRDN; i++)
1202         {
1203             ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1204              &size);
1205             if (ret)
1206                 bytesNeeded += size;
1207         }
1208         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1209         bytesNeeded += 1 + lenBytes;
1210         if (ret)
1211         {
1212             if (!pbEncoded)
1213                 *pcbEncoded = bytesNeeded;
1214             else
1215             {
1216                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1217                  pbEncoded, pcbEncoded, bytesNeeded)))
1218                 {
1219                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1220                         pbEncoded = *(BYTE **)pbEncoded;
1221                     *pbEncoded++ = ASN_SEQUENCEOF;
1222                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1223                      &lenBytes);
1224                     pbEncoded += lenBytes;
1225                     for (i = 0; ret && i < info->cRDN; i++)
1226                     {
1227                         size = bytesNeeded;
1228                         ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1229                          &info->rgRDN[i], pbEncoded, &size);
1230                         if (ret)
1231                         {
1232                             pbEncoded += size;
1233                             bytesNeeded -= size;
1234                         }
1235                     }
1236                 }
1237             }
1238         }
1239     }
1240     __EXCEPT_PAGE_FAULT
1241     {
1242         SetLastError(STATUS_ACCESS_VIOLATION);
1243         ret = FALSE;
1244     }
1245     __ENDTRY
1246     return ret;
1247 }
1248
1249 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1250  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1251  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1252 {
1253     BOOL val = *(const BOOL *)pvStructInfo, ret;
1254
1255     TRACE("%d\n", val);
1256
1257     if (!pbEncoded)
1258     {
1259         *pcbEncoded = 3;
1260         ret = TRUE;
1261     }
1262     else if (*pcbEncoded < 3)
1263     {
1264         *pcbEncoded = 3;
1265         SetLastError(ERROR_MORE_DATA);
1266         ret = FALSE;
1267     }
1268     else
1269     {
1270         *pcbEncoded = 3;
1271         *pbEncoded++ = ASN_BOOL;
1272         *pbEncoded++ = 1;
1273         *pbEncoded++ = val ? 0xff : 0;
1274         ret = TRUE;
1275     }
1276     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1277     return ret;
1278 }
1279
1280 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1281  BYTE *pbEncoded, DWORD *pcbEncoded)
1282 {
1283     BOOL ret;
1284     DWORD dataLen;
1285
1286     ret = TRUE;
1287     switch (entry->dwAltNameChoice)
1288     {
1289     case CERT_ALT_NAME_RFC822_NAME:
1290     case CERT_ALT_NAME_DNS_NAME:
1291     case CERT_ALT_NAME_URL:
1292         if (entry->u.pwszURL)
1293         {
1294             DWORD i;
1295
1296             /* Not + 1: don't encode the NULL-terminator */
1297             dataLen = lstrlenW(entry->u.pwszURL);
1298             for (i = 0; ret && i < dataLen; i++)
1299             {
1300                 if (entry->u.pwszURL[i] > 0x7f)
1301                 {
1302                     SetLastError(CRYPT_E_INVALID_IA5_STRING);
1303                     ret = FALSE;
1304                     *pcbEncoded = i;
1305                 }
1306             }
1307         }
1308         else
1309             dataLen = 0;
1310         break;
1311     case CERT_ALT_NAME_IP_ADDRESS:
1312         dataLen = entry->u.IPAddress.cbData;
1313         break;
1314     case CERT_ALT_NAME_REGISTERED_ID:
1315         /* FIXME: encode OID */
1316     case CERT_ALT_NAME_OTHER_NAME:
1317     case CERT_ALT_NAME_DIRECTORY_NAME:
1318         FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice);
1319         return FALSE;
1320     default:
1321         SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1322         return FALSE;
1323     }
1324     if (ret)
1325     {
1326         DWORD bytesNeeded, lenBytes;
1327
1328         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1329         bytesNeeded = 1 + dataLen + lenBytes;
1330         if (!pbEncoded)
1331             *pcbEncoded = bytesNeeded;
1332         else if (*pcbEncoded < bytesNeeded)
1333         {
1334             SetLastError(ERROR_MORE_DATA);
1335             *pcbEncoded = bytesNeeded;
1336             ret = FALSE;
1337         }
1338         else
1339         {
1340             *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1341             CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1342             pbEncoded += lenBytes;
1343             switch (entry->dwAltNameChoice)
1344             {
1345             case CERT_ALT_NAME_RFC822_NAME:
1346             case CERT_ALT_NAME_DNS_NAME:
1347             case CERT_ALT_NAME_URL:
1348             {
1349                 DWORD i;
1350
1351                 for (i = 0; i < dataLen; i++)
1352                     *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1353                 break;
1354             }
1355             case CERT_ALT_NAME_IP_ADDRESS:
1356                 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1357                 break;
1358             }
1359             if (ret)
1360                 *pcbEncoded = bytesNeeded;
1361         }
1362     }
1363     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1364     return ret;
1365 }
1366
1367 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1368  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1369  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1370 {
1371     BOOL ret;
1372
1373     __TRY
1374     {
1375         const CERT_ALT_NAME_INFO *info =
1376          (const CERT_ALT_NAME_INFO *)pvStructInfo;
1377         DWORD bytesNeeded, dataLen, lenBytes, i;
1378
1379         ret = TRUE;
1380         /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1381          * can't encode an erroneous entry index if it's bigger than this.
1382          */
1383         for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1384         {
1385             DWORD len;
1386
1387             ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1388              &len);
1389             if (ret)
1390                 dataLen += len;
1391             else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1392             {
1393                 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1394                  * the bad character, now set the index of the bad
1395                  * entry
1396                  */
1397                 *pcbEncoded = (BYTE)i <<
1398                  CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1399             }
1400         }
1401         if (ret)
1402         {
1403             CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1404             bytesNeeded = 1 + lenBytes + dataLen;
1405             if (!pbEncoded)
1406             {
1407                 *pcbEncoded = bytesNeeded;
1408                 ret = TRUE;
1409             }
1410             else
1411             {
1412                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1413                  pbEncoded, pcbEncoded, bytesNeeded)))
1414                 {
1415                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1416                         pbEncoded = *(BYTE **)pbEncoded;
1417                     *pbEncoded++ = ASN_SEQUENCEOF;
1418                     CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1419                     pbEncoded += lenBytes;
1420                     for (i = 0; ret && i < info->cAltEntry; i++)
1421                     {
1422                         DWORD len = dataLen;
1423
1424                         ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1425                          pbEncoded, &len);
1426                         if (ret)
1427                         {
1428                             pbEncoded += len;
1429                             dataLen -= len;
1430                         }
1431                     }
1432                 }
1433             }
1434         }
1435     }
1436     __EXCEPT_PAGE_FAULT
1437     {
1438         SetLastError(STATUS_ACCESS_VIOLATION);
1439         ret = FALSE;
1440     }
1441     __ENDTRY
1442     return ret;
1443 }
1444
1445 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1446  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1447  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1448 {
1449     BOOL ret;
1450
1451     __TRY
1452     {
1453         const CERT_BASIC_CONSTRAINTS2_INFO *info =
1454          (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1455         struct AsnEncodeSequenceItem items[2] = { { 0 } };
1456         DWORD cItem = 0;
1457
1458         if (info->fCA)
1459         {
1460             items[cItem].pvStructInfo = &info->fCA;
1461             items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1462             cItem++;
1463         }
1464         if (info->fPathLenConstraint)
1465         {
1466             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1467             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1468             cItem++;
1469         }
1470         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1471          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1472     }
1473     __EXCEPT_PAGE_FAULT
1474     {
1475         SetLastError(STATUS_ACCESS_VIOLATION);
1476         ret = FALSE;
1477     }
1478     __ENDTRY
1479     return ret;
1480 }
1481
1482 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
1483  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1484  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1485 {
1486     BOOL ret;
1487
1488     __TRY
1489     {
1490         const BLOBHEADER *hdr =
1491          (const BLOBHEADER *)pvStructInfo;
1492
1493         if (hdr->bType != PUBLICKEYBLOB)
1494         {
1495             SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1496             ret = FALSE;
1497         }
1498         else
1499         {
1500             const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
1501              ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
1502             CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
1503              (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
1504             struct AsnEncodeSequenceItem items[] = { 
1505              { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
1506              { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
1507             };
1508
1509             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1510              sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1511              pcbEncoded);
1512         }
1513     }
1514     __EXCEPT_PAGE_FAULT
1515     {
1516         SetLastError(STATUS_ACCESS_VIOLATION);
1517         ret = FALSE;
1518     }
1519     __ENDTRY
1520     return ret;
1521 }
1522
1523 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1524  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1525  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1526 {
1527     BOOL ret;
1528
1529     __TRY
1530     {
1531         const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1532         DWORD bytesNeeded, lenBytes;
1533
1534         TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1535          dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1536
1537         CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1538         bytesNeeded = 1 + lenBytes + blob->cbData;
1539         if (!pbEncoded)
1540         {
1541             *pcbEncoded = bytesNeeded;
1542             ret = TRUE;
1543         }
1544         else
1545         {
1546             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1547              pcbEncoded, bytesNeeded)))
1548             {
1549                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1550                     pbEncoded = *(BYTE **)pbEncoded;
1551                 *pbEncoded++ = ASN_OCTETSTRING;
1552                 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1553                 pbEncoded += lenBytes;
1554                 if (blob->cbData)
1555                     memcpy(pbEncoded, blob->pbData, blob->cbData);
1556             }
1557         }
1558     }
1559     __EXCEPT_PAGE_FAULT
1560     {
1561         SetLastError(STATUS_ACCESS_VIOLATION);
1562         ret = FALSE;
1563     }
1564     __ENDTRY
1565     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1566     return ret;
1567 }
1568
1569 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1570  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1571  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1572 {
1573     BOOL ret;
1574
1575     __TRY
1576     {
1577         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1578         DWORD bytesNeeded, lenBytes, dataBytes;
1579         BYTE unusedBits;
1580
1581         /* yep, MS allows cUnusedBits to be >= 8 */
1582         if (!blob->cUnusedBits)
1583         {
1584             dataBytes = blob->cbData;
1585             unusedBits = 0;
1586         }
1587         else if (blob->cbData * 8 > blob->cUnusedBits)
1588         {
1589             dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1590             unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1591              blob->cUnusedBits;
1592         }
1593         else
1594         {
1595             dataBytes = 0;
1596             unusedBits = 0;
1597         }
1598         CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1599         bytesNeeded = 1 + lenBytes + dataBytes + 1;
1600         if (!pbEncoded)
1601         {
1602             *pcbEncoded = bytesNeeded;
1603             ret = TRUE;
1604         }
1605         else
1606         {
1607             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1608              pcbEncoded, bytesNeeded)))
1609             {
1610                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1611                     pbEncoded = *(BYTE **)pbEncoded;
1612                 *pbEncoded++ = ASN_BITSTRING;
1613                 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1614                 pbEncoded += lenBytes;
1615                 *pbEncoded++ = unusedBits;
1616                 if (dataBytes)
1617                 {
1618                     BYTE mask = 0xff << unusedBits;
1619
1620                     if (dataBytes > 1)
1621                     {
1622                         memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1623                         pbEncoded += dataBytes - 1;
1624                     }
1625                     *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1626                 }
1627             }
1628         }
1629     }
1630     __EXCEPT_PAGE_FAULT
1631     {
1632         SetLastError(STATUS_ACCESS_VIOLATION);
1633         ret = FALSE;
1634     }
1635     __ENDTRY
1636     return ret;
1637 }
1638
1639 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
1640  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1641  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1642 {
1643     BOOL ret;
1644
1645     __TRY
1646     {
1647         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1648         CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
1649
1650         ret = TRUE;
1651         if (newBlob.cbData)
1652         {
1653             newBlob.pbData = CryptMemAlloc(newBlob.cbData);
1654             if (newBlob.pbData)
1655             {
1656                 DWORD i;
1657
1658                 for (i = 0; i < newBlob.cbData; i++)
1659                     newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
1660             }
1661             else
1662                 ret = FALSE;
1663         }
1664         if (ret)
1665             ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
1666              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1667         CryptMemFree(newBlob.pbData);
1668     }
1669     __EXCEPT_PAGE_FAULT
1670     {
1671         SetLastError(STATUS_ACCESS_VIOLATION);
1672         ret = FALSE;
1673     }
1674     __ENDTRY
1675     return ret;
1676 }
1677
1678 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1679  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1680  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1681 {
1682     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1683
1684     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1685      &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1686 }
1687
1688 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1689  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1690  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1691 {
1692     BOOL ret;
1693
1694     __TRY
1695     {
1696         DWORD significantBytes, lenBytes;
1697         BYTE padByte = 0, bytesNeeded;
1698         BOOL pad = FALSE;
1699         const CRYPT_INTEGER_BLOB *blob =
1700          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1701
1702         significantBytes = blob->cbData;
1703         if (significantBytes)
1704         {
1705             if (blob->pbData[significantBytes - 1] & 0x80)
1706             {
1707                 /* negative, lop off leading (little-endian) 0xffs */
1708                 for (; significantBytes > 0 &&
1709                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1710                     ;
1711                 if (blob->pbData[significantBytes - 1] < 0x80)
1712                 {
1713                     padByte = 0xff;
1714                     pad = TRUE;
1715                 }
1716             }
1717             else
1718             {
1719                 /* positive, lop off leading (little-endian) zeroes */
1720                 for (; significantBytes > 0 &&
1721                  !blob->pbData[significantBytes - 1]; significantBytes--)
1722                     ;
1723                 if (significantBytes == 0)
1724                     significantBytes = 1;
1725                 if (blob->pbData[significantBytes - 1] > 0x7f)
1726                 {
1727                     padByte = 0;
1728                     pad = TRUE;
1729                 }
1730             }
1731         }
1732         if (pad)
1733             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1734         else
1735             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1736         bytesNeeded = 1 + lenBytes + significantBytes;
1737         if (pad)
1738             bytesNeeded++;
1739         if (!pbEncoded)
1740         {
1741             *pcbEncoded = bytesNeeded;
1742             ret = TRUE;
1743         }
1744         else
1745         {
1746             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1747              pcbEncoded, bytesNeeded)))
1748             {
1749                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1750                     pbEncoded = *(BYTE **)pbEncoded;
1751                 *pbEncoded++ = ASN_INTEGER;
1752                 if (pad)
1753                 {
1754                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1755                     pbEncoded += lenBytes;
1756                     *pbEncoded++ = padByte;
1757                 }
1758                 else
1759                 {
1760                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1761                     pbEncoded += lenBytes;
1762                 }
1763                 for (; significantBytes > 0; significantBytes--)
1764                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
1765             }
1766         }
1767     }
1768     __EXCEPT_PAGE_FAULT
1769     {
1770         SetLastError(STATUS_ACCESS_VIOLATION);
1771         ret = FALSE;
1772     }
1773     __ENDTRY
1774     return ret;
1775 }
1776
1777 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1778  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1779  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1780 {
1781     BOOL ret;
1782
1783     __TRY
1784     {
1785         DWORD significantBytes, lenBytes;
1786         BYTE bytesNeeded;
1787         BOOL pad = FALSE;
1788         const CRYPT_INTEGER_BLOB *blob =
1789          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1790
1791         significantBytes = blob->cbData;
1792         if (significantBytes)
1793         {
1794             /* positive, lop off leading (little-endian) zeroes */
1795             for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1796              significantBytes--)
1797                 ;
1798             if (significantBytes == 0)
1799                 significantBytes = 1;
1800             if (blob->pbData[significantBytes - 1] > 0x7f)
1801                 pad = TRUE;
1802         }
1803         if (pad)
1804             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1805         else
1806             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1807         bytesNeeded = 1 + lenBytes + significantBytes;
1808         if (pad)
1809             bytesNeeded++;
1810         if (!pbEncoded)
1811         {
1812             *pcbEncoded = bytesNeeded;
1813             ret = TRUE;
1814         }
1815         else
1816         {
1817             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1818              pcbEncoded, bytesNeeded)))
1819             {
1820                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1821                     pbEncoded = *(BYTE **)pbEncoded;
1822                 *pbEncoded++ = ASN_INTEGER;
1823                 if (pad)
1824                 {
1825                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1826                     pbEncoded += lenBytes;
1827                     *pbEncoded++ = 0;
1828                 }
1829                 else
1830                 {
1831                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1832                     pbEncoded += lenBytes;
1833                 }
1834                 for (; significantBytes > 0; significantBytes--)
1835                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
1836             }
1837         }
1838     }
1839     __EXCEPT_PAGE_FAULT
1840     {
1841         SetLastError(STATUS_ACCESS_VIOLATION);
1842         ret = FALSE;
1843     }
1844     __ENDTRY
1845     return ret;
1846 }
1847
1848 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
1849  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1850  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1851 {
1852     CRYPT_INTEGER_BLOB blob;
1853     BOOL ret;
1854
1855     /* Encode as an unsigned integer, then change the tag to enumerated */
1856     blob.cbData = sizeof(DWORD);
1857     blob.pbData = (BYTE *)pvStructInfo;
1858     ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
1859      X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1860     if (ret && pbEncoded)
1861     {
1862         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1863             pbEncoded = *(BYTE **)pbEncoded;
1864         pbEncoded[0] = ASN_ENUMERATED;
1865     }
1866     return ret;
1867 }
1868
1869 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
1870  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1871  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1872 {
1873     BOOL ret;
1874
1875     __TRY
1876     {
1877         SYSTEMTIME sysTime;
1878         /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
1879          * temporary buffer because the output buffer is not NULL-terminated.
1880          */
1881         char buf[16];
1882         static const DWORD bytesNeeded = sizeof(buf) - 1;
1883
1884         if (!pbEncoded)
1885         {
1886             *pcbEncoded = bytesNeeded;
1887             ret = TRUE;
1888         }
1889         else
1890         {
1891             /* Sanity check the year, this is a two-digit year format */
1892             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1893              &sysTime);
1894             if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
1895             {
1896                 SetLastError(CRYPT_E_BAD_ENCODE);
1897                 ret = FALSE;
1898             }
1899             if (ret)
1900             {
1901                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1902                  pbEncoded, pcbEncoded, bytesNeeded)))
1903                 {
1904                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1905                         pbEncoded = *(BYTE **)pbEncoded;
1906                     buf[0] = ASN_UTCTIME;
1907                     buf[1] = bytesNeeded - 2;
1908                     snprintf(buf + 2, sizeof(buf) - 2,
1909                      "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
1910                      sysTime.wYear - 2000 : sysTime.wYear - 1900,
1911                      sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1912                      sysTime.wMinute, sysTime.wSecond);
1913                     memcpy(pbEncoded, buf, bytesNeeded);
1914                 }
1915             }
1916         }
1917     }
1918     __EXCEPT_PAGE_FAULT
1919     {
1920         SetLastError(STATUS_ACCESS_VIOLATION);
1921         ret = FALSE;
1922     }
1923     __ENDTRY
1924     return ret;
1925 }
1926
1927 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
1928  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1929  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1930 {
1931     BOOL ret;
1932
1933     __TRY
1934     {
1935         SYSTEMTIME sysTime;
1936         /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
1937          * temporary buffer because the output buffer is not NULL-terminated.
1938          */
1939         char buf[18];
1940         static const DWORD bytesNeeded = sizeof(buf) - 1;
1941
1942         if (!pbEncoded)
1943         {
1944             *pcbEncoded = bytesNeeded;
1945             ret = TRUE;
1946         }
1947         else
1948         {
1949             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1950              &sysTime);
1951             if (ret)
1952                 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1953                  pcbEncoded, bytesNeeded);
1954             if (ret)
1955             {
1956                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1957                     pbEncoded = *(BYTE **)pbEncoded;
1958                 buf[0] = ASN_GENERALTIME;
1959                 buf[1] = bytesNeeded - 2;
1960                 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
1961                  sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1962                  sysTime.wMinute, sysTime.wSecond);
1963                 memcpy(pbEncoded, buf, bytesNeeded);
1964             }
1965         }
1966     }
1967     __EXCEPT_PAGE_FAULT
1968     {
1969         SetLastError(STATUS_ACCESS_VIOLATION);
1970         ret = FALSE;
1971     }
1972     __ENDTRY
1973     return ret;
1974 }
1975
1976 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
1977  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1978  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1979 {
1980     BOOL ret;
1981
1982     __TRY
1983     {
1984         SYSTEMTIME sysTime;
1985
1986         /* Check the year, if it's in the UTCTime range call that encode func */
1987         if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1988             return FALSE;
1989         if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
1990             ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
1991              pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1992         else
1993             ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
1994              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1995              pcbEncoded);
1996     }
1997     __EXCEPT_PAGE_FAULT
1998     {
1999         SetLastError(STATUS_ACCESS_VIOLATION);
2000         ret = FALSE;
2001     }
2002     __ENDTRY
2003     return ret;
2004 }
2005
2006 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2007  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2008  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2009 {
2010     BOOL ret;
2011
2012     __TRY
2013     {
2014         DWORD bytesNeeded, dataLen, lenBytes, i;
2015         const CRYPT_SEQUENCE_OF_ANY *seq =
2016          (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2017
2018         for (i = 0, dataLen = 0; i < seq->cValue; i++)
2019             dataLen += seq->rgValue[i].cbData;
2020         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2021         bytesNeeded = 1 + lenBytes + dataLen;
2022         if (!pbEncoded)
2023         {
2024             *pcbEncoded = bytesNeeded;
2025             ret = TRUE;
2026         }
2027         else
2028         {
2029             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2030              pcbEncoded, bytesNeeded)))
2031             {
2032                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2033                     pbEncoded = *(BYTE **)pbEncoded;
2034                 *pbEncoded++ = ASN_SEQUENCEOF;
2035                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2036                 pbEncoded += lenBytes;
2037                 for (i = 0; i < seq->cValue; i++)
2038                 {
2039                     memcpy(pbEncoded, seq->rgValue[i].pbData,
2040                      seq->rgValue[i].cbData);
2041                     pbEncoded += seq->rgValue[i].cbData;
2042                 }
2043             }
2044         }
2045     }
2046     __EXCEPT_PAGE_FAULT
2047     {
2048         SetLastError(STATUS_ACCESS_VIOLATION);
2049         ret = FALSE;
2050     }
2051     __ENDTRY
2052     return ret;
2053 }
2054
2055 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2056  BYTE *pbEncoded, DWORD *pcbEncoded)
2057 {
2058     BOOL ret = TRUE;
2059     struct AsnEncodeSequenceItem items[3] = { { 0 } };
2060     struct AsnConstructedItem constructed = { 0 };
2061     struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2062     DWORD cItem = 0, cSwapped = 0;
2063
2064     switch (distPoint->DistPointName.dwDistPointNameChoice)
2065     {
2066     case CRL_DIST_POINT_NO_NAME:
2067         /* do nothing */
2068         break;
2069     case CRL_DIST_POINT_FULL_NAME:
2070         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2071         swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2072         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2073         constructed.tag = 0;
2074         constructed.pvStructInfo = &swapped[cSwapped];
2075         constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2076         items[cItem].pvStructInfo = &constructed;
2077         items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2078         cSwapped++;
2079         cItem++;
2080         break;
2081     case CRL_DIST_POINT_ISSUER_RDN_NAME:
2082         FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2083         ret = FALSE;
2084         break;
2085     default:
2086         ret = FALSE;
2087     }
2088     if (ret && distPoint->ReasonFlags.cbData)
2089     {
2090         swapped[cSwapped].tag = ASN_CONTEXT | 1;
2091         swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2092         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2093         items[cItem].pvStructInfo = &swapped[cSwapped];
2094         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2095         cSwapped++;
2096         cItem++;
2097     }
2098     if (ret && distPoint->CRLIssuer.cAltEntry)
2099     {
2100         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2101         swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2102         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2103         items[cItem].pvStructInfo = &swapped[cSwapped];
2104         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2105         cSwapped++;
2106         cItem++;
2107     }
2108     if (ret)
2109         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2110          pbEncoded, pcbEncoded);
2111     return ret;
2112 }
2113
2114 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2115  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2116  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2117 {
2118     BOOL ret;
2119
2120     __TRY
2121     {
2122         const CRL_DIST_POINTS_INFO *info =
2123          (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2124
2125         if (!info->cDistPoint)
2126         {
2127             SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2128             ret = FALSE;
2129         }
2130         else
2131         {
2132             DWORD bytesNeeded, dataLen, lenBytes, i;
2133
2134             ret = TRUE;
2135             for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2136             {
2137                 DWORD len;
2138
2139                 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2140                  &len);
2141                 if (ret)
2142                     dataLen += len;
2143                 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2144                 {
2145                     /* Have to propagate index of failing character */
2146                     *pcbEncoded = len;
2147                 }
2148             }
2149             if (ret)
2150             {
2151                 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2152                 bytesNeeded = 1 + lenBytes + dataLen;
2153                 if (!pbEncoded)
2154                 {
2155                     *pcbEncoded = bytesNeeded;
2156                     ret = TRUE;
2157                 }
2158                 else
2159                 {
2160                     if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2161                      pbEncoded, pcbEncoded, bytesNeeded)))
2162                     {
2163                         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2164                             pbEncoded = *(BYTE **)pbEncoded;
2165                         *pbEncoded++ = ASN_SEQUENCEOF;
2166                         CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2167                         pbEncoded += lenBytes;
2168                         for (i = 0; ret && i < info->cDistPoint; i++)
2169                         {
2170                             DWORD len = dataLen;
2171
2172                             ret = CRYPT_AsnEncodeDistPoint(
2173                              &info->rgDistPoint[i], pbEncoded, &len);
2174                             if (ret)
2175                             {
2176                                 pbEncoded += len;
2177                                 dataLen -= len;
2178                             }
2179                         }
2180                     }
2181                 }
2182             }
2183         }
2184     }
2185     __EXCEPT_PAGE_FAULT
2186     {
2187         SetLastError(STATUS_ACCESS_VIOLATION);
2188         ret = FALSE;
2189     }
2190     __ENDTRY
2191     return ret;
2192 }
2193
2194 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2195  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2196  void *pvEncoded, DWORD *pcbEncoded)
2197 {
2198     static HCRYPTOIDFUNCSET set = NULL;
2199     BOOL ret = FALSE;
2200     CryptEncodeObjectExFunc encodeFunc = NULL;
2201     HCRYPTOIDFUNCADDR hFunc = NULL;
2202
2203     TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2204      debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2205      pvEncoded, pcbEncoded);
2206
2207     if (!pvEncoded && !pcbEncoded)
2208     {
2209         SetLastError(ERROR_INVALID_PARAMETER);
2210         return FALSE;
2211     }
2212     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2213      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2214     {
2215         SetLastError(ERROR_FILE_NOT_FOUND);
2216         return FALSE;
2217     }
2218
2219     SetLastError(NOERROR);
2220     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2221         *(BYTE **)pvEncoded = NULL;
2222     if (!HIWORD(lpszStructType))
2223     {
2224         switch (LOWORD(lpszStructType))
2225         {
2226         case (WORD)X509_CERT:
2227             encodeFunc = CRYPT_AsnEncodeCert;
2228             break;
2229         case (WORD)X509_CERT_TO_BE_SIGNED:
2230             encodeFunc = CRYPT_AsnEncodeCertInfo;
2231             break;
2232         case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2233             encodeFunc = CRYPT_AsnEncodeCRLInfo;
2234             break;
2235         case (WORD)X509_EXTENSIONS:
2236             encodeFunc = CRYPT_AsnEncodeExtensions;
2237             break;
2238         case (WORD)X509_NAME:
2239             encodeFunc = CRYPT_AsnEncodeName;
2240             break;
2241         case (WORD)X509_PUBLIC_KEY_INFO:
2242             encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2243             break;
2244         case (WORD)X509_ALTERNATE_NAME:
2245             encodeFunc = CRYPT_AsnEncodeAltName;
2246             break;
2247         case (WORD)X509_BASIC_CONSTRAINTS2:
2248             encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2249             break;
2250         case (WORD)RSA_CSP_PUBLICKEYBLOB:
2251             encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2252             break;
2253         case (WORD)X509_OCTET_STRING:
2254             encodeFunc = CRYPT_AsnEncodeOctets;
2255             break;
2256         case (WORD)X509_BITS:
2257         case (WORD)X509_KEY_USAGE:
2258             encodeFunc = CRYPT_AsnEncodeBits;
2259             break;
2260         case (WORD)X509_INTEGER:
2261             encodeFunc = CRYPT_AsnEncodeInt;
2262             break;
2263         case (WORD)X509_MULTI_BYTE_INTEGER:
2264             encodeFunc = CRYPT_AsnEncodeInteger;
2265             break;
2266         case (WORD)X509_MULTI_BYTE_UINT:
2267             encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2268             break;
2269         case (WORD)X509_ENUMERATED:
2270             encodeFunc = CRYPT_AsnEncodeEnumerated;
2271             break;
2272         case (WORD)X509_CHOICE_OF_TIME:
2273             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2274             break;
2275         case (WORD)X509_SEQUENCE_OF_ANY:
2276             encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2277             break;
2278         case (WORD)PKCS_UTC_TIME:
2279             encodeFunc = CRYPT_AsnEncodeUtcTime;
2280             break;
2281         case (WORD)X509_CRL_DIST_POINTS:
2282             encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2283             break;
2284         default:
2285             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2286         }
2287     }
2288     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2289         encodeFunc = CRYPT_AsnEncodeExtensions;
2290     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2291         encodeFunc = CRYPT_AsnEncodeUtcTime;
2292     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2293         encodeFunc = CRYPT_AsnEncodeEnumerated;
2294     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2295         encodeFunc = CRYPT_AsnEncodeBits;
2296     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2297         encodeFunc = CRYPT_AsnEncodeOctets;
2298     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2299         encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2300     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2301         encodeFunc = CRYPT_AsnEncodeAltName;
2302     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2303         encodeFunc = CRYPT_AsnEncodeAltName;
2304     else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2305         encodeFunc = CRYPT_AsnEncodeAltName;
2306     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2307         encodeFunc = CRYPT_AsnEncodeAltName;
2308     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2309         encodeFunc = CRYPT_AsnEncodeAltName;
2310     else
2311         TRACE("OID %s not found or unimplemented, looking for DLL\n",
2312          debugstr_a(lpszStructType));
2313     if (!encodeFunc)
2314     {
2315         if (!set)
2316             set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
2317         CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2318          (void **)&encodeFunc, &hFunc);
2319     }
2320     if (encodeFunc)
2321         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2322          dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2323     else
2324         SetLastError(ERROR_FILE_NOT_FOUND);
2325     if (hFunc)
2326         CryptFreeOIDFunctionAddress(hFunc, 0);
2327     return ret;
2328 }
2329
2330 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2331  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
2332  DWORD *pcbStructInfo)
2333 {
2334     static HCRYPTOIDFUNCSET set = NULL;
2335     BOOL ret = FALSE;
2336     CryptDecodeObjectFunc pCryptDecodeObject;
2337     HCRYPTOIDFUNCADDR hFunc;
2338
2339     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType,
2340      debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
2341      pvStructInfo, pcbStructInfo);
2342
2343     if (!pvStructInfo && !pcbStructInfo)
2344     {
2345         SetLastError(ERROR_INVALID_PARAMETER);
2346         return FALSE;
2347     }
2348
2349     /* Try registered DLL first.. */
2350     if (!set)
2351         set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_FUNC, 0);
2352     CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2353      (void **)&pCryptDecodeObject, &hFunc);
2354     if (pCryptDecodeObject)
2355     {
2356         ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
2357          pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
2358         CryptFreeOIDFunctionAddress(hFunc, 0);
2359     }
2360     else
2361     {
2362         /* If not, use CryptDecodeObjectEx */
2363         ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
2364          cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
2365     }
2366     return ret;
2367 }
2368
2369 /* Gets the number of length bytes from the given (leading) length byte */
2370 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
2371
2372 /* Helper function to get the encoded length of the data starting at pbEncoded,
2373  * where pbEncoded[0] is the tag.  If the data are too short to contain a
2374  * length or if the length is too large for cbEncoded, sets an appropriate
2375  * error code and returns FALSE.
2376  */
2377 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
2378  DWORD *len)
2379 {
2380     BOOL ret;
2381
2382     if (cbEncoded <= 1)
2383     {
2384         SetLastError(CRYPT_E_ASN1_CORRUPT);
2385         ret = FALSE;
2386     }
2387     else if (pbEncoded[1] <= 0x7f)
2388     {
2389         if (pbEncoded[1] + 1 > cbEncoded)
2390         {
2391             SetLastError(CRYPT_E_ASN1_EOD);
2392             ret = FALSE;
2393         }
2394         else
2395         {
2396             *len = pbEncoded[1];
2397             ret = TRUE;
2398         }
2399     }
2400     else
2401     {
2402         BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
2403
2404         if (lenLen > sizeof(DWORD) + 1)
2405         {
2406             SetLastError(CRYPT_E_ASN1_LARGE);
2407             ret = FALSE;
2408         }
2409         else if (lenLen + 2 > cbEncoded)
2410         {
2411             SetLastError(CRYPT_E_ASN1_CORRUPT);
2412             ret = FALSE;
2413         }
2414         else
2415         {
2416             DWORD out = 0;
2417
2418             pbEncoded += 2;
2419             while (--lenLen)
2420             {
2421                 out <<= 8;
2422                 out |= *pbEncoded++;
2423             }
2424             if (out + lenLen + 1 > cbEncoded)
2425             {
2426                 SetLastError(CRYPT_E_ASN1_EOD);
2427                 ret = FALSE;
2428             }
2429             else
2430             {
2431                 *len = out;
2432                 ret = TRUE;
2433             }
2434         }
2435     }
2436     return ret;
2437 }
2438
2439 /* Helper function to check *pcbStructInfo, set it to the required size, and
2440  * optionally to allocate memory.  Assumes pvStructInfo is not NULL.
2441  * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
2442  * pointer to the newly allocated memory.
2443  */
2444 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
2445  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2446  DWORD bytesNeeded)
2447 {
2448     BOOL ret = TRUE;
2449
2450     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2451     {
2452         if (pDecodePara && pDecodePara->pfnAlloc)
2453             *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
2454         else
2455             *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
2456         if (!*(BYTE **)pvStructInfo)
2457             ret = FALSE;
2458         else
2459             *pcbStructInfo = bytesNeeded;
2460     }
2461     else if (*pcbStructInfo < bytesNeeded)
2462     {
2463         *pcbStructInfo = bytesNeeded;
2464         SetLastError(ERROR_MORE_DATA);
2465         ret = FALSE;
2466     }
2467     return ret;
2468 }
2469
2470 /* tag:
2471  *     The expected tag of the item.  If tag is 0, decodeFunc is called
2472  *     regardless of the tag value seen.
2473  * offset:
2474  *     A sequence is decoded into a struct.  The offset member is the
2475  *     offset of this item within that struct.
2476  * decodeFunc:
2477  *     The decoder function to use.  If this is NULL, then the member isn't
2478  *     decoded, but minSize space is reserved for it.
2479  * minSize:
2480  *     The minimum amount of space occupied after decoding.  You must set this.
2481  * optional:
2482  *     If true, and the tag doesn't match the expected tag for this item,
2483  *     or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
2484  *     filled with 0 for this member.
2485  * hasPointer, pointerOffset, minSize:
2486  *     If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
2487  *     the offset within the (outer) struct of the data pointer (or to the
2488  *     first data pointer, if more than one exist).
2489  * size:
2490  *     Used by CRYPT_AsnDecodeSequence, not for your use.
2491  */
2492 struct AsnDecodeSequenceItem
2493 {
2494     BYTE                    tag;
2495     DWORD                   offset;
2496     CryptDecodeObjectExFunc decodeFunc;
2497     DWORD                   minSize;
2498     BOOL                    optional;
2499     BOOL                    hasPointer;
2500     DWORD                   pointerOffset;
2501     DWORD                   size;
2502 };
2503
2504 static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
2505  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2506  DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData)
2507 {
2508     BOOL ret;
2509     DWORD i;
2510     const BYTE *ptr;
2511
2512     ptr = pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]);
2513     for (i = 0, ret = TRUE; ret && i < cItem; i++)
2514     {
2515         if (cbEncoded - (ptr - pbEncoded) != 0)
2516         {
2517             DWORD nextItemLen;
2518
2519             if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2520              &nextItemLen)))
2521             {
2522                 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2523
2524                 if (ptr[0] == items[i].tag || !items[i].tag)
2525                 {
2526                     if (nextData && pvStructInfo && items[i].hasPointer)
2527                     {
2528                         TRACE("Setting next pointer to %p\n",
2529                          nextData);
2530                         *(BYTE **)((BYTE *)pvStructInfo +
2531                          items[i].pointerOffset) = nextData;
2532                     }
2533                     if (items[i].decodeFunc)
2534                     {
2535                         if (pvStructInfo)
2536                             TRACE("decoding item %ld\n", i);
2537                         else
2538                             TRACE("sizing item %ld\n", i);
2539                         ret = items[i].decodeFunc(dwCertEncodingType,
2540                          NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
2541                          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2542                          pvStructInfo ?  (BYTE *)pvStructInfo + items[i].offset
2543                          : NULL, &items[i].size);
2544                         if (ret)
2545                         {
2546                             if (nextData && items[i].hasPointer &&
2547                              items[i].size > items[i].minSize)
2548                             {
2549                                 nextData += items[i].size - items[i].minSize;
2550                                 /* align nextData to DWORD boundaries */
2551                                 if (items[i].size % sizeof(DWORD))
2552                                     nextData += sizeof(DWORD) - items[i].size %
2553                                      sizeof(DWORD);
2554                             }
2555                             /* Account for alignment padding */
2556                             if (items[i].size % sizeof(DWORD))
2557                                 items[i].size += sizeof(DWORD) -
2558                                  items[i].size % sizeof(DWORD);
2559                             ptr += 1 + nextItemLenBytes + nextItemLen;
2560                         }
2561                         else if (items[i].optional &&
2562                          GetLastError() == CRYPT_E_ASN1_BADTAG)
2563                         {
2564                             TRACE("skipping optional item %ld\n", i);
2565                             items[i].size = items[i].minSize;
2566                             SetLastError(NOERROR);
2567                             ret = TRUE;
2568                         }
2569                         else
2570                             TRACE("item %ld failed: %08lx\n", i,
2571                              GetLastError());
2572                     }
2573                     else
2574                         items[i].size = items[i].minSize;
2575                 }
2576                 else if (items[i].optional)
2577                 {
2578                     TRACE("skipping optional item %ld\n", i);
2579                     items[i].size = items[i].minSize;
2580                 }
2581                 else
2582                 {
2583                     TRACE("tag %02x doesn't match expected %02x\n",
2584                      ptr[0], items[i].tag);
2585                     SetLastError(CRYPT_E_ASN1_BADTAG);
2586                     ret = FALSE;
2587                 }
2588             }
2589         }
2590         else if (items[i].optional)
2591         {
2592             TRACE("missing optional item %ld, skipping\n", i);
2593             items[i].size = items[i].minSize;
2594         }
2595         else
2596         {
2597             TRACE("not enough bytes for item %ld, failing\n", i);
2598             SetLastError(CRYPT_E_ASN1_CORRUPT);
2599             ret = FALSE;
2600         }
2601     }
2602     if (cbEncoded - (ptr - pbEncoded) != 0)
2603     {
2604         TRACE("%ld remaining bytes, failing\n", cbEncoded -
2605          (ptr - pbEncoded));
2606         SetLastError(CRYPT_E_ASN1_CORRUPT);
2607         ret = FALSE;
2608     }
2609     return ret;
2610 }
2611
2612 /* This decodes an arbitrary sequence into a contiguous block of memory
2613  * (basically, a struct.)  Each element being decoded is described by a struct
2614  * AsnDecodeSequenceItem, see above.
2615  * startingPointer is an optional pointer to the first place where dynamic
2616  * data will be stored.  If you know the starting offset, you may pass it
2617  * here.  Otherwise, pass NULL, and one will be inferred from the items.
2618  * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
2619  * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
2620  */
2621 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
2622  struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2623  DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
2624  void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer)
2625 {
2626     BOOL ret;
2627
2628     TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld, %p\n", items, cItem, pbEncoded,
2629      cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
2630      startingPointer);
2631
2632     if (pbEncoded[0] == ASN_SEQUENCE)
2633     {
2634         DWORD dataLen;
2635
2636         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2637         {
2638             DWORD i;
2639
2640             ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, pbEncoded,
2641              cbEncoded, dwFlags, NULL, NULL);
2642             if (ret)
2643             {
2644                 DWORD bytesNeeded = 0, structSize = 0;
2645
2646                 for (i = 0; i < cItem; i++)
2647                 {
2648                     bytesNeeded += items[i].size;
2649                     structSize += items[i].minSize;
2650                 }
2651                 if (!pvStructInfo)
2652                     *pcbStructInfo = bytesNeeded;
2653                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2654                  pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2655                 {
2656                     BYTE *nextData;
2657
2658                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2659                         pvStructInfo = *(BYTE **)pvStructInfo;
2660                     if (startingPointer)
2661                         nextData = (BYTE *)startingPointer;
2662                     else
2663                         nextData = (BYTE *)pvStructInfo + structSize;
2664                     memset(pvStructInfo, 0, structSize);
2665                     ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
2666                      pbEncoded, cbEncoded, dwFlags, pvStructInfo, nextData);
2667                 }
2668             }
2669         }
2670     }
2671     else
2672     {
2673         SetLastError(CRYPT_E_ASN1_BADTAG);
2674         ret = FALSE;
2675     }
2676     TRACE("returning %d (%08lx)\n", ret, GetLastError());
2677     return ret;
2678 }
2679
2680 /* tag:
2681  *     The expected tag of the entire encoded array (usually a variant
2682  *     of ASN_SETOF or ASN_SEQUENCEOF.)
2683  * decodeFunc:
2684  *     used to decode each item in the array
2685  * itemSize:
2686  *      is the minimum size of each decoded item
2687  * hasPointer:
2688  *      indicates whether each item has a dynamic pointer
2689  * pointerOffset:
2690  *     indicates the offset within itemSize at which the pointer exists
2691  */
2692 struct AsnArrayDescriptor
2693 {
2694     BYTE                    tag;
2695     CryptDecodeObjectExFunc decodeFunc;
2696     DWORD                   itemSize;
2697     BOOL                    hasPointer;
2698     DWORD                   pointerOffset;
2699 };
2700
2701 struct AsnArrayItemSize
2702 {
2703     DWORD encodedLen;
2704     DWORD size;
2705 };
2706
2707 struct GenericArray
2708 {
2709     DWORD cItems;
2710     BYTE *rgItems;
2711 };
2712
2713 /* Decodes an array of like types into a struct GenericArray.
2714  * The layout and decoding of the array are described by a struct
2715  * AsnArrayDescriptor.
2716  */
2717 static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc,
2718  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2719  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2720  void *startingPointer)
2721 {
2722     BOOL ret = TRUE;
2723
2724     TRACE("%p, %p, %ld, %08lx, %p, %p, %ld, %p\n", arrayDesc, pbEncoded,
2725      cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
2726      startingPointer);
2727
2728     if (pbEncoded[0] == arrayDesc->tag)
2729     {
2730         DWORD dataLen;
2731
2732         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2733         {
2734             DWORD bytesNeeded, cItems = 0;
2735             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2736             /* There can be arbitrarily many items, but there is often only one.
2737              */
2738             struct AsnArrayItemSize itemSize = { 0 }, *itemSizes = &itemSize;
2739
2740             bytesNeeded = sizeof(struct GenericArray);
2741             if (dataLen)
2742             {
2743                 const BYTE *ptr;
2744
2745                 for (ptr = pbEncoded + 1 + lenBytes; ret &&
2746                  ptr - pbEncoded - 1 - lenBytes < dataLen; )
2747                 {
2748                     DWORD itemLenBytes, itemDataLen, size;
2749
2750                     itemLenBytes = GET_LEN_BYTES(ptr[1]);
2751                     /* Each item decoded may not tolerate extraneous bytes, so
2752                      * get the length of the next element and pass it directly.
2753                      */
2754                     ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2755                      &itemDataLen);
2756                     if (ret)
2757                         ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr,
2758                          1 + itemLenBytes + itemDataLen,
2759                          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
2760                          &size);
2761                     if (ret)
2762                     {
2763                         DWORD nextLen;
2764
2765                         cItems++;
2766                         if (itemSizes != &itemSize)
2767                             itemSizes = CryptMemRealloc(itemSizes,
2768                              cItems * sizeof(struct AsnArrayItemSize));
2769                         else
2770                         {
2771                             itemSizes =
2772                              CryptMemAlloc(
2773                              cItems * sizeof(struct AsnArrayItemSize));
2774                             memcpy(itemSizes, &itemSize, sizeof(itemSize));
2775                         }
2776                         if (itemSizes)
2777                         {
2778                             itemSizes[cItems - 1].encodedLen = 1 + itemLenBytes
2779                              + itemDataLen;
2780                             itemSizes[cItems - 1].size = size;
2781                             bytesNeeded += size;
2782                             ret = CRYPT_GetLen(ptr,
2783                              cbEncoded - (ptr - pbEncoded), &nextLen);
2784                             if (ret)
2785                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2786                         }
2787                         else
2788                             ret = FALSE;
2789                     }
2790                 }
2791             }
2792             if (ret)
2793             {
2794                 if (!pvStructInfo)
2795                     *pcbStructInfo = bytesNeeded;
2796                 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2797                  pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2798                 {
2799                     DWORD i;
2800                     BYTE *nextData;
2801                     const BYTE *ptr;
2802                     struct GenericArray *array;
2803
2804                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2805                         pvStructInfo = *(BYTE **)pvStructInfo;
2806                     array = (struct GenericArray *)pvStructInfo;
2807                     array->cItems = cItems;
2808                     if (startingPointer)
2809                         array->rgItems = startingPointer;
2810                     else
2811                         array->rgItems = (BYTE *)array +
2812                          sizeof(struct GenericArray);
2813                     nextData = (BYTE *)array->rgItems +
2814                      array->cItems * arrayDesc->itemSize;
2815                     for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
2816                      i < cItems && ptr - pbEncoded - 1 - lenBytes <
2817                      dataLen; i++)
2818                     {
2819                         if (arrayDesc->hasPointer)
2820                             *(BYTE **)(array->rgItems + i * arrayDesc->itemSize
2821                              + arrayDesc->pointerOffset) = nextData;
2822                         ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr,
2823                          itemSizes[i].encodedLen,
2824                          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2825                          array->rgItems + i * arrayDesc->itemSize,
2826                          &itemSizes[i].size);
2827                         if (ret)
2828                         {
2829                             DWORD nextLen;
2830
2831                             nextData += itemSizes[i].size - arrayDesc->itemSize;
2832                             ret = CRYPT_GetLen(ptr,
2833                              cbEncoded - (ptr - pbEncoded), &nextLen);
2834                             if (ret)
2835                                 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2836                         }
2837                     }
2838                 }
2839             }
2840             if (itemSizes != &itemSize)
2841                 CryptMemFree(itemSizes);
2842         }
2843     }
2844     else
2845     {
2846         SetLastError(CRYPT_E_ASN1_BADTAG);
2847         ret = FALSE;
2848     }
2849     return ret;
2850 }
2851
2852 /* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
2853  * pvStructInfo.  The BLOB must be non-empty, otherwise the last error is set
2854  * to CRYPT_E_ASN1_CORRUPT.
2855  * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
2856  * set!
2857  */
2858 static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
2859  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2860  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2861 {
2862     BOOL ret;
2863     DWORD dataLen;
2864
2865     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2866     {
2867         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2868         DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
2869        
2870         if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2871             bytesNeeded += 1 + lenBytes + dataLen;
2872
2873         if (!pvStructInfo)
2874             *pcbStructInfo = bytesNeeded;
2875         else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, 
2876          pvStructInfo, pcbStructInfo, bytesNeeded)))
2877         {
2878             CRYPT_DER_BLOB *blob;
2879
2880             if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2881                 pvStructInfo = *(BYTE **)pvStructInfo;
2882             blob = (CRYPT_DER_BLOB *)pvStructInfo;
2883             blob->cbData = 1 + lenBytes + dataLen;
2884             if (blob->cbData)
2885             {
2886                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
2887                     blob->pbData = (BYTE *)pbEncoded;
2888                 else
2889                 {
2890                     assert(blob->pbData);
2891                     memcpy(blob->pbData, pbEncoded, blob->cbData);
2892                 }
2893             }
2894             else
2895             {
2896                 SetLastError(CRYPT_E_ASN1_CORRUPT);
2897                 ret = FALSE;
2898             }
2899         }
2900     }
2901     return ret;
2902 }
2903
2904 /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */
2905 static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType,
2906  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2907  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2908 {
2909     BOOL ret;
2910
2911     TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
2912      pDecodePara, pvStructInfo, *pcbStructInfo);
2913
2914     /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in-
2915      * place.
2916      */
2917     ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType,
2918      pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pDecodePara,
2919      pvStructInfo, pcbStructInfo);
2920     if (ret && pvStructInfo)
2921     {
2922         CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
2923
2924         if (blob->cbData)
2925         {
2926             DWORD i;
2927             BYTE temp;
2928
2929             for (i = 0; i < blob->cbData / 2; i++)
2930             {
2931                 temp = blob->pbData[i];
2932                 blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
2933                 blob->pbData[blob->cbData - i - 1] = temp;
2934             }
2935         }
2936     }
2937     TRACE("returning %d (%08lx)\n", ret, GetLastError());
2938     return ret;
2939 }
2940
2941 static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
2942  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2943  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2944 {
2945     BOOL ret = TRUE;
2946
2947     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
2948      pDecodePara, pvStructInfo, *pcbStructInfo);
2949
2950     __TRY
2951     {
2952         struct AsnDecodeSequenceItem items[] = {
2953          { 0, offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
2954            CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
2955            offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 },
2956          { ASN_SEQUENCEOF, offsetof(CERT_SIGNED_CONTENT_INFO,
2957            SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
2958            sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE,
2959            offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm.pszObjId), 0 },
2960          { ASN_BITSTRING, offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
2961            CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
2962            offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 },
2963         };
2964
2965         if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
2966             items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
2967         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
2968          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
2969          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
2970     }
2971     __EXCEPT_PAGE_FAULT
2972     {
2973         SetLastError(STATUS_ACCESS_VIOLATION);
2974         ret = FALSE;
2975     }
2976     __ENDTRY
2977     return ret;
2978 }
2979
2980 /* Internal function */
2981 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
2982  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2983  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2984 {
2985     BOOL ret;
2986     DWORD dataLen;
2987
2988     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2989     {
2990         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2991
2992         ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
2993          pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
2994          pvStructInfo, pcbStructInfo);
2995     }
2996     return ret;
2997 }
2998
2999 static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
3000  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3001  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3002 {
3003     BOOL ret;
3004
3005     struct AsnDecodeSequenceItem items[] = {
3006      { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
3007        CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
3008      { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
3009        CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
3010     };
3011
3012     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3013      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3014      pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3015     return ret;
3016 }
3017
3018 /* Internal function */
3019 static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType,
3020  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3021  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3022 {
3023     BOOL ret;
3024     DWORD dataLen;
3025
3026     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3027     {
3028         BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3029
3030         ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3031          X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
3032          pDecodePara, pvStructInfo, pcbStructInfo);
3033     }
3034     return ret;
3035 }
3036
3037 static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
3038  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3039  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3040 {
3041     BOOL ret = TRUE;
3042
3043     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3044      pDecodePara, pvStructInfo, *pcbStructInfo);
3045
3046     __TRY
3047     {
3048         struct AsnDecodeSequenceItem items[] = {
3049          { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CERT_INFO, dwVersion),
3050            CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 },
3051          { ASN_INTEGER, offsetof(CERT_INFO, SerialNumber),
3052            CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE,
3053            TRUE, offsetof(CERT_INFO, SerialNumber.pbData), 0 },
3054          { ASN_SEQUENCEOF, offsetof(CERT_INFO, SignatureAlgorithm),
3055            CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3056            FALSE, TRUE, offsetof(CERT_INFO, SignatureAlgorithm.pszObjId), 0 },
3057          { 0, offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
3058            sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
3059            Issuer.pbData) },
3060          { ASN_SEQUENCEOF, offsetof(CERT_INFO, NotBefore),
3061            CRYPT_AsnDecodeValidity, sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE,
3062            FALSE, 0 },
3063          { 0, offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
3064            sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
3065            Subject.pbData) },
3066          /* jil FIXME: shouldn't this have an internal version, which expects
3067           * the pbData to be set?
3068           */
3069          { ASN_SEQUENCEOF, offsetof(CERT_INFO, SubjectPublicKeyInfo),
3070            CRYPT_AsnDecodePubKeyInfo, sizeof(CERT_PUBLIC_KEY_INFO), FALSE,
3071            TRUE, offsetof(CERT_INFO,
3072            SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
3073          { ASN_BITSTRING, offsetof(CERT_INFO, IssuerUniqueId),
3074            CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
3075            offsetof(CERT_INFO, IssuerUniqueId.pbData), 0 },
3076          { ASN_BITSTRING, offsetof(CERT_INFO, SubjectUniqueId),
3077            CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
3078            offsetof(CERT_INFO, SubjectUniqueId.pbData), 0 },
3079          { ASN_CONTEXT | ASN_CONSTRUCTOR | 3, offsetof(CERT_INFO, cExtension),
3080            CRYPT_AsnDecodeCertExtensions, sizeof(CERT_EXTENSIONS), TRUE, TRUE,
3081            offsetof(CERT_INFO, rgExtension), 0 },
3082         };
3083
3084         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3085          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3086          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3087     }
3088     __EXCEPT_PAGE_FAULT
3089     {
3090         SetLastError(STATUS_ACCESS_VIOLATION);
3091         ret = FALSE;
3092     }
3093     __ENDTRY
3094     return ret;
3095 }
3096
3097 static BOOL WINAPI CRYPT_AsnDecodeCRLEntry(DWORD dwCertEncodingType,
3098  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3099  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3100 {
3101     BOOL ret;
3102     struct AsnDecodeSequenceItem items[] = {
3103      { ASN_INTEGER, offsetof(CRL_ENTRY, SerialNumber),
3104        CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE,
3105        offsetof(CRL_ENTRY, SerialNumber.pbData), 0 },
3106      { 0, offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
3107        sizeof(FILETIME), FALSE, FALSE, 0 },
3108      { ASN_SEQUENCEOF, offsetof(CRL_ENTRY, cExtension),
3109        CRYPT_AsnDecodeExtensionsInternal, sizeof(CERT_EXTENSIONS), TRUE, TRUE,
3110        offsetof(CRL_ENTRY, rgExtension), 0 },
3111     };
3112     PCRL_ENTRY entry = (PCRL_ENTRY)pvStructInfo;
3113
3114     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry,
3115      *pcbStructInfo);
3116
3117     ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3118      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3119      NULL, entry, pcbStructInfo, entry ? entry->SerialNumber.pbData : NULL);
3120     return ret;
3121 }
3122
3123 /* Warning: assumes pvStructInfo is a struct GenericArray whose rgItems has
3124  * been set prior to calling.
3125  */
3126 static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
3127  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3128  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3129 {
3130     BOOL ret;
3131     struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
3132      CRYPT_AsnDecodeCRLEntry, sizeof(CRL_ENTRY), TRUE,
3133      offsetof(CRL_ENTRY, SerialNumber.pbData) };
3134     struct GenericArray *entries = (struct GenericArray *)pvStructInfo;
3135
3136     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3137      pDecodePara, pvStructInfo, *pcbStructInfo);
3138
3139     ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3140      pDecodePara, pvStructInfo, pcbStructInfo,
3141      entries ? entries->rgItems : NULL);
3142     TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3143     return ret;
3144 }
3145
3146 static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
3147  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3148  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3149 {
3150     BOOL ret = TRUE;
3151
3152     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3153      pDecodePara, pvStructInfo, *pcbStructInfo);
3154
3155     __TRY
3156     {
3157         struct AsnDecodeSequenceItem items[] = {
3158          { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CRL_INFO, dwVersion),
3159            CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 },
3160          { ASN_SEQUENCEOF, offsetof(CRL_INFO, SignatureAlgorithm),
3161            CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3162            FALSE, TRUE, offsetof(CRL_INFO, SignatureAlgorithm.pszObjId), 0 },
3163          { 0, offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
3164            sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO,
3165            Issuer.pbData) },
3166          { 0, offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
3167            sizeof(FILETIME), FALSE, FALSE, 0 },
3168          { 0, offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
3169            sizeof(FILETIME), TRUE, FALSE, 0 },
3170          { ASN_SEQUENCEOF, offsetof(CRL_INFO, cCRLEntry),
3171            CRYPT_AsnDecodeCRLEntries, sizeof(struct GenericArray), TRUE, TRUE,
3172            offsetof(CRL_INFO, rgCRLEntry), 0 },
3173          /* Note that the extensions are ignored by MS, so I'll ignore them too
3174           */
3175          { 0, offsetof(CRL_INFO, cExtension), NULL,
3176            sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 },
3177         };
3178
3179         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3180          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3181          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3182     }
3183     __EXCEPT_PAGE_FAULT
3184     {
3185         SetLastError(STATUS_ACCESS_VIOLATION);
3186         ret = FALSE;
3187     }
3188     __ENDTRY
3189
3190     TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3191     return ret;
3192 }
3193
3194 /* Differences between this and CRYPT_AsnDecodeOid:
3195  * - pvStructInfo is a LPSTR *, not an LPSTR
3196  * - CRYPT_AsnDecodeOid doesn't account for the size of an LPSTR in its byte
3197  *   count, whereas our callers (typically CRYPT_AsnDecodeSequence) expect this
3198  *   to
3199  */
3200 static BOOL WINAPI CRYPT_AsnDecodeOidWrapper(DWORD dwCertEncodingType,
3201  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3202  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3203 {
3204     BOOL ret;
3205
3206     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3207      pDecodePara, pvStructInfo, *pcbStructInfo);
3208
3209     ret = CRYPT_AsnDecodeOid(pbEncoded, cbEncoded, dwFlags,
3210      pvStructInfo ? *(LPSTR *)pvStructInfo : NULL, pcbStructInfo);
3211     if (ret || GetLastError() == ERROR_MORE_DATA)
3212         *pcbStructInfo += sizeof(LPSTR);
3213     if (ret && pvStructInfo)
3214         TRACE("returning %s\n", debugstr_a(*(LPSTR *)pvStructInfo));
3215     return ret;
3216 }
3217
3218 /* Warning:  assumes pvStructInfo is a CERT_EXTENSION whose pszObjId is set
3219  * ahead of time!
3220  */
3221 static BOOL WINAPI CRYPT_AsnDecodeExtension(DWORD dwCertEncodingType,
3222  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3223  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3224 {
3225     struct AsnDecodeSequenceItem items[] = {
3226      { ASN_OBJECTIDENTIFIER, offsetof(CERT_EXTENSION, pszObjId),
3227        CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE,
3228        offsetof(CERT_EXTENSION, pszObjId), 0 },
3229      { ASN_BOOL, offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool,
3230        sizeof(BOOL), TRUE, FALSE, 0, 0 },
3231      { ASN_OCTETSTRING, offsetof(CERT_EXTENSION, Value),
3232        CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE,
3233        offsetof(CERT_EXTENSION, Value.pbData) },
3234     };
3235     BOOL ret = TRUE;
3236     PCERT_EXTENSION ext = (PCERT_EXTENSION)pvStructInfo;
3237
3238     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, ext,
3239      *pcbStructInfo);
3240
3241     if (ext)
3242         TRACE("ext->pszObjId is %p\n", ext->pszObjId);
3243     ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3244      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
3245      ext, pcbStructInfo, ext ? ext->pszObjId : NULL);
3246     if (ext)
3247         TRACE("ext->pszObjId is %p (%s)\n", ext->pszObjId,
3248          debugstr_a(ext->pszObjId));
3249     TRACE("returning %d (%08lx)\n", ret, GetLastError());
3250     return ret;
3251 }
3252
3253 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
3254  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3255  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3256 {
3257     BOOL ret = TRUE;
3258     struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
3259      CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE,
3260      offsetof(CERT_EXTENSION, pszObjId) };
3261     PCERT_EXTENSIONS exts = (PCERT_EXTENSIONS)pvStructInfo;
3262
3263     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3264      pDecodePara, pvStructInfo, *pcbStructInfo);
3265
3266     ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3267      pDecodePara, pvStructInfo, pcbStructInfo, exts ? exts->rgExtension : NULL);
3268     return ret;
3269 }
3270
3271 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
3272  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3273  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3274 {
3275     BOOL ret = TRUE;
3276
3277     __TRY
3278     {
3279         ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3280          lpszStructType, pbEncoded, cbEncoded,
3281          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
3282         if (ret && pvStructInfo)
3283         {
3284             ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
3285              pcbStructInfo, *pcbStructInfo);
3286             if (ret)
3287             {
3288                 CERT_EXTENSIONS *exts;
3289
3290                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3291                     pvStructInfo = *(BYTE **)pvStructInfo;
3292                 exts = (CERT_EXTENSIONS *)pvStructInfo;
3293                 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
3294                  sizeof(CERT_EXTENSIONS));
3295                 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3296                  lpszStructType, pbEncoded, cbEncoded,
3297                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3298                  pcbStructInfo);
3299             }
3300         }
3301     }
3302     __EXCEPT_PAGE_FAULT
3303     {
3304         SetLastError(STATUS_ACCESS_VIOLATION);
3305         ret = FALSE;
3306     }
3307     __ENDTRY
3308     return ret;
3309 }
3310
3311 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
3312 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
3313  DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
3314 {
3315     BOOL ret = TRUE;
3316
3317     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, pszObjId,
3318      *pcbObjId);
3319
3320     __TRY
3321     {
3322         if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
3323         {
3324             DWORD dataLen;
3325
3326             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3327             {
3328                 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3329                 DWORD bytesNeeded;
3330
3331                 if (dataLen)
3332                 {
3333                     /* The largest possible string for the first two components
3334                      * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
3335                      */
3336                     char firstTwo[6];
3337                     const BYTE *ptr;
3338
3339                     snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
3340                      pbEncoded[1 + lenBytes] / 40,
3341                      pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
3342                      * 40);
3343                     bytesNeeded = strlen(firstTwo) + 1;
3344                     for (ptr = pbEncoded + 2 + lenBytes; ret &&
3345                      ptr - pbEncoded - 1 - lenBytes < dataLen; )
3346                     {
3347                         /* large enough for ".4000000" */
3348                         char str[9];
3349                         int val = 0;
3350
3351                         while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3352                          (*ptr & 0x80))
3353                         {
3354                             val <<= 7;
3355                             val |= *ptr & 0x7f;
3356                             ptr++;
3357                         }
3358                         if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
3359                          (*ptr & 0x80))
3360                         {
3361                             SetLastError(CRYPT_E_ASN1_CORRUPT);
3362                             ret = FALSE;
3363                         }
3364                         else
3365                         {
3366                             val <<= 7;
3367                             val |= *ptr++;
3368                             snprintf(str, sizeof(str), ".%d", val);
3369                             bytesNeeded += strlen(str);
3370                         }
3371                     }
3372                     if (!pszObjId)
3373                         *pcbObjId = bytesNeeded;
3374                     else if (*pcbObjId < bytesNeeded)
3375                     {
3376                         *pcbObjId = bytesNeeded;
3377                         SetLastError(ERROR_MORE_DATA);
3378                         ret = FALSE;
3379                     }
3380                     else
3381                     {
3382                         *pszObjId = 0;
3383                         sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
3384                          pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
3385                          40) * 40);
3386                         pszObjId += strlen(pszObjId);
3387                         for (ptr = pbEncoded + 2 + lenBytes; ret &&
3388                          ptr - pbEncoded - 1 - lenBytes < dataLen; )
3389                         {
3390                             int val = 0;
3391
3392                             while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3393                              (*ptr & 0x80))
3394                             {
3395                                 val <<= 7;
3396                                 val |= *ptr & 0x7f;
3397                                 ptr++;
3398                             }
3399                             val <<= 7;
3400                             val |= *ptr++;
3401                             sprintf(pszObjId, ".%d", val);
3402                             pszObjId += strlen(pszObjId);
3403                         }
3404                     }
3405                 }
3406                 else
3407                     bytesNeeded = 0;
3408                 *pcbObjId = bytesNeeded;
3409             }
3410         }
3411         else
3412         {
3413             SetLastError(CRYPT_E_ASN1_BADTAG);
3414             ret = FALSE;
3415         }
3416     }
3417     __EXCEPT_PAGE_FAULT
3418     {
3419         SetLastError(STATUS_ACCESS_VIOLATION);
3420         ret = FALSE;
3421     }
3422     __ENDTRY
3423     return ret;
3424 }
3425
3426 /* Warning: this assumes the address of value->Value.pbData is already set, in
3427  * order to avoid overwriting memory.  (In some cases, it may change it, if it
3428  * doesn't copy anything to memory.)  Be sure to set it correctly!
3429  */
3430 static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
3431  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3432  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3433 {
3434     BOOL ret = TRUE;
3435
3436     __TRY
3437     {
3438         DWORD dataLen;
3439         CERT_NAME_VALUE *value = (CERT_NAME_VALUE *)pvStructInfo;
3440
3441         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3442         {
3443             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3444
3445             switch (pbEncoded[0])
3446             {
3447             case ASN_NUMERICSTRING:
3448             case ASN_PRINTABLESTRING:
3449             case ASN_IA5STRING:
3450                 break;
3451             default:
3452                 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
3453                 SetLastError(OSS_UNIMPLEMENTED);
3454                 ret = FALSE;
3455             }
3456             if (ret)
3457             {
3458                 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
3459
3460                 switch (pbEncoded[0])
3461                 {
3462                 case ASN_NUMERICSTRING:
3463                 case ASN_PRINTABLESTRING:
3464                 case ASN_IA5STRING:
3465                     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3466                         bytesNeeded += dataLen;
3467                     break;
3468                 }
3469                 if (!value)
3470                     *pcbStructInfo = bytesNeeded;
3471                 else if (*pcbStructInfo < bytesNeeded)
3472                 {
3473                     *pcbStructInfo = bytesNeeded;
3474                     SetLastError(ERROR_MORE_DATA);
3475                     ret = FALSE;
3476                 }
3477                 else
3478                 {
3479                     *pcbStructInfo = bytesNeeded;
3480                     switch (pbEncoded[0])
3481                     {
3482                     case ASN_NUMERICSTRING:
3483                         value->dwValueType = CERT_RDN_NUMERIC_STRING;
3484                         break;
3485                     case ASN_PRINTABLESTRING:
3486                         value->dwValueType = CERT_RDN_PRINTABLE_STRING;
3487                         break;
3488                     case ASN_IA5STRING:
3489                         value->dwValueType = CERT_RDN_IA5_STRING;
3490                         break;
3491                     }
3492                     if (dataLen)
3493                     {
3494                         switch (pbEncoded[0])
3495                         {
3496                         case ASN_NUMERICSTRING:
3497                         case ASN_PRINTABLESTRING:
3498                         case ASN_IA5STRING:
3499                             value->Value.cbData = dataLen;
3500                             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3501                                 value->Value.pbData = (BYTE *)pbEncoded + 1 +
3502                                  lenBytes;
3503                             else
3504                             {
3505                                 assert(value->Value.pbData);
3506                                 memcpy(value->Value.pbData,
3507                                  pbEncoded + 1 + lenBytes, dataLen);
3508                             }
3509                             break;
3510                         }
3511                     }
3512                     else
3513                     {
3514                         value->Value.cbData = 0;
3515                         value->Value.pbData = NULL;
3516                     }
3517                 }
3518             }
3519         }
3520     }
3521     __EXCEPT_PAGE_FAULT
3522     {
3523         SetLastError(STATUS_ACCESS_VIOLATION);
3524         ret = FALSE;
3525     }
3526     __ENDTRY
3527     return ret;
3528 }
3529
3530 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
3531  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3532  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3533 {
3534     BOOL ret;
3535
3536     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3537      pvStructInfo, *pcbStructInfo);
3538
3539     __TRY
3540     {
3541         struct AsnDecodeSequenceItem items[] = {
3542          { ASN_OBJECTIDENTIFIER, offsetof(CERT_RDN_ATTR, pszObjId),
3543            CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE,
3544            offsetof(CERT_RDN_ATTR, pszObjId), 0 },
3545          { 0, offsetof(CERT_RDN_ATTR, dwValueType), CRYPT_AsnDecodeNameValue,
3546            sizeof(CERT_NAME_VALUE), FALSE, TRUE, offsetof(CERT_RDN_ATTR,
3547            Value.pbData), 0 },
3548         };
3549         CERT_RDN_ATTR *attr = (CERT_RDN_ATTR *)pvStructInfo;
3550
3551         if (attr)
3552             TRACE("attr->pszObjId is %p\n", attr->pszObjId);
3553         ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3554          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
3555          attr, pcbStructInfo, attr ? attr->pszObjId : NULL);
3556         if (attr)
3557         {
3558             TRACE("attr->pszObjId is %p (%s)\n", attr->pszObjId,
3559              debugstr_a(attr->pszObjId));
3560             TRACE("attr->dwValueType is %ld\n", attr->dwValueType);
3561         }
3562         TRACE("returning %d (%08lx)\n", ret, GetLastError());
3563     }
3564     __EXCEPT_PAGE_FAULT
3565     {
3566         SetLastError(STATUS_ACCESS_VIOLATION);
3567         ret = FALSE;
3568     }
3569     __ENDTRY
3570     return ret;
3571 }
3572
3573 static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
3574  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3575  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3576 {
3577     BOOL ret = TRUE;
3578
3579     __TRY
3580     {
3581         struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF,
3582          CRYPT_AsnDecodeRdnAttr, sizeof(CERT_RDN_ATTR), TRUE,
3583          offsetof(CERT_RDN_ATTR, pszObjId) };
3584         PCERT_RDN rdn = (PCERT_RDN)pvStructInfo;
3585
3586         ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3587          pDecodePara, pvStructInfo, pcbStructInfo, rdn ? rdn->rgRDNAttr : NULL);
3588     }
3589     __EXCEPT_PAGE_FAULT
3590     {
3591         SetLastError(STATUS_ACCESS_VIOLATION);
3592         ret = FALSE;
3593     }
3594     __ENDTRY
3595     return ret;
3596 }
3597
3598 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
3599  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3600  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3601 {
3602     BOOL ret = TRUE;
3603
3604     __TRY
3605     {
3606         struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
3607          CRYPT_AsnDecodeRdn, sizeof(CERT_RDN), TRUE,
3608          offsetof(CERT_RDN, rgRDNAttr) };
3609
3610         ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3611          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3612     }
3613     __EXCEPT_PAGE_FAULT
3614     {
3615         SetLastError(STATUS_ACCESS_VIOLATION);
3616         ret = FALSE;
3617     }
3618     __ENDTRY
3619     return ret;
3620 }
3621
3622 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
3623  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3624  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3625 {
3626     BOOL ret = TRUE;
3627     DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
3628
3629     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3630      pDecodePara, pvStructInfo, *pcbStructInfo);
3631
3632     if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3633         bytesNeeded += cbEncoded;
3634     if (!pvStructInfo)
3635         *pcbStructInfo = bytesNeeded;
3636     else if (*pcbStructInfo < bytesNeeded)
3637     {
3638         SetLastError(ERROR_MORE_DATA);
3639         *pcbStructInfo = bytesNeeded;
3640         ret = FALSE;
3641     }
3642     else
3643     {
3644         PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
3645
3646         *pcbStructInfo = bytesNeeded;
3647         blob->cbData = cbEncoded;
3648         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3649             blob->pbData = (LPBYTE)pbEncoded;
3650         else
3651         {
3652             assert(blob->pbData);
3653             memcpy(blob->pbData, pbEncoded, blob->cbData);
3654         }
3655     }
3656     return ret;
3657 }
3658
3659 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
3660  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3661  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3662 {
3663     CRYPT_ALGORITHM_IDENTIFIER *algo =
3664      (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
3665     BOOL ret = TRUE;
3666     struct AsnDecodeSequenceItem items[] = {
3667      { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
3668        CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE, 
3669        offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
3670      { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
3671        CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE, 
3672        offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
3673     };
3674
3675     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3676      pDecodePara, pvStructInfo, *pcbStructInfo);
3677
3678     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3679      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3680      pDecodePara, pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
3681     if (ret && pvStructInfo)
3682     {
3683         TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
3684          debugstr_a(algo->pszObjId));
3685     }
3686     return ret;
3687 }
3688
3689 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
3690  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3691  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3692 {
3693     BOOL ret = TRUE;
3694
3695     __TRY
3696     {
3697         struct AsnDecodeSequenceItem items[] = {
3698          { ASN_SEQUENCEOF, offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
3699            CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3700            FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO,
3701            Algorithm.pszObjId) },
3702          { ASN_BITSTRING, offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
3703            CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
3704            offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) },
3705         };
3706
3707         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3708          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3709          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3710     }
3711     __EXCEPT_PAGE_FAULT
3712     {
3713         SetLastError(STATUS_ACCESS_VIOLATION);
3714         ret = FALSE;
3715     }
3716     __ENDTRY
3717     return ret;
3718 }
3719
3720 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
3721  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3722  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3723 {
3724     BOOL ret;
3725
3726     if (cbEncoded < 3)
3727     {
3728         SetLastError(CRYPT_E_ASN1_CORRUPT);
3729         return FALSE;
3730     }
3731     if (GET_LEN_BYTES(pbEncoded[1]) > 1)
3732     {
3733         SetLastError(CRYPT_E_ASN1_CORRUPT);
3734         return FALSE;
3735     }
3736     if (pbEncoded[1] > 1)
3737     {
3738         SetLastError(CRYPT_E_ASN1_CORRUPT);
3739         return FALSE;
3740     }
3741     if (!pvStructInfo)
3742     {
3743         *pcbStructInfo = sizeof(BOOL);
3744         ret = TRUE;
3745     }
3746     else if (*pcbStructInfo < sizeof(BOOL))
3747     {
3748         *pcbStructInfo = sizeof(BOOL);
3749         SetLastError(ERROR_MORE_DATA);
3750         ret = FALSE;
3751     }
3752     else
3753     {
3754         *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
3755         ret = TRUE;
3756     }
3757     TRACE("returning %d (%08lx)\n", ret, GetLastError());
3758     return ret;
3759 }
3760
3761 static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType,
3762  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3763  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3764 {
3765     PCERT_ALT_NAME_ENTRY entry = (PCERT_ALT_NAME_ENTRY)pvStructInfo;
3766     DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY);
3767     BOOL ret;
3768
3769     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3770      pDecodePara, pvStructInfo, *pcbStructInfo);
3771
3772     if (cbEncoded < 2)
3773     {
3774         SetLastError(CRYPT_E_ASN1_CORRUPT);
3775         return FALSE;
3776     }
3777     if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT)
3778     {
3779         SetLastError(CRYPT_E_ASN1_BADTAG);
3780         return FALSE;
3781     }
3782     lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3783     if (1 + lenBytes > cbEncoded)
3784     {
3785         SetLastError(CRYPT_E_ASN1_CORRUPT);
3786         return FALSE;
3787     }
3788     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3789     {
3790         switch (pbEncoded[0] & ASN_TYPE_MASK)
3791         {
3792         case 1: /* rfc822Name */
3793         case 2: /* dNSName */
3794         case 6: /* uniformResourceIdentifier */
3795             bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
3796             break;
3797         case 7: /* iPAddress */
3798             bytesNeeded += dataLen;
3799             break;
3800         case 8: /* registeredID */
3801             /* FIXME: decode as OID */
3802         case 0: /* otherName */
3803         case 4: /* directoryName */
3804             FIXME("stub\n");
3805             SetLastError(CRYPT_E_ASN1_BADTAG);
3806             ret = FALSE;
3807             break;
3808         case 3: /* x400Address, unimplemented */
3809         case 5: /* ediPartyName, unimplemented */
3810             SetLastError(CRYPT_E_ASN1_BADTAG);
3811             ret = FALSE;
3812             break;
3813         default:
3814             SetLastError(CRYPT_E_ASN1_CORRUPT);
3815             ret = FALSE;
3816         }
3817         if (ret)
3818         {
3819             if (!entry)
3820                 *pcbStructInfo = bytesNeeded;
3821             else if (*pcbStructInfo < bytesNeeded)
3822             {
3823                 *pcbStructInfo = bytesNeeded;
3824                 SetLastError(ERROR_MORE_DATA);
3825                 ret = FALSE;
3826             }
3827             else
3828             {
3829                 *pcbStructInfo = bytesNeeded;
3830                 /* MS used values one greater than the asn1 ones.. sigh */
3831                 entry->dwAltNameChoice = (pbEncoded[0] & 0x7f) + 1;
3832                 switch (pbEncoded[0] & ASN_TYPE_MASK)
3833                 {
3834                 case 1: /* rfc822Name */
3835                 case 2: /* dNSName */
3836                 case 6: /* uniformResourceIdentifier */
3837                 {
3838                     DWORD i;
3839
3840                     for (i = 0; i < dataLen; i++)
3841                         entry->u.pwszURL[i] =
3842                          (WCHAR)pbEncoded[1 + lenBytes + i];
3843                     entry->u.pwszURL[i] = 0;
3844                     TRACE("URL is %p (%s)\n", entry->u.pwszURL,
3845                      debugstr_w(entry->u.pwszURL));
3846                     break;
3847                 }
3848                 case 7: /* iPAddress */
3849                     /* The next data pointer is in the pwszURL spot, that is,
3850                      * the first 4 bytes.  Need to move it to the next spot.
3851                      */
3852                     entry->u.IPAddress.pbData = (LPBYTE)entry->u.pwszURL;
3853                     entry->u.IPAddress.cbData = dataLen;
3854                     memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes,
3855                      dataLen);
3856                     break;
3857                 }
3858             }
3859         }
3860     }
3861     return ret;
3862 }
3863
3864 static BOOL WINAPI CRYPT_AsnDecodeAltNameInternal(DWORD dwCertEncodingType,
3865  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3866  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3867 {
3868     BOOL ret = TRUE;
3869     struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
3870      CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE,
3871      offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) };
3872     PCERT_ALT_NAME_INFO info = (PCERT_ALT_NAME_INFO)pvStructInfo;
3873
3874     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3875      pDecodePara, pvStructInfo, *pcbStructInfo);
3876
3877     if (info)
3878         TRACE("info->rgAltEntry is %p\n", info->rgAltEntry);
3879     ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3880      pDecodePara, pvStructInfo, pcbStructInfo, info ? info->rgAltEntry : NULL);
3881     return ret;
3882 }
3883
3884 static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
3885  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3886  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3887 {
3888     BOOL ret = TRUE;
3889
3890     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3891      pDecodePara, pvStructInfo, *pcbStructInfo);
3892
3893     __TRY
3894     {
3895         struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
3896          CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE,
3897          offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) };
3898
3899         ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3900          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3901     }
3902     __EXCEPT_PAGE_FAULT
3903     {
3904         SetLastError(STATUS_ACCESS_VIOLATION);
3905         ret = FALSE;
3906     }
3907     __ENDTRY
3908     return ret;
3909 }
3910
3911 struct PATH_LEN_CONSTRAINT
3912 {
3913     BOOL  fPathLenConstraint;
3914     DWORD dwPathLenConstraint;
3915 };
3916
3917 static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType,
3918  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3919  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3920 {
3921     BOOL ret = TRUE;
3922
3923     TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3924      pvStructInfo, *pcbStructInfo);
3925
3926     if (cbEncoded)
3927     {
3928         if (pbEncoded[0] == ASN_INTEGER)
3929         {
3930             DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT);
3931
3932             if (!pvStructInfo)
3933                 *pcbStructInfo = bytesNeeded;
3934             else if (*pcbStructInfo < bytesNeeded)
3935             {
3936                 SetLastError(ERROR_MORE_DATA);
3937                 *pcbStructInfo = bytesNeeded;
3938                 ret = FALSE;
3939             }
3940             else
3941             {
3942                 struct PATH_LEN_CONSTRAINT *constraint =
3943                  (struct PATH_LEN_CONSTRAINT *)pvStructInfo;
3944                 DWORD size = sizeof(constraint->dwPathLenConstraint);
3945
3946                 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
3947                  pbEncoded, cbEncoded, 0, NULL,
3948                  &constraint->dwPathLenConstraint, &size);
3949                 if (ret)
3950                     constraint->fPathLenConstraint = TRUE;
3951                 TRACE("got an int, dwPathLenConstraint is %ld\n",
3952                  constraint->dwPathLenConstraint);
3953             }
3954         }
3955         else
3956         {
3957             SetLastError(CRYPT_E_ASN1_CORRUPT);
3958             ret = FALSE;
3959         }
3960     }
3961     TRACE("returning %d (%08lx)\n", ret, GetLastError());
3962     return ret;
3963 }
3964
3965 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
3966  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3967  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3968 {
3969     BOOL ret;
3970
3971     __TRY
3972     {
3973         struct AsnDecodeSequenceItem items[] = {
3974          { ASN_BOOL, offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA),
3975            CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, FALSE, 0, 0 },
3976          { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS2_INFO,
3977            fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint,
3978            sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 },
3979         };
3980
3981         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3982          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3983          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3984     }
3985     __EXCEPT_PAGE_FAULT
3986     {
3987         SetLastError(STATUS_ACCESS_VIOLATION);
3988         ret = FALSE;
3989     }
3990     __ENDTRY
3991     return ret;
3992 }
3993
3994 #define RSA1_MAGIC 0x31415352
3995
3996 struct DECODED_RSA_PUB_KEY
3997 {
3998     DWORD              pubexp;
3999     CRYPT_INTEGER_BLOB modulus;
4000 };
4001
4002 static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
4003  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4004  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4005 {
4006     BOOL ret;
4007
4008     __TRY
4009     {
4010         struct AsnDecodeSequenceItem items[] = {
4011          { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, modulus),
4012            CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB),
4013            FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData),
4014            0 },
4015          { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
4016            CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
4017         };
4018         struct DECODED_RSA_PUB_KEY *decodedKey = NULL;
4019         DWORD size = 0;
4020
4021         ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4022          sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
4023          CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL);
4024         if (ret)
4025         {
4026             DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
4027              decodedKey->modulus.cbData;
4028
4029             if (!pvStructInfo)
4030             {
4031                 *pcbStructInfo = bytesNeeded;
4032                 ret = TRUE;
4033             }
4034             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4035              pvStructInfo, pcbStructInfo, bytesNeeded)))
4036             {
4037                 BLOBHEADER *hdr;
4038                 RSAPUBKEY *rsaPubKey;
4039
4040                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4041                     pvStructInfo = *(BYTE **)pvStructInfo;
4042                 hdr = (BLOBHEADER *)pvStructInfo;
4043                 hdr->bType = PUBLICKEYBLOB;
4044                 hdr->bVersion = CUR_BLOB_VERSION;
4045                 hdr->reserved = 0;
4046                 hdr->aiKeyAlg = CALG_RSA_KEYX;
4047                 rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo +
4048                  sizeof(BLOBHEADER));
4049                 rsaPubKey->magic = RSA1_MAGIC;
4050                 rsaPubKey->pubexp = decodedKey->pubexp;
4051                 rsaPubKey->bitlen = decodedKey->modulus.cbData * 8;
4052                 memcpy((BYTE *)pvStructInfo + sizeof(BLOBHEADER) +
4053                  sizeof(RSAPUBKEY), decodedKey->modulus.pbData,
4054                  decodedKey->modulus.cbData);
4055             }
4056             LocalFree(decodedKey);
4057         }
4058     }
4059     __EXCEPT_PAGE_FAULT
4060     {
4061         SetLastError(STATUS_ACCESS_VIOLATION);
4062         ret = FALSE;
4063     }
4064     __ENDTRY
4065     return ret;
4066 }
4067
4068 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
4069  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4070  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4071 {
4072     BOOL ret;
4073     DWORD bytesNeeded, dataLen;
4074
4075     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4076      pDecodePara, pvStructInfo, *pcbStructInfo);
4077
4078     if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4079     {
4080         if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4081             bytesNeeded = sizeof(CRYPT_DATA_BLOB);
4082         else
4083             bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
4084         if (!pvStructInfo)
4085             *pcbStructInfo = bytesNeeded;
4086         else if (*pcbStructInfo < bytesNeeded)
4087         {
4088             SetLastError(ERROR_MORE_DATA);
4089             *pcbStructInfo = bytesNeeded;
4090             ret = FALSE;
4091         }
4092         else
4093         {
4094             CRYPT_DATA_BLOB *blob;
4095             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4096
4097             blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4098             blob->cbData = dataLen;
4099             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4100                 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
4101             else
4102             {
4103                 assert(blob->pbData);
4104                 if (blob->cbData)
4105                     memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
4106                      blob->cbData);
4107             }
4108         }
4109     }
4110     return ret;
4111 }
4112
4113 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
4114  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4115  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4116 {
4117     BOOL ret;
4118
4119     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4120      pDecodePara, pvStructInfo, *pcbStructInfo);
4121
4122     __TRY
4123     {
4124         DWORD bytesNeeded;
4125
4126         if (!cbEncoded)
4127         {
4128             SetLastError(CRYPT_E_ASN1_CORRUPT);
4129             ret = FALSE;
4130         }
4131         else if (pbEncoded[0] != ASN_OCTETSTRING)
4132         {
4133             SetLastError(CRYPT_E_ASN1_BADTAG);
4134             ret = FALSE;
4135         }
4136         else if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4137          lpszStructType, pbEncoded, cbEncoded,
4138          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4139         {
4140             if (!pvStructInfo)
4141                 *pcbStructInfo = bytesNeeded;
4142             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4143              pvStructInfo, pcbStructInfo, bytesNeeded)))
4144             {
4145                 CRYPT_DATA_BLOB *blob;
4146
4147                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4148                     pvStructInfo = *(BYTE **)pvStructInfo;
4149                 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4150                 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB);
4151                 ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4152                  lpszStructType, pbEncoded, cbEncoded,
4153                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4154                  &bytesNeeded);
4155             }
4156         }
4157     }
4158     __EXCEPT_PAGE_FAULT
4159     {
4160         SetLastError(STATUS_ACCESS_VIOLATION);
4161         ret = FALSE;
4162     }
4163     __ENDTRY
4164     return ret;
4165 }
4166
4167 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
4168  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4169  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4170 {
4171     BOOL ret;
4172
4173     TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
4174      pDecodePara, pvStructInfo, *pcbStructInfo);
4175
4176     if (pbEncoded[0] == ASN_BITSTRING)
4177     {
4178         DWORD bytesNeeded, dataLen;
4179
4180         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4181         {
4182             if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4183                 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
4184             else
4185                 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
4186             if (!pvStructInfo)
4187                 *pcbStructInfo = bytesNeeded;
4188             else if (*pcbStructInfo < bytesNeeded)
4189             {
4190                 *pcbStructInfo = bytesNeeded;
4191                 SetLastError(ERROR_MORE_DATA);
4192                 ret = FALSE;
4193             }
4194             else
4195             {
4196                 CRYPT_BIT_BLOB *blob;
4197
4198                 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4199                 blob->cbData = dataLen - 1;
4200                 blob->cUnusedBits = *(pbEncoded + 1 +
4201                  GET_LEN_BYTES(pbEncoded[1]));
4202                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4203                 {
4204                     blob->pbData = (BYTE *)pbEncoded + 2 +
4205                      GET_LEN_BYTES(pbEncoded[1]);
4206                 }
4207                 else
4208                 {
4209                     assert(blob->pbData);
4210                     if (blob->cbData)
4211                     {
4212                         BYTE mask = 0xff << blob->cUnusedBits;
4213
4214                         memcpy(blob->pbData, pbEncoded + 2 +
4215                          GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
4216                         blob->pbData[blob->cbData - 1] &= mask;
4217                     }
4218                 }
4219             }
4220         }
4221     }
4222     else
4223     {
4224         SetLastError(CRYPT_E_ASN1_BADTAG);
4225         ret = FALSE;
4226     }
4227     TRACE("returning %d (%08lx)\n", ret, GetLastError());
4228     return ret;
4229 }
4230
4231 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
4232  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4233  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4234 {
4235     BOOL ret;
4236
4237     TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
4238      pDecodePara, pvStructInfo, pcbStructInfo);
4239
4240     __TRY
4241     {
4242         DWORD bytesNeeded;
4243
4244         if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4245          lpszStructType, pbEncoded, cbEncoded,
4246          dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4247         {
4248             if (!pvStructInfo)
4249                 *pcbStructInfo = bytesNeeded;
4250             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4251              pvStructInfo, pcbStructInfo, bytesNeeded)))
4252             {
4253                 CRYPT_BIT_BLOB *blob;
4254
4255                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4256                     pvStructInfo = *(BYTE **)pvStructInfo;
4257                 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4258                 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
4259                 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4260                  lpszStructType, pbEncoded, cbEncoded,
4261                  dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4262                  &bytesNeeded);
4263             }
4264         }
4265     }
4266     __EXCEPT_PAGE_FAULT
4267     {
4268         SetLastError(STATUS_ACCESS_VIOLATION);
4269         ret = FALSE;
4270     }
4271     __ENDTRY
4272     TRACE("returning %d (%08lx)\n", ret, GetLastError());
4273     return ret;
4274 }
4275
4276 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
4277  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4278  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4279 {
4280     BOOL ret;
4281
4282     if (!pvStructInfo)
4283     {
4284         *pcbStructInfo = sizeof(int);
4285         return TRUE;
4286     }
4287     __TRY
4288     {
4289         BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
4290         CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
4291         DWORD size = sizeof(buf);
4292
4293         blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
4294         ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4295          X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
4296         if (ret)
4297         {
4298             if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4299              pvStructInfo, pcbStructInfo, sizeof(int))))
4300             {
4301                 int val, i;
4302
4303                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4304                     pvStructInfo = *(BYTE **)pvStructInfo;
4305                 if (blob->pbData[blob->cbData - 1] & 0x80)
4306                 {
4307                     /* initialize to a negative value to sign-extend */
4308                     val = -1;
4309                 }
4310                 else
4311                     val = 0;
4312                 for (i = 0; i < blob->cbData; i++)
4313                 {
4314                     val <<= 8;
4315                     val |= blob->pbData[blob->cbData - i - 1];
4316                 }
4317                 memcpy(pvStructInfo, &val, sizeof(int));
4318             }
4319         }
4320         else if (GetLastError() == ERROR_MORE_DATA)
4321             SetLastError(CRYPT_E_ASN1_LARGE);
4322     }
4323     __EXCEPT_PAGE_FAULT
4324     {
4325         SetLastError(STATUS_ACCESS_VIOLATION);
4326         ret = FALSE;
4327     }
4328     __ENDTRY
4329     return ret;
4330 }
4331
4332 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
4333  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4334  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4335 {
4336     BOOL ret;
4337
4338     if (pbEncoded[0] == ASN_INTEGER)
4339     {
4340         DWORD bytesNeeded, dataLen;
4341
4342         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4343         {
4344             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4345
4346             bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4347             if (!pvStructInfo)
4348                 *pcbStructInfo = bytesNeeded;
4349             else if (*pcbStructInfo < bytesNeeded)
4350             {
4351                 *pcbStructInfo = bytesNeeded;
4352                 SetLastError(ERROR_MORE_DATA);
4353                 ret = FALSE;
4354             }
4355             else
4356             {
4357                 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4358
4359                 blob->cbData = dataLen;
4360                 assert(blob->pbData);
4361                 if (blob->cbData)
4362                 {
4363                     DWORD i;
4364
4365                     for (i = 0; i < blob->cbData; i++)
4366                     {
4367                         blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4368                          dataLen - i - 1);
4369                     }
4370                 }
4371             }
4372         }
4373     }
4374     else
4375     {
4376         SetLastError(CRYPT_E_ASN1_BADTAG);
4377         ret = FALSE;
4378     }
4379     return ret;
4380 }
4381
4382 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
4383  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4384  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4385 {
4386     BOOL ret;
4387
4388     __TRY
4389     {
4390         DWORD bytesNeeded;
4391
4392         if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4393          lpszStructType, pbEncoded, cbEncoded,
4394          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4395         {
4396             if (!pvStructInfo)
4397                 *pcbStructInfo = bytesNeeded;
4398             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4399              pvStructInfo, pcbStructInfo, bytesNeeded)))
4400             {
4401                 CRYPT_INTEGER_BLOB *blob;
4402
4403                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4404                     pvStructInfo = *(BYTE **)pvStructInfo;
4405                 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4406                 blob->pbData = (BYTE *)pvStructInfo +
4407                  sizeof(CRYPT_INTEGER_BLOB);
4408                 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4409                  lpszStructType, pbEncoded, cbEncoded,
4410                  dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4411                  &bytesNeeded);
4412             }
4413         }
4414     }
4415     __EXCEPT_PAGE_FAULT
4416     {
4417         SetLastError(STATUS_ACCESS_VIOLATION);
4418         ret = FALSE;
4419     }
4420     __ENDTRY
4421     return ret;
4422 }
4423
4424 static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
4425  DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
4426  DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
4427  void *pvStructInfo, DWORD *pcbStructInfo)
4428 {
4429     BOOL ret;
4430
4431     if (pbEncoded[0] == ASN_INTEGER)
4432     {
4433         DWORD bytesNeeded, dataLen;
4434
4435         if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4436         {
4437             BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4438
4439             bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4440             if (!pvStructInfo)
4441                 *pcbStructInfo = bytesNeeded;
4442             else if (*pcbStructInfo < bytesNeeded)
4443             {
4444                 *pcbStructInfo = bytesNeeded;
4445                 SetLastError(ERROR_MORE_DATA);
4446                 ret = FALSE;
4447             }
4448             else
4449             {
4450                 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4451
4452                 blob->cbData = dataLen;
4453                 assert(blob->pbData);
4454                 /* remove leading zero byte if it exists */
4455                 if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
4456                 {
4457                     blob->cbData--;
4458                     blob->pbData++;
4459                 }
4460                 if (blob->cbData)
4461                 {
4462                     DWORD i;
4463
4464                     for (i = 0; i < blob->cbData; i++)
4465                     {
4466                         blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4467                          dataLen - i - 1);
4468                     }
4469                 }
4470             }
4471         }
4472     }
4473     else
4474     {
4475         SetLastError(CRYPT_E_ASN1_BADTAG);
4476         ret = FALSE;
4477     }
4478     return ret;
4479 }
4480
4481 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
4482  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4483  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4484 {
4485     BOOL ret;
4486
4487     __TRY
4488     {
4489         DWORD bytesNeeded;
4490
4491         if ((ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType,
4492          lpszStructType, pbEncoded, cbEncoded,
4493          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4494         {
4495             if (!pvStructInfo)
4496                 *pcbStructInfo = bytesNeeded;
4497             else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4498              pvStructInfo, pcbStructInfo, bytesNeeded)))
4499             {
4500                 CRYPT_INTEGER_BLOB *blob;
4501
4502                 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4503                     pvStructInfo = *(BYTE **)pvStructInfo;
4504                 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4505                 blob->pbData = (BYTE *)pvStructInfo +
4506                  sizeof(CRYPT_INTEGER_BLOB);
4507                 ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType,
4508                  lpszStructType, pbEncoded, cbEncoded,
4509                  dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4510                  &bytesNeeded);
4511             }
4512         }
4513     }
4514     __EXCEPT_PAGE_FAULT
4515     {
4516         SetLastError(STATUS_ACCESS_VIOLATION);
4517         ret = FALSE;
4518     }
4519     __ENDTRY
4520     return ret;
4521 }
4522
4523 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
4524  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4525  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4526 {
4527     BOOL ret;
4528
4529     if (!pvStructInfo)
4530     {
4531         *pcbStructInfo = sizeof(int);
4532         return TRUE;
4533     }
4534     __TRY
4535     {
4536         if (pbEncoded[0] == ASN_ENUMERATED)
4537         {
4538             unsigned int val = 0, i;
4539
4540             if (cbEncoded <= 1)
4541             {
4542                 SetLastError(CRYPT_E_ASN1_EOD);
4543                 ret = FALSE;
4544             }
4545             else if (pbEncoded[1] == 0)
4546             {
4547                 SetLastError(CRYPT_E_ASN1_CORRUPT);
4548                 ret = FALSE;
4549             }
4550             else
4551             {
4552                 /* A little strange looking, but we have to accept a sign byte:
4553                  * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff.  Also,
4554                  * assuming a small length is okay here, it has to be in short
4555                  * form.
4556                  */
4557                 if (pbEncoded[1] > sizeof(unsigned int) + 1)
4558                 {
4559                     SetLastError(CRYPT_E_ASN1_LARGE);
4560                     return FALSE;
4561                 }
4562                 for (i = 0; i < pbEncoded[1]; i++)
4563                 {
4564                     val <<= 8;
4565                     val |= pbEncoded[2 + i];
4566                 }
4567                 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4568                  pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
4569                 {
4570                     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4571                         pvStructInfo = *(BYTE **)pvStructInfo;
4572                     memcpy(pvStructInfo, &val, sizeof(unsigned int));
4573                 }
4574             }
4575         }
4576         else
4577         {
4578             SetLastError(CRYPT_E_ASN1_BADTAG);
4579             ret = FALSE;
4580         }
4581     }
4582     __EXCEPT_PAGE_FAULT
4583     {
4584         SetLastError(STATUS_ACCESS_VIOLATION);
4585         ret = FALSE;
4586     }
4587     __ENDTRY
4588     return ret;
4589 }
4590
4591 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
4592  * if it fails.
4593  */
4594 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
4595  do { \
4596     BYTE i; \
4597  \
4598     (word) = 0; \
4599     for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
4600     { \
4601         if (!isdigit(*(pbEncoded))) \
4602         { \
4603             SetLastError(CRYPT_E_ASN1_CORRUPT); \
4604             ret = FALSE; \
4605         } \
4606         else \
4607         { \
4608             (word) *= 10; \
4609             (word) += *(pbEncoded)++ - '0'; \
4610         } \
4611     } \
4612  } while (0)
4613
4614 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
4615  SYSTEMTIME *sysTime)
4616 {
4617     BOOL ret;
4618
4619     __TRY
4620     {
4621         ret = TRUE;
4622         if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
4623         {
4624             WORD hours, minutes = 0;
4625             BYTE sign = *pbEncoded++;
4626
4627             len--;
4628             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
4629             if (ret && hours >= 24)
4630             {
4631                 SetLastError(CRYPT_E_ASN1_CORRUPT);
4632                 ret = FALSE;
4633             }
4634             else if (len >= 2)
4635             {
4636                 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
4637                 if (ret && minutes >= 60)
4638                 {
4639                     SetLastError(CRYPT_E_ASN1_CORRUPT);
4640                     ret = FALSE;
4641                 }
4642             }
4643             if (ret)
4644             {
4645                 if (sign == '+')
4646                 {
4647                     sysTime->wHour += hours;
4648                     sysTime->wMinute += minutes;
4649                 }
4650                 else
4651                 {
4652                     if (hours > sysTime->wHour)
4653                     {
4654                         sysTime->wDay--;
4655                         sysTime->wHour = 24 - (hours - sysTime->wHour);
4656                     }
4657                     else
4658                         sysTime->wHour -= hours;
4659                     if (minutes > sysTime->wMinute)
4660                     {
4661                         sysTime->wHour--;
4662                         sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
4663                     }
4664                     else
4665                         sysTime->wMinute -= minutes;
4666                 }
4667             }
4668         }
4669     }
4670     __EXCEPT_PAGE_FAULT
4671     {
4672         SetLastError(STATUS_ACCESS_VIOLATION);
4673         ret = FALSE;
4674     }
4675     __ENDTRY
4676     return ret;
4677 }
4678
4679 #define MIN_ENCODED_TIME_LENGTH 10
4680
4681 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
4682  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4683  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4684 {
4685     BOOL ret;
4686
4687     if (!pvStructInfo)
4688     {
4689         *pcbStructInfo = sizeof(FILETIME);
4690         return TRUE;
4691     }
4692     __TRY
4693     {
4694         ret = TRUE;
4695         if (pbEncoded[0] == ASN_UTCTIME)
4696         {
4697             if (cbEncoded <= 1)
4698             {
4699                 SetLastError(CRYPT_E_ASN1_EOD);
4700                 ret = FALSE;
4701             }
4702             else if (pbEncoded[1] > 0x7f)
4703             {
4704                 /* long-form date strings really can't be valid */
4705                 SetLastError(CRYPT_E_ASN1_CORRUPT);
4706                 ret = FALSE;
4707             }
4708             else
4709             {
4710                 SYSTEMTIME sysTime = { 0 };
4711                 BYTE len = pbEncoded[1];
4712
4713                 if (len < MIN_ENCODED_TIME_LENGTH)
4714                 {
4715                     SetLastError(CRYPT_E_ASN1_CORRUPT);
4716                     ret = FALSE;
4717                 }
4718                 else
4719                 {
4720                     pbEncoded += 2;
4721                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
4722                     if (sysTime.wYear >= 50)
4723                         sysTime.wYear += 1900;
4724                     else
4725                         sysTime.wYear += 2000;
4726                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
4727                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
4728                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
4729                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
4730                     if (ret && len > 0)
4731                     {
4732                         if (len >= 2 && isdigit(*pbEncoded) &&
4733                          isdigit(*(pbEncoded + 1)))
4734                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4735                              sysTime.wSecond);
4736                         else if (isdigit(*pbEncoded))
4737                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
4738                              sysTime.wSecond);
4739                         if (ret)
4740                             ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
4741                              &sysTime);
4742                     }
4743                     if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
4744                      pDecodePara, pvStructInfo, pcbStructInfo,
4745                      sizeof(FILETIME))))
4746                     {
4747                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4748                             pvStructInfo = *(BYTE **)pvStructInfo;
4749                         ret = SystemTimeToFileTime(&sysTime,
4750                          (FILETIME *)pvStructInfo);
4751                     }
4752                 }
4753             }
4754         }
4755         else
4756         {
4757             SetLastError(CRYPT_E_ASN1_BADTAG);
4758             ret = FALSE;
4759         }
4760     }
4761     __EXCEPT_PAGE_FAULT
4762     {
4763         SetLastError(STATUS_ACCESS_VIOLATION);
4764         ret = FALSE;
4765     }
4766     __ENDTRY
4767     return ret;
4768 }
4769
4770 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
4771  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4772  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4773 {
4774     BOOL ret;
4775
4776     if (!pvStructInfo)
4777     {
4778         *pcbStructInfo = sizeof(FILETIME);
4779         return TRUE;
4780     }
4781     __TRY
4782     {
4783         ret = TRUE;
4784         if (pbEncoded[0] == ASN_GENERALTIME)
4785         {
4786             if (cbEncoded <= 1)
4787             {
4788                 SetLastError(CRYPT_E_ASN1_EOD);
4789                 ret = FALSE;
4790             }
4791             else if (pbEncoded[1] > 0x7f)
4792             {
4793                 /* long-form date strings really can't be valid */
4794                 SetLastError(CRYPT_E_ASN1_CORRUPT);
4795                 ret = FALSE;
4796             }
4797             else
4798             {
4799                 BYTE len = pbEncoded[1];
4800
4801                 if (len < MIN_ENCODED_TIME_LENGTH)
4802                 {
4803                     SetLastError(CRYPT_E_ASN1_CORRUPT);
4804                     ret = FALSE;
4805                 }
4806                 else
4807                 {
4808                     SYSTEMTIME sysTime = { 0 };
4809
4810                     pbEncoded += 2;
4811                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
4812                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
4813                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
4814                     CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
4815                     if (ret && len > 0)
4816                     {
4817                         CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4818                          sysTime.wMinute);
4819                         if (ret && len > 0)
4820                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4821                              sysTime.wSecond);
4822                         if (ret && len > 0 && (*pbEncoded == '.' ||
4823                          *pbEncoded == ','))
4824                         {
4825                             BYTE digits;
4826
4827                             pbEncoded++;
4828                             len--;
4829                             /* workaround macro weirdness */
4830                             digits = min(len, 3);
4831                             CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
4832                              sysTime.wMilliseconds);
4833                         }
4834                         if (ret)
4835                             ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
4836                              &sysTime);
4837                     }
4838                     if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
4839                      pDecodePara, pvStructInfo, pcbStructInfo,
4840                      sizeof(FILETIME))))
4841                     {
4842                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4843                             pvStructInfo = *(BYTE **)pvStructInfo;
4844                         ret = SystemTimeToFileTime(&sysTime,
4845                          (FILETIME *)pvStructInfo);
4846                     }
4847                 }
4848             }
4849         }
4850         else
4851         {
4852             SetLastError(CRYPT_E_ASN1_BADTAG);
4853             ret = FALSE;
4854         }
4855     }
4856     __EXCEPT_PAGE_FAULT
4857     {
4858         SetLastError(STATUS_ACCESS_VIOLATION);
4859         ret = FALSE;
4860     }
4861     __ENDTRY
4862     return ret;
4863 }
4864
4865 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
4866  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4867  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4868 {
4869     BOOL ret;
4870
4871     __TRY
4872     {
4873         if (pbEncoded[0] == ASN_UTCTIME)
4874             ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
4875              pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
4876              pcbStructInfo);
4877         else if (pbEncoded[0] == ASN_GENERALTIME)
4878             ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
4879              lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
4880              pvStructInfo, pcbStructInfo);
4881         else
4882         {
4883             SetLastError(CRYPT_E_ASN1_BADTAG);
4884             ret = FALSE;
4885         }
4886     }
4887     __EXCEPT_PAGE_FAULT
4888     {
4889         SetLastError(STATUS_ACCESS_VIOLATION);
4890         ret = FALSE;
4891     }
4892     __ENDTRY
4893     return ret;
4894 }
4895
4896 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
4897  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4898  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4899 {
4900     BOOL ret = TRUE;
4901
4902     __TRY
4903     {
4904         if (pbEncoded[0] == ASN_SEQUENCEOF)
4905         {
4906             DWORD bytesNeeded, dataLen, remainingLen, cValue;
4907
4908             if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4909             {
4910                 BYTE lenBytes;
4911                 const BYTE *ptr;
4912
4913                 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4914                 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
4915                 cValue = 0;
4916                 ptr = pbEncoded + 1 + lenBytes;
4917                 remainingLen = dataLen;
4918                 while (ret && remainingLen)
4919                 {
4920                     DWORD nextLen;
4921
4922                     ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
4923                     if (ret)
4924                     {
4925                         DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
4926
4927                         remainingLen -= 1 + nextLenBytes + nextLen;
4928                         ptr += 1 + nextLenBytes + nextLen;
4929                         bytesNeeded += sizeof(CRYPT_DER_BLOB);
4930                         if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
4931                             bytesNeeded += 1 + nextLenBytes + nextLen;
4932                         cValue++;
4933                     }
4934                 }
4935                 if (ret)
4936                 {
4937                     CRYPT_SEQUENCE_OF_ANY *seq;
4938                     BYTE *nextPtr;
4939                     DWORD i;
4940
4941                     if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4942                      pvStructInfo, pcbStructInfo, bytesNeeded)))
4943                     {
4944                         if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4945                             pvStructInfo = *(BYTE **)pvStructInfo;
4946                         seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
4947                         seq->cValue = cValue;
4948                         seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
4949                          sizeof(*seq));
4950                         nextPtr = (BYTE *)seq->rgValue +
4951                          cValue * sizeof(CRYPT_DER_BLOB);
4952                         ptr = pbEncoded + 1 + lenBytes;
4953                         remainingLen = dataLen;
4954                         i = 0;
4955                         while (ret && remainingLen)
4956                         {
4957                             DWORD nextLen;
4958
4959                             ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
4960                             if (ret)
4961                             {
4962                                 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
4963
4964                                 seq->rgValue[i].cbData = 1 + nextLenBytes +
4965                                  nextLen;
4966                                 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4967                                     seq->rgValue[i].pbData = (BYTE *)ptr;
4968                                 else
4969                                 {
4970                                     seq->rgValue[i].pbData = nextPtr;
4971                                     memcpy(nextPtr, ptr, 1 + nextLenBytes +
4972                                      nextLen);
4973                                     nextPtr += 1 + nextLenBytes + nextLen;
4974                                 }
4975                                 remainingLen -= 1 + nextLenBytes + nextLen;
4976                                 ptr += 1 + nextLenBytes + nextLen;
4977                                 i++;
4978                             }
4979                         }
4980                     }
4981                 }
4982             }
4983         }
4984         else
4985         {
4986             SetLastError(CRYPT_E_ASN1_BADTAG);
4987             return FALSE;
4988         }
4989     }
4990     __EXCEPT_PAGE_FAULT
4991     {
4992         SetLastError(STATUS_ACCESS_VIOLATION);
4993         ret = FALSE;
4994     }
4995     __ENDTRY
4996     return ret;
4997 }
4998
4999 static BOOL WINAPI CRYPT_AsnDecodeDistPoint(DWORD dwCertEncodingType,
5000  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5001  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5002 {
5003     struct AsnDecodeSequenceItem items[] = {
5004      { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CRL_DIST_POINT,
5005        DistPointName), CRYPT_AsnDecodeAltNameInternal,
5006        sizeof(CRL_DIST_POINT_NAME), TRUE, TRUE, offsetof(CRL_DIST_POINT,
5007        DistPointName.u.FullName.rgAltEntry), 0 },
5008      { ASN_CONTEXT | 1, offsetof(CRL_DIST_POINT, ReasonFlags),
5009        CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
5010        offsetof(CRL_DIST_POINT, ReasonFlags.pbData), 0 },
5011      { ASN_CONTEXT | ASN_CONSTRUCTOR | 2, offsetof(CRL_DIST_POINT, CRLIssuer),
5012        CRYPT_AsnDecodeAltNameInternal, sizeof(CERT_ALT_NAME_INFO), TRUE, TRUE,
5013        offsetof(CRL_DIST_POINT, CRLIssuer.rgAltEntry), 0 },
5014     };
5015     BOOL ret;
5016
5017     ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
5018      sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
5019      dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL);
5020     return ret;
5021 }
5022
5023 static BOOL WINAPI CRYPT_AsnDecodeCRLDistPoints(DWORD dwCertEncodingType,
5024  LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5025  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5026 {
5027     BOOL ret;
5028
5029     TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
5030      pDecodePara, pvStructInfo, *pcbStructInfo);
5031
5032     __TRY
5033     {
5034         struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
5035          CRYPT_AsnDecodeDistPoint, sizeof(CRL_DIST_POINT), TRUE,
5036          offsetof(CRL_DIST_POINT, DistPointName.u.FullName.rgAltEntry) };
5037
5038         ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
5039          pDecodePara, pvStructInfo, pcbStructInfo, NULL);
5040     }
5041     __EXCEPT_PAGE_FAULT
5042     {
5043         SetLastError(STATUS_ACCESS_VIOLATION);
5044         ret = FALSE;
5045     }
5046     __ENDTRY
5047     return ret;
5048 }
5049
5050 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
5051  const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5052  PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5053 {
5054     static HCRYPTOIDFUNCSET set = NULL;
5055     BOOL ret = FALSE;
5056     CryptDecodeObjectExFunc decodeFunc = NULL;
5057     HCRYPTOIDFUNCADDR hFunc = NULL;
5058
5059     TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
5060      dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded,
5061      cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5062
5063     if (!pvStructInfo && !pcbStructInfo)
5064     {
5065         SetLastError(ERROR_INVALID_PARAMETER);
5066         return FALSE;
5067     }
5068     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
5069      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
5070     {
5071         SetLastError(ERROR_FILE_NOT_FOUND);
5072         return FALSE;
5073     }
5074     if (!cbEncoded)
5075     {
5076         SetLastError(CRYPT_E_ASN1_EOD);
5077         return FALSE;
5078     }
5079     if (cbEncoded > MAX_ENCODED_LEN)
5080     {
5081         SetLastError(CRYPT_E_ASN1_LARGE);
5082         return FALSE;
5083     }
5084
5085     SetLastError(NOERROR);
5086     if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
5087         *(BYTE **)pvStructInfo = NULL;
5088     if (!HIWORD(lpszStructType))
5089     {
5090         switch (LOWORD(lpszStructType))
5091         {
5092         case (WORD)X509_CERT:
5093             decodeFunc = CRYPT_AsnDecodeCert;
5094             break;
5095         case (WORD)X509_CERT_TO_BE_SIGNED:
5096             decodeFunc = CRYPT_AsnDecodeCertInfo;
5097             break;
5098         case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
5099             decodeFunc = CRYPT_AsnDecodeCRLInfo;
5100             break;
5101         case (WORD)X509_EXTENSIONS:
5102             decodeFunc = CRYPT_AsnDecodeExtensions;
5103             break;
5104         case (WORD)X509_NAME:
5105             decodeFunc = CRYPT_AsnDecodeName;
5106             break;
5107         case (WORD)X509_PUBLIC_KEY_INFO:
5108             decodeFunc = CRYPT_AsnDecodePubKeyInfo;
5109             break;
5110         case (WORD)X509_ALTERNATE_NAME:
5111             decodeFunc = CRYPT_AsnDecodeAltName;
5112             break;
5113         case (WORD)X509_BASIC_CONSTRAINTS2:
5114             decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5115             break;
5116         case (WORD)RSA_CSP_PUBLICKEYBLOB:
5117             decodeFunc = CRYPT_AsnDecodeRsaPubKey;
5118             break;
5119         case (WORD)X509_OCTET_STRING:
5120             decodeFunc = CRYPT_AsnDecodeOctets;
5121             break;
5122         case (WORD)X509_BITS:
5123         case (WORD)X509_KEY_USAGE:
5124             decodeFunc = CRYPT_AsnDecodeBits;
5125             break;
5126         case (WORD)X509_INTEGER:
5127             decodeFunc = CRYPT_AsnDecodeInt;
5128             break;
5129         case (WORD)X509_MULTI_BYTE_INTEGER:
5130             decodeFunc = CRYPT_AsnDecodeInteger;
5131             break;
5132         case (WORD)X509_MULTI_BYTE_UINT:
5133             decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
5134             break;
5135         case (WORD)X509_ENUMERATED:
5136             decodeFunc = CRYPT_AsnDecodeEnumerated;
5137             break;
5138         case (WORD)X509_CHOICE_OF_TIME:
5139             decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
5140             break;
5141         case (WORD)X509_SEQUENCE_OF_ANY:
5142             decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
5143             break;
5144         case (WORD)PKCS_UTC_TIME:
5145             decodeFunc = CRYPT_AsnDecodeUtcTime;
5146             break;
5147         case (WORD)X509_CRL_DIST_POINTS:
5148             decodeFunc = CRYPT_AsnDecodeCRLDistPoints;
5149             break;
5150         default:
5151             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
5152         }
5153     }
5154     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
5155         decodeFunc = CRYPT_AsnDecodeExtensions;
5156     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
5157         decodeFunc = CRYPT_AsnDecodeUtcTime;
5158     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
5159         decodeFunc = CRYPT_AsnDecodeEnumerated;
5160     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
5161         decodeFunc = CRYPT_AsnDecodeBits;
5162     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
5163         decodeFunc = CRYPT_AsnDecodeOctets;
5164     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
5165         decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5166     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
5167         decodeFunc = CRYPT_AsnDecodeAltName;
5168     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
5169         decodeFunc = CRYPT_AsnDecodeAltName;
5170     else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
5171         decodeFunc = CRYPT_AsnDecodeAltName;
5172     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
5173         decodeFunc = CRYPT_AsnDecodeAltName;
5174     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
5175         decodeFunc = CRYPT_AsnDecodeAltName;
5176     else
5177         TRACE("OID %s not found or unimplemented, looking for DLL\n",
5178          debugstr_a(lpszStructType));
5179     if (!decodeFunc)
5180     {
5181         if (!set)
5182             set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_EX_FUNC, 0);
5183         CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
5184          (void **)&decodeFunc, &hFunc);
5185     }
5186     if (decodeFunc)
5187         ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
5188          cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5189     else
5190         SetLastError(ERROR_FILE_NOT_FOUND);
5191     if (hFunc)
5192         CryptFreeOIDFunctionAddress(hFunc, 0);
5193     return ret;
5194 }
5195
5196 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
5197  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5198 {
5199     return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
5200      NULL, 0, NULL, pInfo, pcbInfo);
5201 }
5202
5203 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5204  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
5205  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5206 {
5207     BOOL ret;
5208     HCRYPTKEY key;
5209
5210     TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
5211      dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
5212      pInfo, pcbInfo);
5213
5214     if (!pszPublicKeyObjId)
5215         pszPublicKeyObjId = szOID_RSA_RSA;
5216     if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
5217     {
5218         DWORD keySize = 0;
5219
5220         ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
5221         if (ret)
5222         {
5223             LPBYTE pubKey = CryptMemAlloc(keySize);
5224
5225             if (pubKey)
5226             {
5227                 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
5228                  &keySize);
5229                 if (ret)
5230                 {
5231                     DWORD encodedLen = 0;
5232
5233                     ret = CryptEncodeObject(dwCertEncodingType,
5234                      RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
5235                     if (ret)
5236                     {
5237                         DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
5238                          strlen(pszPublicKeyObjId) + 1 + encodedLen;
5239
5240                         if (!pInfo)
5241                             *pcbInfo = sizeNeeded;
5242                         else if (*pcbInfo < sizeNeeded)
5243                         {
5244                             SetLastError(ERROR_MORE_DATA);
5245                             *pcbInfo = sizeNeeded;
5246                             ret = FALSE;
5247                         }
5248                         else
5249                         {
5250                             pInfo->Algorithm.pszObjId = (char *)pInfo +
5251                              sizeof(CERT_PUBLIC_KEY_INFO);
5252                             lstrcpyA(pInfo->Algorithm.pszObjId,
5253                              pszPublicKeyObjId);
5254                             pInfo->Algorithm.Parameters.cbData = 0;
5255                             pInfo->Algorithm.Parameters.pbData = NULL;
5256                             pInfo->PublicKey.pbData =
5257                              (BYTE *)pInfo->Algorithm.pszObjId
5258                              + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
5259                             pInfo->PublicKey.cbData = encodedLen;
5260                             pInfo->PublicKey.cUnusedBits = 0;
5261                             ret = CryptEncodeObject(dwCertEncodingType,
5262                              RSA_CSP_PUBLICKEYBLOB, pubKey,
5263                              pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
5264                         }
5265                     }
5266                 }
5267                 CryptMemFree(pubKey);
5268             }
5269             else
5270                 ret = FALSE;
5271         }
5272         CryptDestroyKey(key);
5273     }
5274     return ret;
5275 }
5276
5277 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
5278  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
5279  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
5280
5281 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
5282  DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
5283  void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5284 {
5285     static HCRYPTOIDFUNCSET set = NULL;
5286     BOOL ret;
5287     ExportPublicKeyInfoExFunc exportFunc = NULL;
5288     HCRYPTOIDFUNCADDR hFunc = NULL;
5289
5290     TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
5291      dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
5292      pInfo, pcbInfo);
5293
5294     if (!hCryptProv)
5295     {
5296         SetLastError(ERROR_INVALID_PARAMETER);
5297         return FALSE;
5298     }
5299
5300     if (pszPublicKeyObjId)
5301     {
5302         if (!set)
5303             set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
5304              0);
5305         CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
5306          0, (void **)&exportFunc, &hFunc);
5307     }
5308     if (!exportFunc)
5309         exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
5310     ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
5311      pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
5312     if (hFunc)
5313         CryptFreeOIDFunctionAddress(hFunc, 0);
5314     return ret;
5315 }
5316
5317 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
5318  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
5319 {
5320     return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
5321      0, 0, NULL, phKey);
5322 }
5323
5324 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5325  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5326  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
5327 {
5328     BOOL ret;
5329     DWORD pubKeySize = 0;
5330
5331     TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
5332      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
5333
5334     ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
5335      pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
5336     if (ret)
5337     {
5338         LPBYTE pubKey = CryptMemAlloc(pubKeySize);
5339
5340         if (pubKey)
5341         {
5342             ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
5343              pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
5344              &pubKeySize);
5345             if (ret)
5346                 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
5347                  phKey);
5348             CryptMemFree(pubKey);
5349         }
5350         else
5351             ret = FALSE;
5352     }
5353     return ret;
5354 }
5355
5356 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
5357  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5358  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
5359
5360 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5361  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5362  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
5363 {
5364     static HCRYPTOIDFUNCSET set = NULL;
5365     BOOL ret;
5366     ImportPublicKeyInfoExFunc importFunc = NULL;
5367     HCRYPTOIDFUNCADDR hFunc = NULL;
5368
5369     TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
5370      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
5371
5372     if (!set)
5373         set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
5374     CryptGetOIDFunctionAddress(set, dwCertEncodingType,
5375      pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
5376     if (!importFunc)
5377         importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
5378     ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
5379      pvAuxInfo, phKey);
5380     if (hFunc)
5381         CryptFreeOIDFunctionAddress(hFunc, 0);
5382     return ret;
5383 }