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