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