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