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