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