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