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