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