crypt32: Remove unwanted shadow variable.
[wine] / dlls / crypt32 / encode.c
1 /*
2  * Copyright 2005-2007 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,   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_AsnEncodePKCSAttribute(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_ATTRIBUTE *attr = (const CRYPT_ATTRIBUTE *)pvStructInfo;
1416
1417         if (!attr->pszObjId)
1418             SetLastError(E_INVALIDARG);
1419         else
1420         {
1421             struct AsnEncodeSequenceItem items[2] = {
1422              { attr->pszObjId, CRYPT_AsnEncodeOid, 0 },
1423              { &attr->cValue, CRYPT_DEREncodeSet, 0 },
1424             };
1425
1426             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1427              sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1428              pcbEncoded);
1429         }
1430     }
1431     __EXCEPT_PAGE_FAULT
1432     {
1433         SetLastError(STATUS_ACCESS_VIOLATION);
1434     }
1435     __ENDTRY
1436     return ret;
1437 }
1438
1439 static BOOL WINAPI CRYPT_AsnEncodePKCSAttributes(DWORD dwCertEncodingType,
1440  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1441  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1442 {
1443     BOOL ret = FALSE;
1444
1445     __TRY
1446     {
1447         const CRYPT_ATTRIBUTES *attributes =
1448          (const CRYPT_ATTRIBUTES *)pvStructInfo;
1449         struct DERSetDescriptor desc = { attributes->cAttr, attributes->rgAttr,
1450          sizeof(CRYPT_ATTRIBUTE), 0, CRYPT_AsnEncodePKCSAttribute };
1451
1452         ret = CRYPT_DEREncodeItemsAsSet(X509_ASN_ENCODING, lpszStructType,
1453          &desc, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1454     }
1455     __EXCEPT_PAGE_FAULT
1456     {
1457         SetLastError(STATUS_ACCESS_VIOLATION);
1458     }
1459     __ENDTRY
1460     return ret;
1461 }
1462
1463 /* Like CRYPT_AsnEncodePKCSContentInfo, but allows the OID to be NULL */
1464 static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfoInternal(
1465  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
1466  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1467  DWORD *pcbEncoded)
1468 {
1469     const CRYPT_CONTENT_INFO *info = (const CRYPT_CONTENT_INFO *)pvStructInfo;
1470     struct AsnEncodeSequenceItem items[2] = {
1471      { info->pszObjId, CRYPT_AsnEncodeOid, 0 },
1472      { NULL, NULL, 0 },
1473     };
1474     struct AsnConstructedItem constructed = { 0 };
1475     DWORD cItem = 1;
1476
1477     if (info->Content.cbData)
1478     {
1479         constructed.tag = 0;
1480         constructed.pvStructInfo = &info->Content;
1481         constructed.encodeFunc = CRYPT_CopyEncodedBlob;
1482         items[cItem].pvStructInfo = &constructed;
1483         items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
1484         cItem++;
1485     }
1486     return CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1487      cItem, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1488 }
1489
1490 BOOL CRYPT_AsnEncodePKCSDigestedData(CRYPT_DIGESTED_DATA *digestedData,
1491  void *pvData, DWORD *pcbData)
1492 {
1493     struct AsnEncodeSequenceItem items[] = {
1494      { &digestedData->version, CRYPT_AsnEncodeInt, 0 },
1495      { &digestedData->DigestAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams,
1496        0 },
1497      { &digestedData->ContentInfo, CRYPT_AsnEncodePKCSContentInfoInternal, 0 },
1498      { &digestedData->hash, CRYPT_AsnEncodeOctets, 0 },
1499     };
1500
1501     return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items,
1502      sizeof(items) / sizeof(items[0]), 0, NULL, pvData, pcbData);
1503 }
1504
1505 static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfo(DWORD dwCertEncodingType,
1506  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1507  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1508 {
1509     BOOL ret = FALSE;
1510
1511     __TRY
1512     {
1513         const CRYPT_CONTENT_INFO *info =
1514          (const CRYPT_CONTENT_INFO *)pvStructInfo;
1515
1516         if (!info->pszObjId)
1517             SetLastError(E_INVALIDARG);
1518         else
1519             ret = CRYPT_AsnEncodePKCSContentInfoInternal(dwCertEncodingType,
1520              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1521              pcbEncoded);
1522     }
1523     __EXCEPT_PAGE_FAULT
1524     {
1525         SetLastError(STATUS_ACCESS_VIOLATION);
1526     }
1527     __ENDTRY
1528     return ret;
1529 }
1530
1531 static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value,
1532  BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1533  DWORD *pcbEncoded)
1534 {
1535     BOOL ret = TRUE;
1536     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1537     DWORD bytesNeeded, lenBytes, encodedLen;
1538
1539     encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1540      lstrlenW(str);
1541     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1542     bytesNeeded = 1 + lenBytes + encodedLen;
1543     if (!pbEncoded)
1544         *pcbEncoded = bytesNeeded;
1545     else
1546     {
1547         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1548          pbEncoded, pcbEncoded, bytesNeeded)))
1549         {
1550             DWORD i;
1551
1552             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1553                 pbEncoded = *(BYTE **)pbEncoded;
1554             *pbEncoded++ = tag;
1555             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1556             pbEncoded += lenBytes;
1557             for (i = 0; i < encodedLen; i++)
1558                 *pbEncoded++ = (BYTE)str[i];
1559         }
1560     }
1561     return ret;
1562 }
1563
1564 static BOOL CRYPT_AsnEncodeNumericString(const CERT_NAME_VALUE *value,
1565  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1566  DWORD *pcbEncoded)
1567 {
1568     BOOL ret = TRUE;
1569     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1570     DWORD bytesNeeded, lenBytes, encodedLen;
1571
1572     encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1573      lstrlenW(str);
1574     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1575     bytesNeeded = 1 + lenBytes + encodedLen;
1576     if (!pbEncoded)
1577         *pcbEncoded = bytesNeeded;
1578     else
1579     {
1580         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1581          pbEncoded, pcbEncoded, bytesNeeded)))
1582         {
1583             DWORD i;
1584             BYTE *ptr;
1585
1586             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1587                 ptr = *(BYTE **)pbEncoded;
1588             else
1589                 ptr = pbEncoded;
1590             *ptr++ = ASN_NUMERICSTRING;
1591             CRYPT_EncodeLen(encodedLen, ptr, &lenBytes);
1592             ptr += lenBytes;
1593             for (i = 0; ret && i < encodedLen; i++)
1594             {
1595                 if (isdigitW(str[i]))
1596                     *ptr++ = (BYTE)str[i];
1597                 else
1598                 {
1599                     *pcbEncoded = i;
1600                     SetLastError(CRYPT_E_INVALID_NUMERIC_STRING);
1601                     ret = FALSE;
1602                 }
1603             }
1604             if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG))
1605                 CryptMemFree(*(BYTE **)pbEncoded);
1606         }
1607     }
1608     return ret;
1609 }
1610
1611 static inline int isprintableW(WCHAR wc)
1612 {
1613     return isalnumW(wc) || isspaceW(wc) || wc == '\'' || wc == '(' ||
1614      wc == ')' || wc == '+' || wc == ',' || wc == '-' || wc == '.' ||
1615      wc == '/' || wc == ':' || wc == '=' || wc == '?';
1616 }
1617
1618 static BOOL CRYPT_AsnEncodePrintableString(const CERT_NAME_VALUE *value,
1619  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1620  DWORD *pcbEncoded)
1621 {
1622     BOOL ret = TRUE;
1623     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1624     DWORD bytesNeeded, lenBytes, encodedLen;
1625
1626     encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1627      lstrlenW(str);
1628     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1629     bytesNeeded = 1 + lenBytes + encodedLen;
1630     if (!pbEncoded)
1631         *pcbEncoded = bytesNeeded;
1632     else
1633     {
1634         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1635          pbEncoded, pcbEncoded, bytesNeeded)))
1636         {
1637             DWORD i;
1638             BYTE *ptr;
1639
1640             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1641                 ptr = *(BYTE **)pbEncoded;
1642             else
1643                 ptr = pbEncoded;
1644             *ptr++ = ASN_PRINTABLESTRING;
1645             CRYPT_EncodeLen(encodedLen, ptr, &lenBytes);
1646             ptr += lenBytes;
1647             for (i = 0; ret && i < encodedLen; i++)
1648             {
1649                 if (isprintableW(str[i]))
1650                     *ptr++ = (BYTE)str[i];
1651                 else
1652                 {
1653                     *pcbEncoded = i;
1654                     SetLastError(CRYPT_E_INVALID_PRINTABLE_STRING);
1655                     ret = FALSE;
1656                 }
1657             }
1658             if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG))
1659                 CryptMemFree(*(BYTE **)pbEncoded);
1660         }
1661     }
1662     return ret;
1663 }
1664
1665 static BOOL CRYPT_AsnEncodeIA5String(const CERT_NAME_VALUE *value,
1666  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1667  DWORD *pcbEncoded)
1668 {
1669     BOOL ret = TRUE;
1670     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1671     DWORD bytesNeeded, lenBytes, encodedLen;
1672
1673     encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1674      lstrlenW(str);
1675     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1676     bytesNeeded = 1 + lenBytes + encodedLen;
1677     if (!pbEncoded)
1678         *pcbEncoded = bytesNeeded;
1679     else
1680     {
1681         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1682          pbEncoded, pcbEncoded, bytesNeeded)))
1683         {
1684             DWORD i;
1685             BYTE *ptr;
1686
1687             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1688                 ptr = *(BYTE **)pbEncoded;
1689             else
1690                 ptr = pbEncoded;
1691             *ptr++ = ASN_IA5STRING;
1692             CRYPT_EncodeLen(encodedLen, ptr, &lenBytes);
1693             ptr += lenBytes;
1694             for (i = 0; ret && i < encodedLen; i++)
1695             {
1696                 if (str[i] <= 0x7f)
1697                     *ptr++ = (BYTE)str[i];
1698                 else
1699                 {
1700                     *pcbEncoded = i;
1701                     SetLastError(CRYPT_E_INVALID_IA5_STRING);
1702                     ret = FALSE;
1703                 }
1704             }
1705             if (!ret && (dwFlags & CRYPT_ENCODE_ALLOC_FLAG))
1706                 CryptMemFree(*(BYTE **)pbEncoded);
1707         }
1708     }
1709     return ret;
1710 }
1711
1712 static BOOL CRYPT_AsnEncodeUniversalString(const CERT_NAME_VALUE *value,
1713  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1714  DWORD *pcbEncoded)
1715 {
1716     BOOL ret = TRUE;
1717     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1718     DWORD bytesNeeded, lenBytes, strLen;
1719
1720     /* FIXME: doesn't handle composite characters */
1721     strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1722      lstrlenW(str);
1723     CRYPT_EncodeLen(strLen * 4, NULL, &lenBytes);
1724     bytesNeeded = 1 + lenBytes + strLen * 4;
1725     if (!pbEncoded)
1726         *pcbEncoded = bytesNeeded;
1727     else
1728     {
1729         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1730          pbEncoded, pcbEncoded, bytesNeeded)))
1731         {
1732             DWORD i;
1733
1734             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1735                 pbEncoded = *(BYTE **)pbEncoded;
1736             *pbEncoded++ = ASN_UNIVERSALSTRING;
1737             CRYPT_EncodeLen(strLen * 4, pbEncoded, &lenBytes);
1738             pbEncoded += lenBytes;
1739             for (i = 0; i < strLen; i++)
1740             {
1741                 *pbEncoded++ = 0;
1742                 *pbEncoded++ = 0;
1743                 *pbEncoded++ = (BYTE)((str[i] & 0xff00) >> 8);
1744                 *pbEncoded++ = (BYTE)(str[i] & 0x00ff);
1745             }
1746         }
1747     }
1748     return ret;
1749 }
1750
1751 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1752  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1753  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1754 {
1755     BOOL ret = FALSE;
1756
1757     __TRY
1758     {
1759         const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1760
1761         switch (value->dwValueType)
1762         {
1763         case CERT_RDN_ANY_TYPE:
1764         case CERT_RDN_ENCODED_BLOB:
1765         case CERT_RDN_OCTET_STRING:
1766             SetLastError(CRYPT_E_NOT_CHAR_STRING);
1767             break;
1768         case CERT_RDN_NUMERIC_STRING:
1769             ret = CRYPT_AsnEncodeNumericString(value, dwFlags, pEncodePara,
1770              pbEncoded, pcbEncoded);
1771             break;
1772         case CERT_RDN_PRINTABLE_STRING:
1773             ret = CRYPT_AsnEncodePrintableString(value, dwFlags, pEncodePara,
1774              pbEncoded, pcbEncoded);
1775             break;
1776         case CERT_RDN_TELETEX_STRING:
1777             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_T61STRING,
1778              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1779             break;
1780         case CERT_RDN_VIDEOTEX_STRING:
1781             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value,
1782              ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1783             break;
1784         case CERT_RDN_IA5_STRING:
1785             ret = CRYPT_AsnEncodeIA5String(value, dwFlags, pEncodePara,
1786              pbEncoded, pcbEncoded);
1787             break;
1788         case CERT_RDN_GRAPHIC_STRING:
1789             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GRAPHICSTRING,
1790              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1791             break;
1792         case CERT_RDN_VISIBLE_STRING:
1793             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_VISIBLESTRING,
1794              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1795             break;
1796         case CERT_RDN_GENERAL_STRING:
1797             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GENERALSTRING,
1798              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1799             break;
1800         case CERT_RDN_UNIVERSAL_STRING:
1801             ret = CRYPT_AsnEncodeUniversalString(value, dwFlags, pEncodePara,
1802              pbEncoded, pcbEncoded);
1803             break;
1804         case CERT_RDN_BMP_STRING:
1805             ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
1806              pbEncoded, pcbEncoded);
1807             break;
1808         case CERT_RDN_UTF8_STRING:
1809             ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
1810              pbEncoded, pcbEncoded);
1811             break;
1812         default:
1813             SetLastError(CRYPT_E_ASN1_CHOICE);
1814         }
1815     }
1816     __EXCEPT_PAGE_FAULT
1817     {
1818         SetLastError(STATUS_ACCESS_VIOLATION);
1819     }
1820     __ENDTRY
1821     return ret;
1822 }
1823
1824 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1825  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1826  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1827 {
1828     BOOL ret;
1829
1830     __TRY
1831     {
1832         const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1833         DWORD bytesNeeded = 0, lenBytes, size, i;
1834
1835         TRACE("encoding name with %d RDNs\n", info->cRDN);
1836         ret = TRUE;
1837         for (i = 0; ret && i < info->cRDN; i++)
1838         {
1839             ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1840              CRYPT_AsnEncodeNameValue, NULL, &size);
1841             if (ret)
1842                 bytesNeeded += size;
1843         }
1844         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1845         bytesNeeded += 1 + lenBytes;
1846         if (ret)
1847         {
1848             if (!pbEncoded)
1849                 *pcbEncoded = bytesNeeded;
1850             else
1851             {
1852                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1853                  pbEncoded, pcbEncoded, bytesNeeded)))
1854                 {
1855                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1856                         pbEncoded = *(BYTE **)pbEncoded;
1857                     *pbEncoded++ = ASN_SEQUENCEOF;
1858                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1859                      &lenBytes);
1860                     pbEncoded += lenBytes;
1861                     for (i = 0; ret && i < info->cRDN; i++)
1862                     {
1863                         size = bytesNeeded;
1864                         ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1865                          &info->rgRDN[i], CRYPT_AsnEncodeNameValue, pbEncoded,
1866                          &size);
1867                         if (ret)
1868                         {
1869                             pbEncoded += size;
1870                             bytesNeeded -= size;
1871                         }
1872                     }
1873                 }
1874             }
1875         }
1876     }
1877     __EXCEPT_PAGE_FAULT
1878     {
1879         SetLastError(STATUS_ACCESS_VIOLATION);
1880         ret = FALSE;
1881     }
1882     __ENDTRY
1883     return ret;
1884 }
1885
1886 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1887  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1888  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1889 {
1890     BOOL val = *(const BOOL *)pvStructInfo, ret;
1891
1892     TRACE("%d\n", val);
1893
1894     if (!pbEncoded)
1895     {
1896         *pcbEncoded = 3;
1897         ret = TRUE;
1898     }
1899     else if (*pcbEncoded < 3)
1900     {
1901         *pcbEncoded = 3;
1902         SetLastError(ERROR_MORE_DATA);
1903         ret = FALSE;
1904     }
1905     else
1906     {
1907         *pcbEncoded = 3;
1908         *pbEncoded++ = ASN_BOOL;
1909         *pbEncoded++ = 1;
1910         *pbEncoded++ = val ? 0xff : 0;
1911         ret = TRUE;
1912     }
1913     TRACE("returning %d (%08x)\n", ret, GetLastError());
1914     return ret;
1915 }
1916
1917 static BOOL WINAPI CRYPT_AsnEncodeAltNameEntry(DWORD dwCertEncodingType,
1918  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1919  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1920 {
1921     const CERT_ALT_NAME_ENTRY *entry =
1922      (const CERT_ALT_NAME_ENTRY *)pvStructInfo;
1923     BOOL ret;
1924     DWORD dataLen;
1925     BYTE tag;
1926
1927     ret = TRUE;
1928     switch (entry->dwAltNameChoice)
1929     {
1930     case CERT_ALT_NAME_RFC822_NAME:
1931     case CERT_ALT_NAME_DNS_NAME:
1932     case CERT_ALT_NAME_URL:
1933         tag = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1934         if (entry->u.pwszURL)
1935         {
1936             DWORD i;
1937
1938             /* Not + 1: don't encode the NULL-terminator */
1939             dataLen = lstrlenW(entry->u.pwszURL);
1940             for (i = 0; ret && i < dataLen; i++)
1941             {
1942                 if (entry->u.pwszURL[i] > 0x7f)
1943                 {
1944                     SetLastError(CRYPT_E_INVALID_IA5_STRING);
1945                     ret = FALSE;
1946                     *pcbEncoded = i;
1947                 }
1948             }
1949         }
1950         else
1951             dataLen = 0;
1952         break;
1953     case CERT_ALT_NAME_DIRECTORY_NAME:
1954         tag = ASN_CONTEXT | ASN_CONSTRUCTOR | (entry->dwAltNameChoice - 1);
1955         dataLen = entry->u.DirectoryName.cbData;
1956         break;
1957     case CERT_ALT_NAME_IP_ADDRESS:
1958         tag = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1959         dataLen = entry->u.IPAddress.cbData;
1960         break;
1961     case CERT_ALT_NAME_REGISTERED_ID:
1962     {
1963         struct AsnEncodeTagSwappedItem swapped =
1964          { ASN_CONTEXT | (entry->dwAltNameChoice - 1), entry->u.pszRegisteredID,
1965            CRYPT_AsnEncodeOid };
1966
1967         return CRYPT_AsnEncodeSwapTag(0, NULL, &swapped, 0, NULL, pbEncoded,
1968          pcbEncoded);
1969     }
1970     case CERT_ALT_NAME_OTHER_NAME:
1971         FIXME("name type %d unimplemented\n", entry->dwAltNameChoice);
1972         return FALSE;
1973     default:
1974         SetLastError(E_INVALIDARG);
1975         return FALSE;
1976     }
1977     if (ret)
1978     {
1979         DWORD bytesNeeded, lenBytes;
1980
1981         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1982         bytesNeeded = 1 + dataLen + lenBytes;
1983         if (!pbEncoded)
1984             *pcbEncoded = bytesNeeded;
1985         else if (*pcbEncoded < bytesNeeded)
1986         {
1987             SetLastError(ERROR_MORE_DATA);
1988             *pcbEncoded = bytesNeeded;
1989             ret = FALSE;
1990         }
1991         else
1992         {
1993             *pbEncoded++ = tag;
1994             CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1995             pbEncoded += lenBytes;
1996             switch (entry->dwAltNameChoice)
1997             {
1998             case CERT_ALT_NAME_RFC822_NAME:
1999             case CERT_ALT_NAME_DNS_NAME:
2000             case CERT_ALT_NAME_URL:
2001             {
2002                 DWORD i;
2003
2004                 for (i = 0; i < dataLen; i++)
2005                     *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
2006                 break;
2007             }
2008             case CERT_ALT_NAME_DIRECTORY_NAME:
2009                 memcpy(pbEncoded, entry->u.DirectoryName.pbData, dataLen);
2010                 break;
2011             case CERT_ALT_NAME_IP_ADDRESS:
2012                 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
2013                 break;
2014             }
2015             if (ret)
2016                 *pcbEncoded = bytesNeeded;
2017         }
2018     }
2019     TRACE("returning %d (%08x)\n", ret, GetLastError());
2020     return ret;
2021 }
2022
2023 static BOOL WINAPI CRYPT_AsnEncodeIntegerSwapBytes(DWORD dwCertEncodingType,
2024  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2025  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2026 {
2027     BOOL ret;
2028
2029     __TRY
2030     {
2031         const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
2032         CRYPT_DATA_BLOB newBlob = { blob->cbData, NULL };
2033
2034         ret = TRUE;
2035         if (newBlob.cbData)
2036         {
2037             newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2038             if (newBlob.pbData)
2039             {
2040                 DWORD i;
2041
2042                 for (i = 0; i < newBlob.cbData; i++)
2043                     newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2044             }
2045             else
2046                 ret = FALSE;
2047         }
2048         if (ret)
2049             ret = CRYPT_AsnEncodeInteger(dwCertEncodingType, lpszStructType,
2050              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2051         CryptMemFree(newBlob.pbData);
2052     }
2053     __EXCEPT_PAGE_FAULT
2054     {
2055         SetLastError(STATUS_ACCESS_VIOLATION);
2056         ret = FALSE;
2057     }
2058     __ENDTRY
2059     return ret;
2060 }
2061
2062 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType,
2063  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2064  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2065 {
2066     BOOL ret;
2067
2068     __TRY
2069     {
2070         const CERT_AUTHORITY_KEY_ID_INFO *info =
2071          (const CERT_AUTHORITY_KEY_ID_INFO *)pvStructInfo;
2072         struct AsnEncodeSequenceItem items[3] = { { 0 } };
2073         struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2074         struct AsnConstructedItem constructed = { 0 };
2075         DWORD cItem = 0, cSwapped = 0;
2076
2077         if (info->KeyId.cbData)
2078         {
2079             swapped[cSwapped].tag = ASN_CONTEXT | 0;
2080             swapped[cSwapped].pvStructInfo = &info->KeyId;
2081             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeIntegerSwapBytes;
2082             items[cItem].pvStructInfo = &swapped[cSwapped];
2083             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2084             cSwapped++;
2085             cItem++;
2086         }
2087         if (info->CertIssuer.cbData)
2088         {
2089             constructed.tag = 1;
2090             constructed.pvStructInfo = &info->CertIssuer;
2091             constructed.encodeFunc = CRYPT_CopyEncodedBlob;
2092             items[cItem].pvStructInfo = &constructed;
2093             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2094             cItem++;
2095         }
2096         if (info->CertSerialNumber.cbData)
2097         {
2098             swapped[cSwapped].tag = ASN_CONTEXT | 2;
2099             swapped[cSwapped].pvStructInfo = &info->CertSerialNumber;
2100             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
2101             items[cItem].pvStructInfo = &swapped[cSwapped];
2102             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2103             cSwapped++;
2104             cItem++;
2105         }
2106         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
2107          pEncodePara, pbEncoded, pcbEncoded);
2108     }
2109     __EXCEPT_PAGE_FAULT
2110     {
2111         SetLastError(STATUS_ACCESS_VIOLATION);
2112         ret = FALSE;
2113     }
2114     __ENDTRY
2115     return ret;
2116 }
2117
2118 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
2119  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2120  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2121 {
2122     BOOL ret;
2123
2124     __TRY
2125     {
2126         const CERT_ALT_NAME_INFO *info =
2127          (const CERT_ALT_NAME_INFO *)pvStructInfo;
2128         DWORD bytesNeeded, dataLen, lenBytes, i;
2129
2130         ret = TRUE;
2131         /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
2132          * can't encode an erroneous entry index if it's bigger than this.
2133          */
2134         for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
2135         {
2136             DWORD len;
2137
2138             ret = CRYPT_AsnEncodeAltNameEntry(dwCertEncodingType, NULL,
2139              &info->rgAltEntry[i], 0, NULL, NULL, &len);
2140             if (ret)
2141                 dataLen += len;
2142             else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2143             {
2144                 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
2145                  * the bad character, now set the index of the bad
2146                  * entry
2147                  */
2148                 *pcbEncoded = (BYTE)i <<
2149                  CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
2150             }
2151         }
2152         if (ret)
2153         {
2154             CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2155             bytesNeeded = 1 + lenBytes + dataLen;
2156             if (!pbEncoded)
2157             {
2158                 *pcbEncoded = bytesNeeded;
2159                 ret = TRUE;
2160             }
2161             else
2162             {
2163                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2164                  pbEncoded, pcbEncoded, bytesNeeded)))
2165                 {
2166                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2167                         pbEncoded = *(BYTE **)pbEncoded;
2168                     *pbEncoded++ = ASN_SEQUENCEOF;
2169                     CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2170                     pbEncoded += lenBytes;
2171                     for (i = 0; ret && i < info->cAltEntry; i++)
2172                     {
2173                         DWORD len = dataLen;
2174
2175                         ret = CRYPT_AsnEncodeAltNameEntry(dwCertEncodingType,
2176                          NULL, &info->rgAltEntry[i], 0, NULL, pbEncoded, &len);
2177                         if (ret)
2178                         {
2179                             pbEncoded += len;
2180                             dataLen -= len;
2181                         }
2182                     }
2183                 }
2184             }
2185         }
2186     }
2187     __EXCEPT_PAGE_FAULT
2188     {
2189         SetLastError(STATUS_ACCESS_VIOLATION);
2190         ret = FALSE;
2191     }
2192     __ENDTRY
2193     return ret;
2194 }
2195
2196 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId2(DWORD dwCertEncodingType,
2197  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2198  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2199 {
2200     BOOL ret;
2201
2202     __TRY
2203     {
2204         const CERT_AUTHORITY_KEY_ID2_INFO *info =
2205          (const CERT_AUTHORITY_KEY_ID2_INFO *)pvStructInfo;
2206         struct AsnEncodeSequenceItem items[3] = { { 0 } };
2207         struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2208         DWORD cItem = 0, cSwapped = 0;
2209
2210         if (info->KeyId.cbData)
2211         {
2212             swapped[cSwapped].tag = ASN_CONTEXT | 0;
2213             swapped[cSwapped].pvStructInfo = &info->KeyId;
2214             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeIntegerSwapBytes;
2215             items[cItem].pvStructInfo = &swapped[cSwapped];
2216             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2217             cSwapped++;
2218             cItem++;
2219         }
2220         if (info->AuthorityCertIssuer.cAltEntry)
2221         {
2222             swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
2223             swapped[cSwapped].pvStructInfo = &info->AuthorityCertIssuer;
2224             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2225             items[cItem].pvStructInfo = &swapped[cSwapped];
2226             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2227             cSwapped++;
2228             cItem++;
2229         }
2230         if (info->AuthorityCertSerialNumber.cbData)
2231         {
2232             swapped[cSwapped].tag = ASN_CONTEXT | 2;
2233             swapped[cSwapped].pvStructInfo = &info->AuthorityCertSerialNumber;
2234             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
2235             items[cItem].pvStructInfo = &swapped[cSwapped];
2236             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2237             cSwapped++;
2238             cItem++;
2239         }
2240         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
2241          pEncodePara, pbEncoded, pcbEncoded);
2242     }
2243     __EXCEPT_PAGE_FAULT
2244     {
2245         SetLastError(STATUS_ACCESS_VIOLATION);
2246         ret = FALSE;
2247     }
2248     __ENDTRY
2249     return ret;
2250 }
2251
2252 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
2253  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2254  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2255 {
2256     BOOL ret;
2257
2258     __TRY
2259     {
2260         const CERT_BASIC_CONSTRAINTS_INFO *info =
2261          (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
2262         struct AsnEncodeSequenceItem items[3] = {
2263          { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
2264          { 0 }
2265         };
2266         DWORD cItem = 1;
2267
2268         if (info->fPathLenConstraint)
2269         {
2270             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2271             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2272             cItem++;
2273         }
2274         if (info->cSubtreesConstraint)
2275         {
2276             items[cItem].pvStructInfo = &info->cSubtreesConstraint;
2277             items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2278             cItem++;
2279         }
2280         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2281          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2282     }
2283     __EXCEPT_PAGE_FAULT
2284     {
2285         SetLastError(STATUS_ACCESS_VIOLATION);
2286         ret = FALSE;
2287     }
2288     __ENDTRY
2289     return ret;
2290 }
2291
2292 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
2293  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2294  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2295 {
2296     BOOL ret;
2297
2298     __TRY
2299     {
2300         const CERT_BASIC_CONSTRAINTS2_INFO *info =
2301          (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
2302         struct AsnEncodeSequenceItem items[2] = { { 0 } };
2303         DWORD cItem = 0;
2304
2305         if (info->fCA)
2306         {
2307             items[cItem].pvStructInfo = &info->fCA;
2308             items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
2309             cItem++;
2310         }
2311         if (info->fPathLenConstraint)
2312         {
2313             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2314             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2315             cItem++;
2316         }
2317         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2318          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2319     }
2320     __EXCEPT_PAGE_FAULT
2321     {
2322         SetLastError(STATUS_ACCESS_VIOLATION);
2323         ret = FALSE;
2324     }
2325     __ENDTRY
2326     return ret;
2327 }
2328
2329 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
2330  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2331  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2332 {
2333     BOOL ret;
2334
2335     __TRY
2336     {
2337         const BLOBHEADER *hdr =
2338          (const BLOBHEADER *)pvStructInfo;
2339
2340         if (hdr->bType != PUBLICKEYBLOB)
2341         {
2342             SetLastError(E_INVALIDARG);
2343             ret = FALSE;
2344         }
2345         else
2346         {
2347             const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
2348              ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
2349             CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
2350              (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
2351             struct AsnEncodeSequenceItem items[] = { 
2352              { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
2353              { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
2354             };
2355
2356             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
2357              sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
2358              pcbEncoded);
2359         }
2360     }
2361     __EXCEPT_PAGE_FAULT
2362     {
2363         SetLastError(STATUS_ACCESS_VIOLATION);
2364         ret = FALSE;
2365     }
2366     __ENDTRY
2367     return ret;
2368 }
2369
2370 BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
2371  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2372  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2373 {
2374     BOOL ret;
2375
2376     __TRY
2377     {
2378         const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
2379         DWORD bytesNeeded, lenBytes;
2380
2381         TRACE("(%d, %p), %08x, %p, %p, %d\n", blob->cbData, blob->pbData,
2382          dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
2383
2384         CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
2385         bytesNeeded = 1 + lenBytes + blob->cbData;
2386         if (!pbEncoded)
2387         {
2388             *pcbEncoded = bytesNeeded;
2389             ret = TRUE;
2390         }
2391         else
2392         {
2393             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2394              pcbEncoded, bytesNeeded)))
2395             {
2396                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2397                     pbEncoded = *(BYTE **)pbEncoded;
2398                 *pbEncoded++ = ASN_OCTETSTRING;
2399                 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
2400                 pbEncoded += lenBytes;
2401                 if (blob->cbData)
2402                     memcpy(pbEncoded, blob->pbData, blob->cbData);
2403             }
2404         }
2405     }
2406     __EXCEPT_PAGE_FAULT
2407     {
2408         SetLastError(STATUS_ACCESS_VIOLATION);
2409         ret = FALSE;
2410     }
2411     __ENDTRY
2412     TRACE("returning %d (%08x)\n", ret, GetLastError());
2413     return ret;
2414 }
2415
2416 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
2417  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2418  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2419 {
2420     BOOL ret;
2421
2422     __TRY
2423     {
2424         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2425         DWORD bytesNeeded, lenBytes, dataBytes;
2426         BYTE unusedBits;
2427
2428         /* yep, MS allows cUnusedBits to be >= 8 */
2429         if (!blob->cUnusedBits)
2430         {
2431             dataBytes = blob->cbData;
2432             unusedBits = 0;
2433         }
2434         else if (blob->cbData * 8 > blob->cUnusedBits)
2435         {
2436             dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
2437             unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
2438              blob->cUnusedBits;
2439         }
2440         else
2441         {
2442             dataBytes = 0;
2443             unusedBits = 0;
2444         }
2445         CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
2446         bytesNeeded = 1 + lenBytes + dataBytes + 1;
2447         if (!pbEncoded)
2448         {
2449             *pcbEncoded = bytesNeeded;
2450             ret = TRUE;
2451         }
2452         else
2453         {
2454             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2455              pcbEncoded, bytesNeeded)))
2456             {
2457                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2458                     pbEncoded = *(BYTE **)pbEncoded;
2459                 *pbEncoded++ = ASN_BITSTRING;
2460                 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
2461                 pbEncoded += lenBytes;
2462                 *pbEncoded++ = unusedBits;
2463                 if (dataBytes)
2464                 {
2465                     BYTE mask = 0xff << unusedBits;
2466
2467                     if (dataBytes > 1)
2468                     {
2469                         memcpy(pbEncoded, blob->pbData, dataBytes - 1);
2470                         pbEncoded += dataBytes - 1;
2471                     }
2472                     *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
2473                 }
2474             }
2475         }
2476     }
2477     __EXCEPT_PAGE_FAULT
2478     {
2479         SetLastError(STATUS_ACCESS_VIOLATION);
2480         ret = FALSE;
2481     }
2482     __ENDTRY
2483     return ret;
2484 }
2485
2486 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
2487  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2488  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2489 {
2490     BOOL ret;
2491
2492     __TRY
2493     {
2494         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2495         CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
2496
2497         ret = TRUE;
2498         if (newBlob.cbData)
2499         {
2500             newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2501             if (newBlob.pbData)
2502             {
2503                 DWORD i;
2504
2505                 for (i = 0; i < newBlob.cbData; i++)
2506                     newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2507             }
2508             else
2509                 ret = FALSE;
2510         }
2511         if (ret)
2512             ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
2513              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2514         CryptMemFree(newBlob.pbData);
2515     }
2516     __EXCEPT_PAGE_FAULT
2517     {
2518         SetLastError(STATUS_ACCESS_VIOLATION);
2519         ret = FALSE;
2520     }
2521     __ENDTRY
2522     return ret;
2523 }
2524
2525 BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
2526  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2527  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2528 {
2529     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
2530
2531     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
2532      &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2533 }
2534
2535 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
2536  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2537  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2538 {
2539     BOOL ret;
2540
2541     __TRY
2542     {
2543         DWORD significantBytes, lenBytes;
2544         BYTE padByte = 0, bytesNeeded;
2545         BOOL pad = FALSE;
2546         const CRYPT_INTEGER_BLOB *blob =
2547          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2548
2549         significantBytes = blob->cbData;
2550         if (significantBytes)
2551         {
2552             if (blob->pbData[significantBytes - 1] & 0x80)
2553             {
2554                 /* negative, lop off leading (little-endian) 0xffs */
2555                 for (; significantBytes > 0 &&
2556                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
2557                     ;
2558                 if (blob->pbData[significantBytes - 1] < 0x80)
2559                 {
2560                     padByte = 0xff;
2561                     pad = TRUE;
2562                 }
2563             }
2564             else
2565             {
2566                 /* positive, lop off leading (little-endian) zeroes */
2567                 for (; significantBytes > 0 &&
2568                  !blob->pbData[significantBytes - 1]; significantBytes--)
2569                     ;
2570                 if (significantBytes == 0)
2571                     significantBytes = 1;
2572                 if (blob->pbData[significantBytes - 1] > 0x7f)
2573                 {
2574                     padByte = 0;
2575                     pad = TRUE;
2576                 }
2577             }
2578         }
2579         if (pad)
2580             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2581         else
2582             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2583         bytesNeeded = 1 + lenBytes + significantBytes;
2584         if (pad)
2585             bytesNeeded++;
2586         if (!pbEncoded)
2587         {
2588             *pcbEncoded = bytesNeeded;
2589             ret = TRUE;
2590         }
2591         else
2592         {
2593             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2594              pcbEncoded, bytesNeeded)))
2595             {
2596                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2597                     pbEncoded = *(BYTE **)pbEncoded;
2598                 *pbEncoded++ = ASN_INTEGER;
2599                 if (pad)
2600                 {
2601                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2602                     pbEncoded += lenBytes;
2603                     *pbEncoded++ = padByte;
2604                 }
2605                 else
2606                 {
2607                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2608                     pbEncoded += lenBytes;
2609                 }
2610                 for (; significantBytes > 0; significantBytes--)
2611                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
2612             }
2613         }
2614     }
2615     __EXCEPT_PAGE_FAULT
2616     {
2617         SetLastError(STATUS_ACCESS_VIOLATION);
2618         ret = FALSE;
2619     }
2620     __ENDTRY
2621     return ret;
2622 }
2623
2624 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
2625  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2626  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2627 {
2628     BOOL ret;
2629
2630     __TRY
2631     {
2632         DWORD significantBytes, lenBytes;
2633         BYTE bytesNeeded;
2634         BOOL pad = FALSE;
2635         const CRYPT_INTEGER_BLOB *blob =
2636          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2637
2638         significantBytes = blob->cbData;
2639         if (significantBytes)
2640         {
2641             /* positive, lop off leading (little-endian) zeroes */
2642             for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2643              significantBytes--)
2644                 ;
2645             if (significantBytes == 0)
2646                 significantBytes = 1;
2647             if (blob->pbData[significantBytes - 1] > 0x7f)
2648                 pad = TRUE;
2649         }
2650         if (pad)
2651             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2652         else
2653             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2654         bytesNeeded = 1 + lenBytes + significantBytes;
2655         if (pad)
2656             bytesNeeded++;
2657         if (!pbEncoded)
2658         {
2659             *pcbEncoded = bytesNeeded;
2660             ret = TRUE;
2661         }
2662         else
2663         {
2664             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2665              pcbEncoded, bytesNeeded)))
2666             {
2667                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2668                     pbEncoded = *(BYTE **)pbEncoded;
2669                 *pbEncoded++ = ASN_INTEGER;
2670                 if (pad)
2671                 {
2672                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2673                     pbEncoded += lenBytes;
2674                     *pbEncoded++ = 0;
2675                 }
2676                 else
2677                 {
2678                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2679                     pbEncoded += lenBytes;
2680                 }
2681                 for (; significantBytes > 0; significantBytes--)
2682                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
2683             }
2684         }
2685     }
2686     __EXCEPT_PAGE_FAULT
2687     {
2688         SetLastError(STATUS_ACCESS_VIOLATION);
2689         ret = FALSE;
2690     }
2691     __ENDTRY
2692     return ret;
2693 }
2694
2695 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2696  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2697  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2698 {
2699     CRYPT_INTEGER_BLOB blob;
2700     BOOL ret;
2701
2702     /* Encode as an unsigned integer, then change the tag to enumerated */
2703     blob.cbData = sizeof(DWORD);
2704     blob.pbData = (BYTE *)pvStructInfo;
2705     ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2706      X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2707     if (ret && pbEncoded)
2708     {
2709         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2710             pbEncoded = *(BYTE **)pbEncoded;
2711         pbEncoded[0] = ASN_ENUMERATED;
2712     }
2713     return ret;
2714 }
2715
2716 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2717  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2718  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2719 {
2720     BOOL ret;
2721
2722     __TRY
2723     {
2724         SYSTEMTIME sysTime;
2725         /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
2726          * temporary buffer because the output buffer is not NULL-terminated.
2727          */
2728         char buf[16];
2729         static const DWORD bytesNeeded = sizeof(buf) - 1;
2730
2731         if (!pbEncoded)
2732         {
2733             *pcbEncoded = bytesNeeded;
2734             ret = TRUE;
2735         }
2736         else
2737         {
2738             /* Sanity check the year, this is a two-digit year format */
2739             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2740              &sysTime);
2741             if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2742             {
2743                 SetLastError(CRYPT_E_BAD_ENCODE);
2744                 ret = FALSE;
2745             }
2746             if (ret)
2747             {
2748                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2749                  pbEncoded, pcbEncoded, bytesNeeded)))
2750                 {
2751                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2752                         pbEncoded = *(BYTE **)pbEncoded;
2753                     buf[0] = ASN_UTCTIME;
2754                     buf[1] = bytesNeeded - 2;
2755                     snprintf(buf + 2, sizeof(buf) - 2,
2756                      "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2757                      sysTime.wYear - 2000 : sysTime.wYear - 1900,
2758                      sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2759                      sysTime.wMinute, sysTime.wSecond);
2760                     memcpy(pbEncoded, buf, bytesNeeded);
2761                 }
2762             }
2763         }
2764     }
2765     __EXCEPT_PAGE_FAULT
2766     {
2767         SetLastError(STATUS_ACCESS_VIOLATION);
2768         ret = FALSE;
2769     }
2770     __ENDTRY
2771     return ret;
2772 }
2773
2774 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2775  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2776  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2777 {
2778     BOOL ret;
2779
2780     __TRY
2781     {
2782         SYSTEMTIME sysTime;
2783         /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
2784          * temporary buffer because the output buffer is not NULL-terminated.
2785          */
2786         char buf[18];
2787         static const DWORD bytesNeeded = sizeof(buf) - 1;
2788
2789         if (!pbEncoded)
2790         {
2791             *pcbEncoded = bytesNeeded;
2792             ret = TRUE;
2793         }
2794         else
2795         {
2796             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2797              &sysTime);
2798             if (ret)
2799                 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2800                  pcbEncoded, bytesNeeded);
2801             if (ret)
2802             {
2803                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2804                     pbEncoded = *(BYTE **)pbEncoded;
2805                 buf[0] = ASN_GENERALTIME;
2806                 buf[1] = bytesNeeded - 2;
2807                 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2808                  sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2809                  sysTime.wMinute, sysTime.wSecond);
2810                 memcpy(pbEncoded, buf, bytesNeeded);
2811             }
2812         }
2813     }
2814     __EXCEPT_PAGE_FAULT
2815     {
2816         SetLastError(STATUS_ACCESS_VIOLATION);
2817         ret = FALSE;
2818     }
2819     __ENDTRY
2820     return ret;
2821 }
2822
2823 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2824  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2825  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2826 {
2827     BOOL ret;
2828
2829     __TRY
2830     {
2831         SYSTEMTIME sysTime;
2832
2833         /* Check the year, if it's in the UTCTime range call that encode func */
2834         if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2835             return FALSE;
2836         if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2837             ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2838              pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2839         else
2840             ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2841              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2842              pcbEncoded);
2843     }
2844     __EXCEPT_PAGE_FAULT
2845     {
2846         SetLastError(STATUS_ACCESS_VIOLATION);
2847         ret = FALSE;
2848     }
2849     __ENDTRY
2850     return ret;
2851 }
2852
2853 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2854  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2855  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2856 {
2857     BOOL ret;
2858
2859     __TRY
2860     {
2861         DWORD bytesNeeded, dataLen, lenBytes, i;
2862         const CRYPT_SEQUENCE_OF_ANY *seq =
2863          (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2864
2865         for (i = 0, dataLen = 0; i < seq->cValue; i++)
2866             dataLen += seq->rgValue[i].cbData;
2867         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2868         bytesNeeded = 1 + lenBytes + dataLen;
2869         if (!pbEncoded)
2870         {
2871             *pcbEncoded = bytesNeeded;
2872             ret = TRUE;
2873         }
2874         else
2875         {
2876             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2877              pcbEncoded, bytesNeeded)))
2878             {
2879                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2880                     pbEncoded = *(BYTE **)pbEncoded;
2881                 *pbEncoded++ = ASN_SEQUENCEOF;
2882                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2883                 pbEncoded += lenBytes;
2884                 for (i = 0; i < seq->cValue; i++)
2885                 {
2886                     memcpy(pbEncoded, seq->rgValue[i].pbData,
2887                      seq->rgValue[i].cbData);
2888                     pbEncoded += seq->rgValue[i].cbData;
2889                 }
2890             }
2891         }
2892     }
2893     __EXCEPT_PAGE_FAULT
2894     {
2895         SetLastError(STATUS_ACCESS_VIOLATION);
2896         ret = FALSE;
2897     }
2898     __ENDTRY
2899     return ret;
2900 }
2901
2902 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2903  BYTE *pbEncoded, DWORD *pcbEncoded)
2904 {
2905     BOOL ret = TRUE;
2906     struct AsnEncodeSequenceItem items[3] = { { 0 } };
2907     struct AsnConstructedItem constructed = { 0 };
2908     struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2909     DWORD cItem = 0, cSwapped = 0;
2910
2911     switch (distPoint->DistPointName.dwDistPointNameChoice)
2912     {
2913     case CRL_DIST_POINT_NO_NAME:
2914         /* do nothing */
2915         break;
2916     case CRL_DIST_POINT_FULL_NAME:
2917         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2918         swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2919         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2920         constructed.tag = 0;
2921         constructed.pvStructInfo = &swapped[cSwapped];
2922         constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2923         items[cItem].pvStructInfo = &constructed;
2924         items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2925         cSwapped++;
2926         cItem++;
2927         break;
2928     case CRL_DIST_POINT_ISSUER_RDN_NAME:
2929         FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2930         ret = FALSE;
2931         break;
2932     default:
2933         ret = FALSE;
2934     }
2935     if (ret && distPoint->ReasonFlags.cbData)
2936     {
2937         swapped[cSwapped].tag = ASN_CONTEXT | 1;
2938         swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2939         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2940         items[cItem].pvStructInfo = &swapped[cSwapped];
2941         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2942         cSwapped++;
2943         cItem++;
2944     }
2945     if (ret && distPoint->CRLIssuer.cAltEntry)
2946     {
2947         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2948         swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2949         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2950         items[cItem].pvStructInfo = &swapped[cSwapped];
2951         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2952         cSwapped++;
2953         cItem++;
2954     }
2955     if (ret)
2956         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2957          pbEncoded, pcbEncoded);
2958     return ret;
2959 }
2960
2961 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2962  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2963  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2964 {
2965     BOOL ret;
2966
2967     __TRY
2968     {
2969         const CRL_DIST_POINTS_INFO *info =
2970          (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2971
2972         if (!info->cDistPoint)
2973         {
2974             SetLastError(E_INVALIDARG);
2975             ret = FALSE;
2976         }
2977         else
2978         {
2979             DWORD bytesNeeded, dataLen, lenBytes, i;
2980
2981             ret = TRUE;
2982             for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2983             {
2984                 DWORD len;
2985
2986                 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2987                  &len);
2988                 if (ret)
2989                     dataLen += len;
2990                 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2991                 {
2992                     /* Have to propagate index of failing character */
2993                     *pcbEncoded = len;
2994                 }
2995             }
2996             if (ret)
2997             {
2998                 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2999                 bytesNeeded = 1 + lenBytes + dataLen;
3000                 if (!pbEncoded)
3001                 {
3002                     *pcbEncoded = bytesNeeded;
3003                     ret = TRUE;
3004                 }
3005                 else
3006                 {
3007                     if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
3008                      pbEncoded, pcbEncoded, bytesNeeded)))
3009                     {
3010                         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3011                             pbEncoded = *(BYTE **)pbEncoded;
3012                         *pbEncoded++ = ASN_SEQUENCEOF;
3013                         CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
3014                         pbEncoded += lenBytes;
3015                         for (i = 0; ret && i < info->cDistPoint; i++)
3016                         {
3017                             DWORD len = dataLen;
3018
3019                             ret = CRYPT_AsnEncodeDistPoint(
3020                              &info->rgDistPoint[i], pbEncoded, &len);
3021                             if (ret)
3022                             {
3023                                 pbEncoded += len;
3024                                 dataLen -= len;
3025                             }
3026                         }
3027                     }
3028                 }
3029             }
3030         }
3031     }
3032     __EXCEPT_PAGE_FAULT
3033     {
3034         SetLastError(STATUS_ACCESS_VIOLATION);
3035         ret = FALSE;
3036     }
3037     __ENDTRY
3038     return ret;
3039 }
3040
3041 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
3042  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3043  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3044 {
3045     BOOL ret;
3046
3047     __TRY
3048     {
3049         const CERT_ENHKEY_USAGE *usage =
3050          (const CERT_ENHKEY_USAGE *)pvStructInfo;
3051         DWORD bytesNeeded = 0, lenBytes, size, i;
3052
3053         ret = TRUE;
3054         for (i = 0; ret && i < usage->cUsageIdentifier; i++)
3055         {
3056             ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
3057              usage->rgpszUsageIdentifier[i],
3058              dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
3059             if (ret)
3060                 bytesNeeded += size;
3061         }
3062         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
3063         bytesNeeded += 1 + lenBytes;
3064         if (ret)
3065         {
3066             if (!pbEncoded)
3067                 *pcbEncoded = bytesNeeded;
3068             else
3069             {
3070                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
3071                  pbEncoded, pcbEncoded, bytesNeeded)))
3072                 {
3073                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3074                         pbEncoded = *(BYTE **)pbEncoded;
3075                     *pbEncoded++ = ASN_SEQUENCEOF;
3076                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
3077                      &lenBytes);
3078                     pbEncoded += lenBytes;
3079                     for (i = 0; ret && i < usage->cUsageIdentifier; i++)
3080                     {
3081                         size = bytesNeeded;
3082                         ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
3083                          usage->rgpszUsageIdentifier[i],
3084                          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
3085                          &size);
3086                         if (ret)
3087                         {
3088                             pbEncoded += size;
3089                             bytesNeeded -= size;
3090                         }
3091                     }
3092                 }
3093             }
3094         }
3095     }
3096     __EXCEPT_PAGE_FAULT
3097     {
3098         SetLastError(STATUS_ACCESS_VIOLATION);
3099         ret = FALSE;
3100     }
3101     __ENDTRY
3102     return ret;
3103 }
3104
3105 static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType,
3106  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3107  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3108 {
3109     BOOL ret;
3110
3111     __TRY
3112     {
3113         const CRL_ISSUING_DIST_POINT *point =
3114          (const CRL_ISSUING_DIST_POINT *)pvStructInfo;
3115         struct AsnEncodeSequenceItem items[6] = { { 0 } };
3116         struct AsnConstructedItem constructed = { 0 };
3117         struct AsnEncodeTagSwappedItem swapped[5] = { { 0 } };
3118         DWORD cItem = 0, cSwapped = 0;
3119
3120         ret = TRUE;
3121         switch (point->DistPointName.dwDistPointNameChoice)
3122         {
3123         case CRL_DIST_POINT_NO_NAME:
3124             /* do nothing */
3125             break;
3126         case CRL_DIST_POINT_FULL_NAME:
3127             swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
3128             swapped[cSwapped].pvStructInfo = &point->DistPointName.u.FullName;
3129             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
3130             constructed.tag = 0;
3131             constructed.pvStructInfo = &swapped[cSwapped];
3132             constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
3133             items[cItem].pvStructInfo = &constructed;
3134             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
3135             cSwapped++;
3136             cItem++;
3137             break;
3138         default:
3139             SetLastError(E_INVALIDARG);
3140             ret = FALSE;
3141         }
3142         if (ret && point->fOnlyContainsUserCerts)
3143         {
3144             swapped[cSwapped].tag = ASN_CONTEXT | 1;
3145             swapped[cSwapped].pvStructInfo = &point->fOnlyContainsUserCerts;
3146             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
3147             items[cItem].pvStructInfo = &swapped[cSwapped];
3148             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3149             cSwapped++;
3150             cItem++;
3151         }
3152         if (ret && point->fOnlyContainsCACerts)
3153         {
3154             swapped[cSwapped].tag = ASN_CONTEXT | 2;
3155             swapped[cSwapped].pvStructInfo = &point->fOnlyContainsCACerts;
3156             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
3157             items[cItem].pvStructInfo = &swapped[cSwapped];
3158             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3159             cSwapped++;
3160             cItem++;
3161         }
3162         if (ret && point->OnlySomeReasonFlags.cbData)
3163         {
3164             swapped[cSwapped].tag = ASN_CONTEXT | 3;
3165             swapped[cSwapped].pvStructInfo = &point->OnlySomeReasonFlags;
3166             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
3167             items[cItem].pvStructInfo = &swapped[cSwapped];
3168             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3169             cSwapped++;
3170             cItem++;
3171         }
3172         if (ret && point->fIndirectCRL)
3173         {
3174             swapped[cSwapped].tag = ASN_CONTEXT | 4;
3175             swapped[cSwapped].pvStructInfo = &point->fIndirectCRL;
3176             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
3177             items[cItem].pvStructInfo = &swapped[cSwapped];
3178             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3179             cSwapped++;
3180             cItem++;
3181         }
3182         if (ret)
3183             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
3184              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3185     }
3186     __EXCEPT_PAGE_FAULT
3187     {
3188         SetLastError(STATUS_ACCESS_VIOLATION);
3189         ret = FALSE;
3190     }
3191     __ENDTRY
3192     return ret;
3193 }
3194
3195 static BOOL WINAPI CRYPT_AsnEncodeGeneralSubtree(DWORD dwCertEncodingType,
3196  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3197  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3198 {
3199     BOOL ret;
3200     const CERT_GENERAL_SUBTREE *subtree =
3201      (const CERT_GENERAL_SUBTREE *)pvStructInfo;
3202     struct AsnEncodeSequenceItem items[3] = {
3203      { &subtree->Base, CRYPT_AsnEncodeAltNameEntry, 0 },
3204      { 0 }
3205     };
3206     struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
3207     DWORD cItem = 1, cSwapped = 0;
3208
3209     if (subtree->dwMinimum)
3210     {
3211         swapped[cSwapped].tag = ASN_CONTEXT | 0;
3212         swapped[cSwapped].pvStructInfo = &subtree->dwMinimum;
3213         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInt;
3214         items[cItem].pvStructInfo = &swapped[cSwapped];
3215         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3216         cSwapped++;
3217         cItem++;
3218     }
3219     if (subtree->fMaximum)
3220     {
3221         swapped[cSwapped].tag = ASN_CONTEXT | 1;
3222         swapped[cSwapped].pvStructInfo = &subtree->dwMaximum;
3223         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInt;
3224         items[cItem].pvStructInfo = &swapped[cSwapped];
3225         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3226         cSwapped++;
3227         cItem++;
3228     }
3229     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem, dwFlags,
3230      pEncodePara, pbEncoded, pcbEncoded);
3231     return ret;
3232 }
3233
3234 static BOOL WINAPI CRYPT_AsnEncodeNameConstraints(DWORD dwCertEncodingType,
3235  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3236  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3237 {
3238     BOOL ret = FALSE;
3239     CRYPT_BLOB_ARRAY permitted = { 0, NULL }, excluded = { 0, NULL };
3240
3241     TRACE("%p\n", pvStructInfo);
3242
3243     __TRY
3244     {
3245         const CERT_NAME_CONSTRAINTS_INFO *constraints =
3246          (const CERT_NAME_CONSTRAINTS_INFO *)pvStructInfo;
3247         struct AsnEncodeSequenceItem items[2] = { { 0 } };
3248         struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
3249         DWORD i, cItem = 0, cSwapped = 0;
3250
3251         ret = TRUE;
3252         if (constraints->cPermittedSubtree)
3253         {
3254             permitted.rgBlob = CryptMemAlloc(
3255              constraints->cPermittedSubtree * sizeof(CRYPT_DER_BLOB));
3256             if (permitted.rgBlob)
3257             {
3258                 permitted.cBlob = constraints->cPermittedSubtree;
3259                 memset(permitted.rgBlob, 0,
3260                  permitted.cBlob * sizeof(CRYPT_DER_BLOB));
3261                 for (i = 0; ret && i < permitted.cBlob; i++)
3262                     ret = CRYPT_AsnEncodeGeneralSubtree(dwCertEncodingType,
3263                      NULL, &constraints->rgPermittedSubtree[i],
3264                      CRYPT_ENCODE_ALLOC_FLAG, NULL,
3265                      (BYTE *)&permitted.rgBlob[i].pbData,
3266                      &permitted.rgBlob[i].cbData);
3267                 if (ret)
3268                 {
3269                     swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
3270                     swapped[cSwapped].pvStructInfo = &permitted;
3271                     swapped[cSwapped].encodeFunc = CRYPT_DEREncodeSet;
3272                     items[cItem].pvStructInfo = &swapped[cSwapped];
3273                     items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3274                     cSwapped++;
3275                     cItem++;
3276                 }
3277             }
3278             else
3279                 ret = FALSE;
3280         }
3281         if (constraints->cExcludedSubtree)
3282         {
3283             excluded.rgBlob = CryptMemAlloc(
3284              constraints->cExcludedSubtree * sizeof(CRYPT_DER_BLOB));
3285             if (excluded.rgBlob)
3286             {
3287                 excluded.cBlob = constraints->cExcludedSubtree;
3288                 memset(excluded.rgBlob, 0,
3289                  excluded.cBlob * sizeof(CRYPT_DER_BLOB));
3290                 for (i = 0; ret && i < excluded.cBlob; i++)
3291                     ret = CRYPT_AsnEncodeGeneralSubtree(dwCertEncodingType,
3292                      NULL, &constraints->rgExcludedSubtree[i],
3293                      CRYPT_ENCODE_ALLOC_FLAG, NULL,
3294                      (BYTE *)&excluded.rgBlob[i].pbData,
3295                      &excluded.rgBlob[i].cbData);
3296                 if (ret)
3297                 {
3298                     swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
3299                     swapped[cSwapped].pvStructInfo = &excluded;
3300                     swapped[cSwapped].encodeFunc = CRYPT_DEREncodeSet;
3301                     items[cItem].pvStructInfo = &swapped[cSwapped];
3302                     items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3303                     cSwapped++;
3304                     cItem++;
3305                 }
3306             }
3307             else
3308                 ret = FALSE;
3309         }
3310         if (ret)
3311             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
3312              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3313         for (i = 0; i < permitted.cBlob; i++)
3314             LocalFree(permitted.rgBlob[i].pbData);
3315         for (i = 0; i < excluded.cBlob; i++)
3316             LocalFree(excluded.rgBlob[i].pbData);
3317     }
3318     __EXCEPT_PAGE_FAULT
3319     {
3320         SetLastError(STATUS_ACCESS_VIOLATION);
3321     }
3322     __ENDTRY
3323     CryptMemFree(permitted.rgBlob);
3324     CryptMemFree(excluded.rgBlob);
3325     TRACE("returning %d\n", ret);
3326     return ret;
3327 }
3328
3329 static BOOL WINAPI CRYPT_AsnEncodeIssuerSerialNumber(
3330  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
3331  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
3332  DWORD *pcbEncoded)
3333 {
3334     BOOL ret;
3335     const CERT_ISSUER_SERIAL_NUMBER *issuerSerial =
3336      (const CERT_ISSUER_SERIAL_NUMBER *)pvStructInfo;
3337     struct AsnEncodeSequenceItem items[] = {
3338      { &issuerSerial->Issuer,       CRYPT_CopyEncodedBlob, 0 },
3339      { &issuerSerial->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
3340     };
3341
3342     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
3343      sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
3344      pcbEncoded);
3345     return ret;
3346 }
3347
3348 static BOOL WINAPI CRYPT_AsnEncodePKCSSignerInfo(DWORD dwCertEncodingType,
3349  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3350  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3351 {
3352     BOOL ret = FALSE;
3353
3354     if (!(dwCertEncodingType & PKCS_7_ASN_ENCODING))
3355     {
3356         SetLastError(E_INVALIDARG);
3357         return FALSE;
3358     }
3359
3360     __TRY
3361     {
3362         const CMSG_SIGNER_INFO *info = (const CMSG_SIGNER_INFO *)pvStructInfo;
3363
3364         if (!info->Issuer.cbData)
3365             SetLastError(E_INVALIDARG);
3366         else
3367         {
3368             struct AsnEncodeSequenceItem items[7] = {
3369              { &info->dwVersion,     CRYPT_AsnEncodeInt, 0 },
3370              { &info->Issuer,        CRYPT_AsnEncodeIssuerSerialNumber, 0 },
3371              { &info->HashAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams,
3372                0 },
3373             };
3374             struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
3375             DWORD cItem = 3, cSwapped = 0;
3376
3377             if (info->AuthAttrs.cAttr)
3378             {
3379                 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
3380                 swapped[cSwapped].pvStructInfo = &info->AuthAttrs;
3381                 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodePKCSAttributes;
3382                 items[cItem].pvStructInfo = &swapped[cSwapped];
3383                 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3384                 cSwapped++;
3385                 cItem++;
3386             }
3387             items[cItem].pvStructInfo = &info->HashEncryptionAlgorithm;
3388             items[cItem].encodeFunc = CRYPT_AsnEncodeAlgorithmIdWithNullParams;
3389             cItem++;
3390             items[cItem].pvStructInfo = &info->EncryptedHash;
3391             items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
3392             cItem++;
3393             if (info->UnauthAttrs.cAttr)
3394             {
3395                 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
3396                 swapped[cSwapped].pvStructInfo = &info->UnauthAttrs;
3397                 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodePKCSAttributes;
3398                 items[cItem].pvStructInfo = &swapped[cSwapped];
3399                 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3400                 cSwapped++;
3401                 cItem++;
3402             }
3403             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
3404              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3405         }
3406     }
3407     __EXCEPT_PAGE_FAULT
3408     {
3409         SetLastError(STATUS_ACCESS_VIOLATION);
3410     }
3411     __ENDTRY
3412     return ret;
3413 }
3414
3415 BOOL CRYPT_AsnEncodePKCSSignedInfo(CRYPT_SIGNED_INFO *signedInfo, void *pvData,
3416  DWORD *pcbData)
3417 {
3418     struct AsnEncodeSequenceItem items[7] = {
3419      { &signedInfo->version, CRYPT_AsnEncodeInt, 0 },
3420     };
3421     struct DERSetDescriptor digestAlgorithmsSet = { 0 }, certSet = { 0 };
3422     struct DERSetDescriptor crlSet = { 0 }, signerSet = { 0 };
3423     struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
3424     DWORD cItem = 1, cSwapped = 0;
3425     BOOL ret = TRUE;
3426
3427     if (signedInfo->cSignerInfo)
3428     {
3429         digestAlgorithmsSet.cItems = signedInfo->cSignerInfo;
3430         digestAlgorithmsSet.items = signedInfo->rgSignerInfo;
3431         digestAlgorithmsSet.itemSize = sizeof(CMSG_SIGNER_INFO);
3432         digestAlgorithmsSet.itemOffset =
3433          offsetof(CMSG_SIGNER_INFO, HashAlgorithm);
3434         digestAlgorithmsSet.encode = CRYPT_AsnEncodeAlgorithmIdWithNullParams;
3435         items[cItem].pvStructInfo = &digestAlgorithmsSet;
3436         items[cItem].encodeFunc = CRYPT_DEREncodeItemsAsSet;
3437         cItem++;
3438     }
3439     items[cItem].pvStructInfo = &signedInfo->content;
3440     items[cItem].encodeFunc = CRYPT_AsnEncodePKCSContentInfoInternal;
3441     cItem++;
3442     if (signedInfo->cCertEncoded)
3443     {
3444         certSet.cItems = signedInfo->cCertEncoded;
3445         certSet.items = signedInfo->rgCertEncoded;
3446         certSet.itemSize = sizeof(CERT_BLOB);
3447         certSet.itemOffset = 0;
3448         certSet.encode = CRYPT_CopyEncodedBlob;
3449         swapped[cSwapped].tag = ASN_CONSTRUCTOR | ASN_CONTEXT | 0;
3450         swapped[cSwapped].pvStructInfo = &certSet;
3451         swapped[cSwapped].encodeFunc = CRYPT_DEREncodeItemsAsSet;
3452         items[cItem].pvStructInfo = &swapped[cSwapped];
3453         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3454         cSwapped++;
3455         cItem++;
3456     }
3457     if (signedInfo->cCrlEncoded)
3458     {
3459         crlSet.cItems = signedInfo->cCrlEncoded;
3460         crlSet.items = signedInfo->rgCrlEncoded;
3461         crlSet.itemSize = sizeof(CRL_BLOB);
3462         crlSet.itemOffset = 0;
3463         crlSet.encode = CRYPT_CopyEncodedBlob;
3464         swapped[cSwapped].tag = ASN_CONSTRUCTOR | ASN_CONTEXT | 1;
3465         swapped[cSwapped].pvStructInfo = &crlSet;
3466         swapped[cSwapped].encodeFunc = CRYPT_DEREncodeItemsAsSet;
3467         items[cItem].pvStructInfo = &swapped[cSwapped];
3468         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3469         cSwapped++;
3470         cItem++;
3471     }
3472     if (ret && signedInfo->cSignerInfo)
3473     {
3474         signerSet.cItems = signedInfo->cSignerInfo;
3475         signerSet.items = signedInfo->rgSignerInfo;
3476         signerSet.itemSize = sizeof(CMSG_SIGNER_INFO);
3477         signerSet.itemOffset = 0;
3478         signerSet.encode = CRYPT_AsnEncodePKCSSignerInfo;
3479         items[cItem].pvStructInfo = &signerSet;
3480         items[cItem].encodeFunc = CRYPT_DEREncodeItemsAsSet;
3481         cItem++;
3482     }
3483     if (ret)
3484         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
3485          items, cItem, 0, NULL, pvData, pcbData);
3486
3487     return ret;
3488 }
3489
3490 static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType,
3491  LPCSTR lpszStructType)
3492 {
3493     CryptEncodeObjectExFunc encodeFunc = NULL;
3494
3495     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
3496      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
3497     {
3498         SetLastError(ERROR_FILE_NOT_FOUND);
3499         return NULL;
3500     }
3501
3502     if (!HIWORD(lpszStructType))
3503     {
3504         switch (LOWORD(lpszStructType))
3505         {
3506         case LOWORD(X509_CERT):
3507             encodeFunc = CRYPT_AsnEncodeCert;
3508             break;
3509         case LOWORD(X509_CERT_TO_BE_SIGNED):
3510             encodeFunc = CRYPT_AsnEncodeCertInfo;
3511             break;
3512         case LOWORD(X509_CERT_CRL_TO_BE_SIGNED):
3513             encodeFunc = CRYPT_AsnEncodeCRLInfo;
3514             break;
3515         case LOWORD(X509_EXTENSIONS):
3516             encodeFunc = CRYPT_AsnEncodeExtensions;
3517             break;
3518         case LOWORD(X509_NAME_VALUE):
3519             encodeFunc = CRYPT_AsnEncodeNameValue;
3520             break;
3521         case LOWORD(X509_NAME):
3522             encodeFunc = CRYPT_AsnEncodeName;
3523             break;
3524         case LOWORD(X509_PUBLIC_KEY_INFO):
3525             encodeFunc = CRYPT_AsnEncodePubKeyInfo;
3526             break;
3527         case LOWORD(X509_AUTHORITY_KEY_ID):
3528             encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3529             break;
3530         case LOWORD(X509_ALTERNATE_NAME):
3531             encodeFunc = CRYPT_AsnEncodeAltName;
3532             break;
3533         case LOWORD(X509_BASIC_CONSTRAINTS):
3534             encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3535             break;
3536         case LOWORD(X509_BASIC_CONSTRAINTS2):
3537             encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3538             break;
3539         case LOWORD(RSA_CSP_PUBLICKEYBLOB):
3540             encodeFunc = CRYPT_AsnEncodeRsaPubKey;
3541             break;
3542         case LOWORD(X509_UNICODE_NAME):
3543             encodeFunc = CRYPT_AsnEncodeUnicodeName;
3544             break;
3545         case LOWORD(PKCS_CONTENT_INFO):
3546             encodeFunc = CRYPT_AsnEncodePKCSContentInfo;
3547             break;
3548         case LOWORD(PKCS_ATTRIBUTE):
3549             encodeFunc = CRYPT_AsnEncodePKCSAttribute;
3550             break;
3551         case LOWORD(X509_UNICODE_NAME_VALUE):
3552             encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
3553             break;
3554         case LOWORD(X509_OCTET_STRING):
3555             encodeFunc = CRYPT_AsnEncodeOctets;
3556             break;
3557         case LOWORD(X509_BITS):
3558         case LOWORD(X509_KEY_USAGE):
3559             encodeFunc = CRYPT_AsnEncodeBits;
3560             break;
3561         case LOWORD(X509_INTEGER):
3562             encodeFunc = CRYPT_AsnEncodeInt;
3563             break;
3564         case LOWORD(X509_MULTI_BYTE_INTEGER):
3565             encodeFunc = CRYPT_AsnEncodeInteger;
3566             break;
3567         case LOWORD(X509_MULTI_BYTE_UINT):
3568             encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
3569             break;
3570         case LOWORD(X509_ENUMERATED):
3571             encodeFunc = CRYPT_AsnEncodeEnumerated;
3572             break;
3573         case LOWORD(X509_CHOICE_OF_TIME):
3574             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
3575             break;
3576         case LOWORD(X509_AUTHORITY_KEY_ID2):
3577             encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
3578             break;
3579         case LOWORD(X509_SEQUENCE_OF_ANY):
3580             encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
3581             break;
3582         case LOWORD(PKCS_UTC_TIME):
3583             encodeFunc = CRYPT_AsnEncodeUtcTime;
3584             break;
3585         case LOWORD(X509_CRL_DIST_POINTS):
3586             encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3587             break;
3588         case LOWORD(X509_ENHANCED_KEY_USAGE):
3589             encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3590             break;
3591         case LOWORD(PKCS_ATTRIBUTES):
3592             encodeFunc = CRYPT_AsnEncodePKCSAttributes;
3593             break;
3594         case LOWORD(X509_ISSUING_DIST_POINT):
3595             encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3596             break;
3597         case LOWORD(X509_NAME_CONSTRAINTS):
3598             encodeFunc = CRYPT_AsnEncodeNameConstraints;
3599             break;
3600         case LOWORD(PKCS7_SIGNER_INFO):
3601             encodeFunc = CRYPT_AsnEncodePKCSSignerInfo;
3602             break;
3603         }
3604     }
3605     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
3606         encodeFunc = CRYPT_AsnEncodeExtensions;
3607     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
3608         encodeFunc = CRYPT_AsnEncodeUtcTime;
3609     else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
3610         encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3611     else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
3612         encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
3613     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
3614         encodeFunc = CRYPT_AsnEncodeEnumerated;
3615     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
3616         encodeFunc = CRYPT_AsnEncodeBits;
3617     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
3618         encodeFunc = CRYPT_AsnEncodeOctets;
3619     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
3620         encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3621     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
3622         encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3623     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
3624         encodeFunc = CRYPT_AsnEncodeAltName;
3625     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
3626         encodeFunc = CRYPT_AsnEncodeAltName;
3627     else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
3628         encodeFunc = CRYPT_AsnEncodeAltName;
3629     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
3630         encodeFunc = CRYPT_AsnEncodeAltName;
3631     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
3632         encodeFunc = CRYPT_AsnEncodeAltName;
3633     else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
3634         encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3635     else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
3636         encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3637     else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
3638         encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3639     else if (!strcmp(lpszStructType, szOID_NAME_CONSTRAINTS))
3640         encodeFunc = CRYPT_AsnEncodeNameConstraints;
3641     return encodeFunc;
3642 }
3643
3644 static CryptEncodeObjectFunc CRYPT_LoadEncoderFunc(DWORD dwCertEncodingType,
3645  LPCSTR lpszStructType, HCRYPTOIDFUNCADDR *hFunc)
3646 {
3647     static HCRYPTOIDFUNCSET set = NULL;
3648     CryptEncodeObjectFunc encodeFunc = NULL;
3649
3650     if (!set)
3651         set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_FUNC, 0);
3652     CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
3653      (void **)&encodeFunc, hFunc);
3654     return encodeFunc;
3655 }
3656
3657 static CryptEncodeObjectExFunc CRYPT_LoadEncoderExFunc(DWORD dwCertEncodingType,
3658  LPCSTR lpszStructType, HCRYPTOIDFUNCADDR *hFunc)
3659 {
3660     static HCRYPTOIDFUNCSET set = NULL;
3661     CryptEncodeObjectExFunc encodeFunc = NULL;
3662
3663     if (!set)
3664         set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
3665     CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
3666      (void **)&encodeFunc, hFunc);
3667     return encodeFunc;
3668 }
3669
3670 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
3671  const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
3672 {
3673     BOOL ret = FALSE;
3674     HCRYPTOIDFUNCADDR hFunc = NULL;
3675     CryptEncodeObjectFunc pCryptEncodeObject = NULL;
3676     CryptEncodeObjectExFunc pCryptEncodeObjectEx = NULL;
3677
3678     TRACE_(crypt)("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
3679      debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
3680      pcbEncoded);
3681
3682     if (!pbEncoded && !pcbEncoded)
3683     {
3684         SetLastError(ERROR_INVALID_PARAMETER);
3685         return FALSE;
3686     }
3687
3688     if (!(pCryptEncodeObjectEx = CRYPT_GetBuiltinEncoder(dwCertEncodingType,
3689      lpszStructType)))
3690     {
3691         TRACE_(crypt)("OID %s not found or unimplemented, looking for DLL\n",
3692          debugstr_a(lpszStructType));
3693         pCryptEncodeObject = CRYPT_LoadEncoderFunc(dwCertEncodingType,
3694          lpszStructType, &hFunc);
3695         if (!pCryptEncodeObject)
3696             pCryptEncodeObjectEx = CRYPT_LoadEncoderExFunc(dwCertEncodingType,
3697              lpszStructType, &hFunc);
3698     }
3699     if (pCryptEncodeObject)
3700         ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
3701          pvStructInfo, pbEncoded, pcbEncoded);
3702     else if (pCryptEncodeObjectEx)
3703         ret = pCryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
3704          pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
3705     if (hFunc)
3706         CryptFreeOIDFunctionAddress(hFunc, 0);
3707     TRACE_(crypt)("returning %d\n", ret);
3708     return ret;
3709 }
3710
3711 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
3712  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
3713  void *pvEncoded, DWORD *pcbEncoded)
3714 {
3715     BOOL ret = FALSE;
3716     HCRYPTOIDFUNCADDR hFunc = NULL;
3717     CryptEncodeObjectExFunc encodeFunc = NULL;
3718
3719     TRACE_(crypt)("(0x%08x, %s, %p, 0x%08x, %p, %p, %p)\n", dwCertEncodingType,
3720      debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
3721      pvEncoded, pcbEncoded);
3722
3723     if (!pvEncoded && !pcbEncoded)
3724     {
3725         SetLastError(ERROR_INVALID_PARAMETER);
3726         return FALSE;
3727     }
3728
3729     SetLastError(NOERROR);
3730     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
3731         *(BYTE **)pvEncoded = NULL;
3732     encodeFunc = CRYPT_GetBuiltinEncoder(dwCertEncodingType, lpszStructType);
3733     if (!encodeFunc)
3734     {
3735         TRACE_(crypt)("OID %s not found or unimplemented, looking for DLL\n",
3736          debugstr_a(lpszStructType));
3737         encodeFunc = CRYPT_LoadEncoderExFunc(dwCertEncodingType, lpszStructType,
3738          &hFunc);
3739     }
3740     if (encodeFunc)
3741         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
3742          dwFlags, pEncodePara, pvEncoded, pcbEncoded);
3743     else
3744     {
3745         CryptEncodeObjectFunc pCryptEncodeObject =
3746          CRYPT_LoadEncoderFunc(dwCertEncodingType, lpszStructType, &hFunc);
3747
3748         if (pCryptEncodeObject)
3749         {
3750             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3751             {
3752                 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
3753                  pvStructInfo, NULL, pcbEncoded);
3754                 if (ret && (ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
3755                  pvEncoded, pcbEncoded, *pcbEncoded)))
3756                     ret = pCryptEncodeObject(dwCertEncodingType,
3757                      lpszStructType, pvStructInfo, *(BYTE **)pvEncoded,
3758                      pcbEncoded);
3759             }
3760             else
3761                 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
3762                  pvStructInfo, pvEncoded, pcbEncoded);
3763         }
3764     }
3765     if (hFunc)
3766         CryptFreeOIDFunctionAddress(hFunc, 0);
3767     TRACE_(crypt)("returning %d\n", ret);
3768     return ret;
3769 }
3770
3771 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, DWORD dwKeySpec,
3772  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3773 {
3774     return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
3775      NULL, 0, NULL, pInfo, pcbInfo);
3776 }
3777
3778 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
3779  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3780  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3781 {
3782     BOOL ret;
3783     HCRYPTKEY key;
3784     static CHAR oid[] = szOID_RSA_RSA;
3785
3786     TRACE_(crypt)("(%08lx, %d, %08x, %s, %08x, %p, %p, %d)\n", hCryptProv,
3787      dwKeySpec, dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags,
3788      pvAuxInfo, pInfo, pInfo ? *pcbInfo : 0);
3789
3790     if (!pszPublicKeyObjId)
3791         pszPublicKeyObjId = oid;
3792     if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
3793     {
3794         DWORD keySize = 0;
3795
3796         ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
3797         if (ret)
3798         {
3799             LPBYTE pubKey = CryptMemAlloc(keySize);
3800
3801             if (pubKey)
3802             {
3803                 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
3804                  &keySize);
3805                 if (ret)
3806                 {
3807                     DWORD encodedLen = 0;
3808
3809                     ret = CryptEncodeObject(dwCertEncodingType,
3810                      RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
3811                     if (ret)
3812                     {
3813                         DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
3814                          strlen(pszPublicKeyObjId) + 1 + encodedLen;
3815
3816                         if (!pInfo)
3817                             *pcbInfo = sizeNeeded;
3818                         else if (*pcbInfo < sizeNeeded)
3819                         {
3820                             SetLastError(ERROR_MORE_DATA);
3821                             *pcbInfo = sizeNeeded;
3822                             ret = FALSE;
3823                         }
3824                         else
3825                         {
3826                             pInfo->Algorithm.pszObjId = (char *)pInfo +
3827                              sizeof(CERT_PUBLIC_KEY_INFO);
3828                             lstrcpyA(pInfo->Algorithm.pszObjId,
3829                              pszPublicKeyObjId);
3830                             pInfo->Algorithm.Parameters.cbData = 0;
3831                             pInfo->Algorithm.Parameters.pbData = NULL;
3832                             pInfo->PublicKey.pbData =
3833                              (BYTE *)pInfo->Algorithm.pszObjId
3834                              + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
3835                             pInfo->PublicKey.cbData = encodedLen;
3836                             pInfo->PublicKey.cUnusedBits = 0;
3837                             ret = CryptEncodeObject(dwCertEncodingType,
3838                              RSA_CSP_PUBLICKEYBLOB, pubKey,
3839                              pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
3840                         }
3841                     }
3842                 }
3843                 CryptMemFree(pubKey);
3844             }
3845             else
3846                 ret = FALSE;
3847         }
3848         CryptDestroyKey(key);
3849     }
3850     return ret;
3851 }
3852
3853 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
3854  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3855  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
3856
3857 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, DWORD dwKeySpec,
3858  DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
3859  void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3860 {
3861     static HCRYPTOIDFUNCSET set = NULL;
3862     BOOL ret;
3863     ExportPublicKeyInfoExFunc exportFunc = NULL;
3864     HCRYPTOIDFUNCADDR hFunc = NULL;
3865
3866     TRACE_(crypt)("(%08lx, %d, %08x, %s, %08x, %p, %p, %d)\n", hCryptProv,
3867      dwKeySpec, dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags,
3868      pvAuxInfo, pInfo, pInfo ? *pcbInfo : 0);
3869
3870     if (!hCryptProv)
3871     {
3872         SetLastError(ERROR_INVALID_PARAMETER);
3873         return FALSE;
3874     }
3875
3876     if (pszPublicKeyObjId)
3877     {
3878         if (!set)
3879             set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
3880              0);
3881         CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
3882          0, (void **)&exportFunc, &hFunc);
3883     }
3884     if (!exportFunc)
3885         exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
3886     ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
3887      pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
3888     if (hFunc)
3889         CryptFreeOIDFunctionAddress(hFunc, 0);
3890     return ret;
3891 }
3892
3893 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
3894  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
3895 {
3896     return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
3897      0, 0, NULL, phKey);
3898 }
3899
3900 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3901  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3902  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3903 {
3904     BOOL ret;
3905     DWORD pubKeySize = 0;
3906
3907     TRACE_(crypt)("(%08lx, %08x, %p, %08x, %08x, %p, %p)\n", hCryptProv,
3908      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3909
3910     ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3911      pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
3912     if (ret)
3913     {
3914         LPBYTE pubKey = CryptMemAlloc(pubKeySize);
3915
3916         if (pubKey)
3917         {
3918             ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3919              pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
3920              &pubKeySize);
3921             if (ret)
3922                 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
3923                  phKey);
3924             CryptMemFree(pubKey);
3925         }
3926         else
3927             ret = FALSE;
3928     }
3929     return ret;
3930 }
3931
3932 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3933  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3934  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
3935
3936 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3937  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3938  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3939 {
3940     static HCRYPTOIDFUNCSET set = NULL;
3941     BOOL ret;
3942     ImportPublicKeyInfoExFunc importFunc = NULL;
3943     HCRYPTOIDFUNCADDR hFunc = NULL;
3944
3945     TRACE_(crypt)("(%08lx, %08x, %p, %08x, %08x, %p, %p)\n", hCryptProv,
3946      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3947
3948     if (!set)
3949         set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
3950     CryptGetOIDFunctionAddress(set, dwCertEncodingType,
3951      pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
3952     if (!importFunc)
3953         importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
3954     ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
3955      pvAuxInfo, phKey);
3956     if (hFunc)
3957         CryptFreeOIDFunctionAddress(hFunc, 0);
3958     return ret;
3959 }