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