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