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