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