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