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