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