kernel32: FindExSearchLimitToDirectories has no effect on FindFirstFileEx.
[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     strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
917      lstrlenW(str);
918     CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes);
919     bytesNeeded = 1 + lenBytes + strLen * 2;
920     if (!pbEncoded)
921         *pcbEncoded = bytesNeeded;
922     else
923     {
924         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
925          pbEncoded, pcbEncoded, bytesNeeded)))
926         {
927             DWORD i;
928
929             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
930                 pbEncoded = *(BYTE **)pbEncoded;
931             *pbEncoded++ = ASN_BMPSTRING;
932             CRYPT_EncodeLen(strLen * 2, pbEncoded, &lenBytes);
933             pbEncoded += lenBytes;
934             for (i = 0; i < strLen; i++)
935             {
936                 *pbEncoded++ = (str[i] & 0xff00) >> 8;
937                 *pbEncoded++ = str[i] & 0x00ff;
938             }
939         }
940     }
941     return ret;
942 }
943
944 static BOOL CRYPT_AsnEncodeUTF8String(const CERT_NAME_VALUE *value,
945  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
946  DWORD *pcbEncoded)
947 {
948     BOOL ret = TRUE;
949     LPCWSTR str = (LPCWSTR)value->Value.pbData;
950     DWORD bytesNeeded, lenBytes, encodedLen, strLen;
951
952     strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
953      lstrlenW(str);
954     encodedLen = WideCharToMultiByte(CP_UTF8, 0, str, strLen, NULL, 0, NULL,
955      NULL);
956     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
957     bytesNeeded = 1 + lenBytes + encodedLen;
958     if (!pbEncoded)
959         *pcbEncoded = bytesNeeded;
960     else
961     {
962         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
963          pbEncoded, pcbEncoded, bytesNeeded)))
964         {
965             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
966                 pbEncoded = *(BYTE **)pbEncoded;
967             *pbEncoded++ = ASN_UTF8STRING;
968             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
969             pbEncoded += lenBytes;
970             WideCharToMultiByte(CP_UTF8, 0, str, strLen, (LPSTR)pbEncoded,
971              bytesNeeded - lenBytes - 1, NULL, NULL);
972         }
973     }
974     return ret;
975 }
976
977 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
978  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
979  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
980 {
981     BOOL ret = TRUE;
982
983     __TRY
984     {
985         const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
986
987         switch (value->dwValueType)
988         {
989         case CERT_RDN_ANY_TYPE:
990             /* explicitly disallowed */
991             SetLastError(E_INVALIDARG);
992             ret = FALSE;
993             break;
994         case CERT_RDN_ENCODED_BLOB:
995             ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL,
996              &value->Value, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
997             break;
998         case CERT_RDN_OCTET_STRING:
999             ret = CRYPT_AsnEncodeStringCoerce(value, ASN_OCTETSTRING,
1000              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1001             break;
1002         case CERT_RDN_NUMERIC_STRING:
1003             ret = CRYPT_AsnEncodeStringCoerce(value, ASN_NUMERICSTRING,
1004              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1005             break;
1006         case CERT_RDN_PRINTABLE_STRING:
1007             ret = CRYPT_AsnEncodeStringCoerce(value, ASN_PRINTABLESTRING,
1008              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1009             break;
1010         case CERT_RDN_TELETEX_STRING:
1011             ret = CRYPT_AsnEncodeStringCoerce(value, ASN_T61STRING,
1012              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1013             break;
1014         case CERT_RDN_VIDEOTEX_STRING:
1015             ret = CRYPT_AsnEncodeStringCoerce(value,
1016              ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1017             break;
1018         case CERT_RDN_IA5_STRING:
1019             ret = CRYPT_AsnEncodeStringCoerce(value, ASN_IA5STRING,
1020              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1021             break;
1022         case CERT_RDN_GRAPHIC_STRING:
1023             ret = CRYPT_AsnEncodeStringCoerce(value, ASN_GRAPHICSTRING,
1024              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1025             break;
1026         case CERT_RDN_VISIBLE_STRING:
1027             ret = CRYPT_AsnEncodeStringCoerce(value, ASN_VISIBLESTRING,
1028              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1029             break;
1030         case CERT_RDN_GENERAL_STRING:
1031             ret = CRYPT_AsnEncodeStringCoerce(value, ASN_GENERALSTRING,
1032              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1033             break;
1034         case CERT_RDN_UNIVERSAL_STRING:
1035             FIXME("CERT_RDN_UNIVERSAL_STRING: unimplemented\n");
1036             SetLastError(CRYPT_E_ASN1_CHOICE);
1037             ret = FALSE;
1038             break;
1039         case CERT_RDN_BMP_STRING:
1040             ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
1041              pbEncoded, pcbEncoded);
1042             break;
1043         case CERT_RDN_UTF8_STRING:
1044             ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
1045              pbEncoded, pcbEncoded);
1046             break;
1047         default:
1048             SetLastError(CRYPT_E_ASN1_CHOICE);
1049             ret = FALSE;
1050         }
1051     }
1052     __EXCEPT_PAGE_FAULT
1053     {
1054         SetLastError(STATUS_ACCESS_VIOLATION);
1055         ret = FALSE;
1056     }
1057     __ENDTRY
1058     return ret;
1059 }
1060
1061 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1062  CERT_RDN_ATTR *attr, CryptEncodeObjectExFunc nameValueEncodeFunc,
1063  BYTE *pbEncoded, DWORD *pcbEncoded)
1064 {
1065     DWORD bytesNeeded = 0, lenBytes, size;
1066     BOOL ret;
1067
1068     ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1069      0, NULL, NULL, &size);
1070     if (ret)
1071     {
1072         bytesNeeded += size;
1073         /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1074          * with dwValueType, so "cast" it to get its encoded size
1075          */
1076         ret = nameValueEncodeFunc(dwCertEncodingType, NULL,
1077          (CERT_NAME_VALUE *)&attr->dwValueType, 0, NULL, NULL, &size);
1078         if (ret)
1079         {
1080             bytesNeeded += size;
1081             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1082             bytesNeeded += 1 + lenBytes;
1083             if (pbEncoded)
1084             {
1085                 if (*pcbEncoded < bytesNeeded)
1086                 {
1087                     SetLastError(ERROR_MORE_DATA);
1088                     ret = FALSE;
1089                 }
1090                 else
1091                 {
1092                     *pbEncoded++ = ASN_SEQUENCE;
1093                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1094                      &lenBytes);
1095                     pbEncoded += lenBytes;
1096                     size = bytesNeeded - 1 - lenBytes;
1097                     ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1098                      attr->pszObjId, 0, NULL, pbEncoded, &size);
1099                     if (ret)
1100                     {
1101                         pbEncoded += size;
1102                         size = bytesNeeded - 1 - lenBytes - size;
1103                         ret = nameValueEncodeFunc(dwCertEncodingType,
1104                          NULL, (CERT_NAME_VALUE *)&attr->dwValueType,
1105                          0, NULL, pbEncoded, &size);
1106                         if (!ret)
1107                             *pcbEncoded = size;
1108                     }
1109                 }
1110             }
1111             if (ret)
1112                 *pcbEncoded = bytesNeeded;
1113         }
1114         else
1115         {
1116             /* Have to propagate index of failing character */
1117             *pcbEncoded = size;
1118         }
1119     }
1120     return ret;
1121 }
1122
1123 static int BLOBComp(const void *l, const void *r)
1124 {
1125     const CRYPT_DER_BLOB *a = (const CRYPT_DER_BLOB *)l, *b = (const CRYPT_DER_BLOB *)r;
1126     int ret;
1127
1128     if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1129         ret = a->cbData - b->cbData;
1130     return ret;
1131 }
1132
1133 typedef struct _CRYPT_SET_OF {
1134     DWORD           cValue;
1135     PCRYPT_DER_BLOB rgValue;
1136 } CRYPT_SET_OF;
1137
1138 /* This encodes a SET OF, which in DER must be lexicographically sorted.
1139  */
1140 static BOOL WINAPI CRYPT_DEREncodeSet(DWORD dwCertEncodingType,
1141  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1142  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1143 {
1144     const CRYPT_SET_OF *set = (const CRYPT_SET_OF *)pvStructInfo;
1145     DWORD bytesNeeded = 0, lenBytes, i;
1146     BOOL ret;
1147
1148     for (i = 0; i < set->cValue; i++)
1149         bytesNeeded += set->rgValue[i].cbData;
1150     CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1151     bytesNeeded += 1 + lenBytes;
1152     if (!pbEncoded)
1153     {
1154         *pcbEncoded = bytesNeeded;
1155         ret = TRUE;
1156     }
1157     else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1158      pbEncoded, pcbEncoded, bytesNeeded)))
1159     {
1160         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1161             pbEncoded = *(BYTE **)pbEncoded;
1162         qsort(set->rgValue, set->cValue, sizeof(CRYPT_DER_BLOB), BLOBComp);
1163         *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1164         CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, &lenBytes);
1165         pbEncoded += lenBytes;
1166         for (i = 0; ret && i < set->cValue; i++)
1167         {
1168             memcpy(pbEncoded, set->rgValue[i].pbData, set->rgValue[i].cbData);
1169             pbEncoded += set->rgValue[i].cbData;
1170         }
1171     }
1172     return ret;
1173 }
1174
1175 struct DERSetDescriptor
1176 {
1177     DWORD                   cItems;
1178     const void             *items;
1179     size_t                  itemSize;
1180     size_t                  itemOffset;
1181     CryptEncodeObjectExFunc encode;
1182 };
1183
1184 static BOOL WINAPI CRYPT_DEREncodeItemsAsSet(DWORD dwCertEncodingType,
1185  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1186  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1187 {
1188     const struct DERSetDescriptor *desc =
1189      (const struct DERSetDescriptor *)pvStructInfo;
1190     CRYPT_SET_OF setOf = { 0, NULL };
1191     BOOL ret = TRUE;
1192     DWORD i;
1193
1194     if (desc->cItems)
1195     {
1196         setOf.rgValue = CryptMemAlloc(desc->cItems * sizeof(CRYPT_DER_BLOB));
1197         if (!setOf.rgValue)
1198             ret = FALSE;
1199         else
1200         {
1201             setOf.cValue = desc->cItems;
1202             memset(setOf.rgValue, 0, setOf.cValue * sizeof(CRYPT_DER_BLOB));
1203         }
1204     }
1205     for (i = 0; ret && i < setOf.cValue; i++)
1206     {
1207         ret = desc->encode(dwCertEncodingType, lpszStructType,
1208          (const BYTE *)desc->items + i * desc->itemSize + desc->itemOffset,
1209          0, NULL, NULL, &setOf.rgValue[i].cbData);
1210         if (ret)
1211         {
1212             setOf.rgValue[i].pbData = CryptMemAlloc(setOf.rgValue[i].cbData);
1213             if (!setOf.rgValue[i].pbData)
1214                 ret = FALSE;
1215             else
1216                 ret = desc->encode(dwCertEncodingType, lpszStructType,
1217                  (const BYTE *)desc->items + i * desc->itemSize +
1218                  desc->itemOffset, 0, NULL, setOf.rgValue[i].pbData,
1219                  &setOf.rgValue[i].cbData);
1220         }
1221         /* Some functions propagate their errors through the size */
1222         if (!ret)
1223             *pcbEncoded = setOf.rgValue[i].cbData;
1224     }
1225     if (ret)
1226     {
1227         DWORD bytesNeeded = 0, lenBytes;
1228         BOOL ret;
1229
1230         for (i = 0; i < setOf.cValue; i++)
1231             bytesNeeded += setOf.rgValue[i].cbData;
1232         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1233         bytesNeeded += 1 + lenBytes;
1234         if (!pbEncoded)
1235             *pcbEncoded = bytesNeeded;
1236         else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1237          pbEncoded, pcbEncoded, bytesNeeded)))
1238         {
1239             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1240                 pbEncoded = *(BYTE **)pbEncoded;
1241             qsort(setOf.rgValue, setOf.cValue, sizeof(CRYPT_DER_BLOB),
1242              BLOBComp);
1243             *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1244             CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded, &lenBytes);
1245             pbEncoded += lenBytes;
1246             for (i = 0; i < setOf.cValue; i++)
1247             {
1248                 memcpy(pbEncoded, setOf.rgValue[i].pbData,
1249                  setOf.rgValue[i].cbData);
1250                 pbEncoded += setOf.rgValue[i].cbData;
1251             }
1252         }
1253     }
1254     for (i = 0; i < setOf.cValue; i++)
1255         CryptMemFree(setOf.rgValue[i].pbData);
1256     CryptMemFree(setOf.rgValue);
1257     return ret;
1258 }
1259
1260 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1261  CryptEncodeObjectExFunc nameValueEncodeFunc, BYTE *pbEncoded,
1262  DWORD *pcbEncoded)
1263 {
1264     BOOL ret;
1265     CRYPT_SET_OF setOf = { 0, NULL };
1266
1267     __TRY
1268     {
1269         DWORD i;
1270
1271         ret = TRUE;
1272         if (rdn->cRDNAttr)
1273         {
1274             setOf.cValue = rdn->cRDNAttr;
1275             setOf.rgValue = CryptMemAlloc(rdn->cRDNAttr *
1276              sizeof(CRYPT_DER_BLOB));
1277             if (!setOf.rgValue)
1278                 ret = FALSE;
1279             else
1280                 memset(setOf.rgValue, 0, setOf.cValue * sizeof(CRYPT_DER_BLOB));
1281         }
1282         for (i = 0; ret && i < rdn->cRDNAttr; i++)
1283         {
1284             setOf.rgValue[i].cbData = 0;
1285             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1286              nameValueEncodeFunc, NULL, &setOf.rgValue[i].cbData);
1287             if (ret)
1288             {
1289                 setOf.rgValue[i].pbData =
1290                  CryptMemAlloc(setOf.rgValue[i].cbData);
1291                 if (!setOf.rgValue[i].pbData)
1292                     ret = FALSE;
1293                 else
1294                     ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1295                      &rdn->rgRDNAttr[i], nameValueEncodeFunc,
1296                      setOf.rgValue[i].pbData, &setOf.rgValue[i].cbData);
1297             }
1298             if (!ret)
1299             {
1300                 /* Have to propagate index of failing character */
1301                 *pcbEncoded = setOf.rgValue[i].cbData;
1302             }
1303         }
1304         if (ret)
1305             ret = CRYPT_DEREncodeSet(X509_ASN_ENCODING, NULL, &setOf, 0, NULL,
1306              pbEncoded, pcbEncoded);
1307         for (i = 0; i < setOf.cValue; i++)
1308             CryptMemFree(setOf.rgValue[i].pbData);
1309     }
1310     __EXCEPT_PAGE_FAULT
1311     {
1312         SetLastError(STATUS_ACCESS_VIOLATION);
1313         ret = FALSE;
1314     }
1315     __ENDTRY
1316     CryptMemFree(setOf.rgValue);
1317     return ret;
1318 }
1319
1320 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1321  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1322  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
1323
1324 static BOOL WINAPI CRYPT_AsnEncodeOrCopyUnicodeNameValue(
1325  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
1326  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1327  DWORD *pcbEncoded)
1328 {
1329     const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1330     BOOL ret;
1331
1332     if (value->dwValueType == CERT_RDN_ENCODED_BLOB)
1333         ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL, &value->Value,
1334          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1335     else
1336         ret = CRYPT_AsnEncodeUnicodeNameValue(dwCertEncodingType, NULL, value,
1337          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1338     return ret;
1339 }
1340
1341 static BOOL WINAPI CRYPT_AsnEncodeUnicodeName(DWORD dwCertEncodingType,
1342  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1343  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1344 {
1345     BOOL ret = TRUE;
1346
1347     __TRY
1348     {
1349         const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1350         DWORD bytesNeeded = 0, lenBytes, size, i;
1351
1352         TRACE("encoding name with %d RDNs\n", info->cRDN);
1353         ret = TRUE;
1354         for (i = 0; ret && i < info->cRDN; i++)
1355         {
1356             ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1357              CRYPT_AsnEncodeOrCopyUnicodeNameValue, NULL, &size);
1358             if (ret)
1359                 bytesNeeded += size;
1360             else
1361                 *pcbEncoded = size;
1362         }
1363         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1364         bytesNeeded += 1 + lenBytes;
1365         if (ret)
1366         {
1367             if (!pbEncoded)
1368                 *pcbEncoded = bytesNeeded;
1369             else
1370             {
1371                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1372                  pbEncoded, pcbEncoded, bytesNeeded)))
1373                 {
1374                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1375                         pbEncoded = *(BYTE **)pbEncoded;
1376                     *pbEncoded++ = ASN_SEQUENCEOF;
1377                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1378                      &lenBytes);
1379                     pbEncoded += lenBytes;
1380                     for (i = 0; ret && i < info->cRDN; i++)
1381                     {
1382                         size = bytesNeeded;
1383                         ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1384                          &info->rgRDN[i], CRYPT_AsnEncodeOrCopyUnicodeNameValue,
1385                          pbEncoded, &size);
1386                         if (ret)
1387                         {
1388                             pbEncoded += size;
1389                             bytesNeeded -= size;
1390                         }
1391                         else
1392                             *pcbEncoded = size;
1393                     }
1394                 }
1395             }
1396         }
1397     }
1398     __EXCEPT_PAGE_FAULT
1399     {
1400         SetLastError(STATUS_ACCESS_VIOLATION);
1401         ret = FALSE;
1402     }
1403     __ENDTRY
1404     return ret;
1405 }
1406
1407 static BOOL WINAPI CRYPT_AsnEncodePKCSAttribute(DWORD dwCertEncodingType,
1408  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1409  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1410 {
1411     BOOL ret = FALSE;
1412
1413     __TRY
1414     {
1415         const CRYPT_ATTRIBUTE *attr = (const CRYPT_ATTRIBUTE *)pvStructInfo;
1416
1417         if (!attr->pszObjId)
1418             SetLastError(E_INVALIDARG);
1419         else
1420         {
1421             struct AsnEncodeSequenceItem items[2] = {
1422              { attr->pszObjId, CRYPT_AsnEncodeOid, 0 },
1423              { &attr->cValue, CRYPT_DEREncodeSet, 0 },
1424             };
1425
1426             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1427              sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1428              pcbEncoded);
1429         }
1430     }
1431     __EXCEPT_PAGE_FAULT
1432     {
1433         SetLastError(STATUS_ACCESS_VIOLATION);
1434     }
1435     __ENDTRY
1436     return ret;
1437 }
1438
1439 static BOOL WINAPI CRYPT_AsnEncodePKCSAttributes(DWORD dwCertEncodingType,
1440  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1441  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1442 {
1443     BOOL ret = FALSE;
1444
1445     __TRY
1446     {
1447         const CRYPT_ATTRIBUTES *attributes =
1448          (const CRYPT_ATTRIBUTES *)pvStructInfo;
1449         struct DERSetDescriptor desc = { attributes->cAttr, attributes->rgAttr,
1450          sizeof(CRYPT_ATTRIBUTE), 0, CRYPT_AsnEncodePKCSAttribute };
1451
1452         ret = CRYPT_DEREncodeItemsAsSet(X509_ASN_ENCODING, lpszStructType,
1453          &desc, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1454     }
1455     __EXCEPT_PAGE_FAULT
1456     {
1457         SetLastError(STATUS_ACCESS_VIOLATION);
1458     }
1459     __ENDTRY
1460     return ret;
1461 }
1462
1463 /* Like CRYPT_AsnEncodePKCSContentInfo, but allows the OID to be NULL */
1464 static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfoInternal(
1465  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
1466  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1467  DWORD *pcbEncoded)
1468 {
1469     const CRYPT_CONTENT_INFO *info = (const CRYPT_CONTENT_INFO *)pvStructInfo;
1470     struct AsnEncodeSequenceItem items[2] = {
1471      { info->pszObjId, CRYPT_AsnEncodeOid, 0 },
1472      { NULL, NULL, 0 },
1473     };
1474     struct AsnConstructedItem constructed = { 0 };
1475     DWORD cItem = 1;
1476
1477     if (info->Content.cbData)
1478     {
1479         constructed.tag = 0;
1480         constructed.pvStructInfo = &info->Content;
1481         constructed.encodeFunc = CRYPT_CopyEncodedBlob;
1482         items[cItem].pvStructInfo = &constructed;
1483         items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
1484         cItem++;
1485     }
1486     return CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1487      cItem, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1488 }
1489
1490 BOOL CRYPT_AsnEncodePKCSDigestedData(CRYPT_DIGESTED_DATA *digestedData,
1491  void *pvData, DWORD *pcbData)
1492 {
1493     struct AsnEncodeSequenceItem items[] = {
1494      { &digestedData->version, CRYPT_AsnEncodeInt, 0 },
1495      { &digestedData->DigestAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams,
1496        0 },
1497      { &digestedData->ContentInfo, CRYPT_AsnEncodePKCSContentInfoInternal, 0 },
1498      { &digestedData->hash, CRYPT_AsnEncodeOctets, 0 },
1499     };
1500
1501     return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items,
1502      sizeof(items) / sizeof(items[0]), 0, NULL, pvData, pcbData);
1503 }
1504
1505 static BOOL WINAPI CRYPT_AsnEncodePKCSContentInfo(DWORD dwCertEncodingType,
1506  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1507  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1508 {
1509     BOOL ret = FALSE;
1510
1511     __TRY
1512     {
1513         const CRYPT_CONTENT_INFO *info =
1514          (const CRYPT_CONTENT_INFO *)pvStructInfo;
1515
1516         if (!info->pszObjId)
1517             SetLastError(E_INVALIDARG);
1518         else
1519             ret = CRYPT_AsnEncodePKCSContentInfoInternal(dwCertEncodingType,
1520              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1521              pcbEncoded);
1522     }
1523     __EXCEPT_PAGE_FAULT
1524     {
1525         SetLastError(STATUS_ACCESS_VIOLATION);
1526     }
1527     __ENDTRY
1528     return ret;
1529 }
1530
1531 static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value,
1532  BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1533  DWORD *pcbEncoded)
1534 {
1535     BOOL ret = TRUE;
1536     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1537     DWORD bytesNeeded, lenBytes, encodedLen;
1538
1539     encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1540      lstrlenW(str);
1541     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1542     bytesNeeded = 1 + lenBytes + encodedLen;
1543     if (!pbEncoded)
1544         *pcbEncoded = bytesNeeded;
1545     else
1546     {
1547         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1548          pbEncoded, pcbEncoded, bytesNeeded)))
1549         {
1550             DWORD i;
1551
1552             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1553                 pbEncoded = *(BYTE **)pbEncoded;
1554             *pbEncoded++ = tag;
1555             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1556             pbEncoded += lenBytes;
1557             for (i = 0; i < encodedLen; i++)
1558                 *pbEncoded++ = (BYTE)str[i];
1559         }
1560     }
1561     return ret;
1562 }
1563
1564 static BOOL CRYPT_AsnEncodeNumericString(const CERT_NAME_VALUE *value,
1565  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1566  DWORD *pcbEncoded)
1567 {
1568     BOOL ret = TRUE;
1569     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1570     DWORD bytesNeeded, lenBytes, encodedLen;
1571
1572     encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1573      lstrlenW(str);
1574     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1575     bytesNeeded = 1 + lenBytes + encodedLen;
1576     if (!pbEncoded)
1577         *pcbEncoded = bytesNeeded;
1578     else
1579     {
1580         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1581          pbEncoded, pcbEncoded, bytesNeeded)))
1582         {
1583             DWORD i;
1584
1585             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1586                 pbEncoded = *(BYTE **)pbEncoded;
1587             *pbEncoded++ = ASN_NUMERICSTRING;
1588             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1589             pbEncoded += lenBytes;
1590             for (i = 0; ret && i < encodedLen; i++)
1591             {
1592                 if (isdigitW(str[i]))
1593                     *pbEncoded++ = (BYTE)str[i];
1594                 else
1595                 {
1596                     *pcbEncoded = i;
1597                     SetLastError(CRYPT_E_INVALID_NUMERIC_STRING);
1598                     ret = FALSE;
1599                 }
1600             }
1601         }
1602     }
1603     return ret;
1604 }
1605
1606 static inline int isprintableW(WCHAR wc)
1607 {
1608     return isalnumW(wc) || isspaceW(wc) || wc == '\'' || wc == '(' ||
1609      wc == ')' || wc == '+' || wc == ',' || wc == '-' || wc == '.' ||
1610      wc == '/' || wc == ':' || wc == '=' || wc == '?';
1611 }
1612
1613 static BOOL CRYPT_AsnEncodePrintableString(const CERT_NAME_VALUE *value,
1614  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1615  DWORD *pcbEncoded)
1616 {
1617     BOOL ret = TRUE;
1618     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1619     DWORD bytesNeeded, lenBytes, encodedLen;
1620
1621     encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1622      lstrlenW(str);
1623     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1624     bytesNeeded = 1 + lenBytes + encodedLen;
1625     if (!pbEncoded)
1626         *pcbEncoded = bytesNeeded;
1627     else
1628     {
1629         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1630          pbEncoded, pcbEncoded, bytesNeeded)))
1631         {
1632             DWORD i;
1633
1634             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1635                 pbEncoded = *(BYTE **)pbEncoded;
1636             *pbEncoded++ = ASN_PRINTABLESTRING;
1637             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1638             pbEncoded += lenBytes;
1639             for (i = 0; ret && i < encodedLen; i++)
1640             {
1641                 if (isprintableW(str[i]))
1642                     *pbEncoded++ = (BYTE)str[i];
1643                 else
1644                 {
1645                     *pcbEncoded = i;
1646                     SetLastError(CRYPT_E_INVALID_PRINTABLE_STRING);
1647                     ret = FALSE;
1648                 }
1649             }
1650         }
1651     }
1652     return ret;
1653 }
1654
1655 static BOOL CRYPT_AsnEncodeIA5String(const CERT_NAME_VALUE *value,
1656  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1657  DWORD *pcbEncoded)
1658 {
1659     BOOL ret = TRUE;
1660     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1661     DWORD bytesNeeded, lenBytes, encodedLen;
1662
1663     encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1664      lstrlenW(str);
1665     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1666     bytesNeeded = 1 + lenBytes + encodedLen;
1667     if (!pbEncoded)
1668         *pcbEncoded = bytesNeeded;
1669     else
1670     {
1671         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1672          pbEncoded, pcbEncoded, bytesNeeded)))
1673         {
1674             DWORD i;
1675
1676             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1677                 pbEncoded = *(BYTE **)pbEncoded;
1678             *pbEncoded++ = ASN_IA5STRING;
1679             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1680             pbEncoded += lenBytes;
1681             for (i = 0; ret && i < encodedLen; i++)
1682             {
1683                 if (str[i] <= 0x7f)
1684                     *pbEncoded++ = (BYTE)str[i];
1685                 else
1686                 {
1687                     *pcbEncoded = i;
1688                     SetLastError(CRYPT_E_INVALID_IA5_STRING);
1689                     ret = FALSE;
1690                 }
1691             }
1692         }
1693     }
1694     return ret;
1695 }
1696
1697 static BOOL CRYPT_AsnEncodeUniversalString(const CERT_NAME_VALUE *value,
1698  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1699  DWORD *pcbEncoded)
1700 {
1701     BOOL ret = TRUE;
1702     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1703     DWORD bytesNeeded, lenBytes, strLen;
1704
1705     /* FIXME: doesn't handle composite characters */
1706     strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1707      lstrlenW(str);
1708     CRYPT_EncodeLen(strLen * 4, NULL, &lenBytes);
1709     bytesNeeded = 1 + lenBytes + strLen * 4;
1710     if (!pbEncoded)
1711         *pcbEncoded = bytesNeeded;
1712     else
1713     {
1714         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1715          pbEncoded, pcbEncoded, bytesNeeded)))
1716         {
1717             DWORD i;
1718
1719             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1720                 pbEncoded = *(BYTE **)pbEncoded;
1721             *pbEncoded++ = ASN_UNIVERSALSTRING;
1722             CRYPT_EncodeLen(strLen * 4, pbEncoded, &lenBytes);
1723             pbEncoded += lenBytes;
1724             for (i = 0; i < strLen; i++)
1725             {
1726                 *pbEncoded++ = 0;
1727                 *pbEncoded++ = 0;
1728                 *pbEncoded++ = (BYTE)((str[i] & 0xff00) >> 8);
1729                 *pbEncoded++ = (BYTE)(str[i] & 0x00ff);
1730             }
1731         }
1732     }
1733     return ret;
1734 }
1735
1736 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1737  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1738  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1739 {
1740     BOOL ret = FALSE;
1741
1742     __TRY
1743     {
1744         const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1745
1746         switch (value->dwValueType)
1747         {
1748         case CERT_RDN_ANY_TYPE:
1749         case CERT_RDN_ENCODED_BLOB:
1750         case CERT_RDN_OCTET_STRING:
1751             SetLastError(CRYPT_E_NOT_CHAR_STRING);
1752             break;
1753         case CERT_RDN_NUMERIC_STRING:
1754             ret = CRYPT_AsnEncodeNumericString(value, dwFlags, pEncodePara,
1755              pbEncoded, pcbEncoded);
1756             break;
1757         case CERT_RDN_PRINTABLE_STRING:
1758             ret = CRYPT_AsnEncodePrintableString(value, dwFlags, pEncodePara,
1759              pbEncoded, pcbEncoded);
1760             break;
1761         case CERT_RDN_TELETEX_STRING:
1762             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_T61STRING,
1763              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1764             break;
1765         case CERT_RDN_VIDEOTEX_STRING:
1766             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value,
1767              ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1768             break;
1769         case CERT_RDN_IA5_STRING:
1770             ret = CRYPT_AsnEncodeIA5String(value, dwFlags, pEncodePara,
1771              pbEncoded, pcbEncoded);
1772             break;
1773         case CERT_RDN_GRAPHIC_STRING:
1774             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GRAPHICSTRING,
1775              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1776             break;
1777         case CERT_RDN_VISIBLE_STRING:
1778             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_VISIBLESTRING,
1779              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1780             break;
1781         case CERT_RDN_GENERAL_STRING:
1782             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GENERALSTRING,
1783              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1784             break;
1785         case CERT_RDN_UNIVERSAL_STRING:
1786             ret = CRYPT_AsnEncodeUniversalString(value, dwFlags, pEncodePara,
1787              pbEncoded, pcbEncoded);
1788             break;
1789         case CERT_RDN_BMP_STRING:
1790             ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
1791              pbEncoded, pcbEncoded);
1792             break;
1793         case CERT_RDN_UTF8_STRING:
1794             ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
1795              pbEncoded, pcbEncoded);
1796             break;
1797         default:
1798             SetLastError(CRYPT_E_ASN1_CHOICE);
1799         }
1800     }
1801     __EXCEPT_PAGE_FAULT
1802     {
1803         SetLastError(STATUS_ACCESS_VIOLATION);
1804     }
1805     __ENDTRY
1806     return ret;
1807 }
1808
1809 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1810  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1811  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1812 {
1813     BOOL ret;
1814
1815     __TRY
1816     {
1817         const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1818         DWORD bytesNeeded = 0, lenBytes, size, i;
1819
1820         TRACE("encoding name with %d RDNs\n", info->cRDN);
1821         ret = TRUE;
1822         for (i = 0; ret && i < info->cRDN; i++)
1823         {
1824             ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1825              CRYPT_AsnEncodeNameValue, NULL, &size);
1826             if (ret)
1827                 bytesNeeded += size;
1828         }
1829         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1830         bytesNeeded += 1 + lenBytes;
1831         if (ret)
1832         {
1833             if (!pbEncoded)
1834                 *pcbEncoded = bytesNeeded;
1835             else
1836             {
1837                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1838                  pbEncoded, pcbEncoded, bytesNeeded)))
1839                 {
1840                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1841                         pbEncoded = *(BYTE **)pbEncoded;
1842                     *pbEncoded++ = ASN_SEQUENCEOF;
1843                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1844                      &lenBytes);
1845                     pbEncoded += lenBytes;
1846                     for (i = 0; ret && i < info->cRDN; i++)
1847                     {
1848                         size = bytesNeeded;
1849                         ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1850                          &info->rgRDN[i], CRYPT_AsnEncodeNameValue, pbEncoded,
1851                          &size);
1852                         if (ret)
1853                         {
1854                             pbEncoded += size;
1855                             bytesNeeded -= size;
1856                         }
1857                     }
1858                 }
1859             }
1860         }
1861     }
1862     __EXCEPT_PAGE_FAULT
1863     {
1864         SetLastError(STATUS_ACCESS_VIOLATION);
1865         ret = FALSE;
1866     }
1867     __ENDTRY
1868     return ret;
1869 }
1870
1871 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1872  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1873  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1874 {
1875     BOOL val = *(const BOOL *)pvStructInfo, ret;
1876
1877     TRACE("%d\n", val);
1878
1879     if (!pbEncoded)
1880     {
1881         *pcbEncoded = 3;
1882         ret = TRUE;
1883     }
1884     else if (*pcbEncoded < 3)
1885     {
1886         *pcbEncoded = 3;
1887         SetLastError(ERROR_MORE_DATA);
1888         ret = FALSE;
1889     }
1890     else
1891     {
1892         *pcbEncoded = 3;
1893         *pbEncoded++ = ASN_BOOL;
1894         *pbEncoded++ = 1;
1895         *pbEncoded++ = val ? 0xff : 0;
1896         ret = TRUE;
1897     }
1898     TRACE("returning %d (%08x)\n", ret, GetLastError());
1899     return ret;
1900 }
1901
1902 static BOOL WINAPI CRYPT_AsnEncodeAltNameEntry(DWORD dwCertEncodingType,
1903  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1904  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1905 {
1906     const CERT_ALT_NAME_ENTRY *entry =
1907      (const CERT_ALT_NAME_ENTRY *)pvStructInfo;
1908     BOOL ret;
1909     DWORD dataLen;
1910     BYTE tag;
1911
1912     ret = TRUE;
1913     switch (entry->dwAltNameChoice)
1914     {
1915     case CERT_ALT_NAME_RFC822_NAME:
1916     case CERT_ALT_NAME_DNS_NAME:
1917     case CERT_ALT_NAME_URL:
1918         tag = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1919         if (entry->u.pwszURL)
1920         {
1921             DWORD i;
1922
1923             /* Not + 1: don't encode the NULL-terminator */
1924             dataLen = lstrlenW(entry->u.pwszURL);
1925             for (i = 0; ret && i < dataLen; i++)
1926             {
1927                 if (entry->u.pwszURL[i] > 0x7f)
1928                 {
1929                     SetLastError(CRYPT_E_INVALID_IA5_STRING);
1930                     ret = FALSE;
1931                     *pcbEncoded = i;
1932                 }
1933             }
1934         }
1935         else
1936             dataLen = 0;
1937         break;
1938     case CERT_ALT_NAME_DIRECTORY_NAME:
1939         tag = ASN_CONTEXT | ASN_CONSTRUCTOR | (entry->dwAltNameChoice - 1);
1940         dataLen = entry->u.DirectoryName.cbData;
1941         break;
1942     case CERT_ALT_NAME_IP_ADDRESS:
1943         tag = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1944         dataLen = entry->u.IPAddress.cbData;
1945         break;
1946     case CERT_ALT_NAME_REGISTERED_ID:
1947     {
1948         struct AsnEncodeTagSwappedItem swapped =
1949          { ASN_CONTEXT | (entry->dwAltNameChoice - 1), entry->u.pszRegisteredID,
1950            CRYPT_AsnEncodeOid };
1951
1952         return CRYPT_AsnEncodeSwapTag(0, NULL, &swapped, 0, NULL, pbEncoded,
1953          pcbEncoded);
1954     }
1955     case CERT_ALT_NAME_OTHER_NAME:
1956         FIXME("name type %d unimplemented\n", entry->dwAltNameChoice);
1957         return FALSE;
1958     default:
1959         SetLastError(E_INVALIDARG);
1960         return FALSE;
1961     }
1962     if (ret)
1963     {
1964         DWORD bytesNeeded, lenBytes;
1965
1966         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1967         bytesNeeded = 1 + dataLen + lenBytes;
1968         if (!pbEncoded)
1969             *pcbEncoded = bytesNeeded;
1970         else if (*pcbEncoded < bytesNeeded)
1971         {
1972             SetLastError(ERROR_MORE_DATA);
1973             *pcbEncoded = bytesNeeded;
1974             ret = FALSE;
1975         }
1976         else
1977         {
1978             *pbEncoded++ = tag;
1979             CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1980             pbEncoded += lenBytes;
1981             switch (entry->dwAltNameChoice)
1982             {
1983             case CERT_ALT_NAME_RFC822_NAME:
1984             case CERT_ALT_NAME_DNS_NAME:
1985             case CERT_ALT_NAME_URL:
1986             {
1987                 DWORD i;
1988
1989                 for (i = 0; i < dataLen; i++)
1990                     *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1991                 break;
1992             }
1993             case CERT_ALT_NAME_DIRECTORY_NAME:
1994                 memcpy(pbEncoded, entry->u.DirectoryName.pbData, dataLen);
1995                 break;
1996             case CERT_ALT_NAME_IP_ADDRESS:
1997                 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1998                 break;
1999             }
2000             if (ret)
2001                 *pcbEncoded = bytesNeeded;
2002         }
2003     }
2004     TRACE("returning %d (%08x)\n", ret, GetLastError());
2005     return ret;
2006 }
2007
2008 static BOOL WINAPI CRYPT_AsnEncodeIntegerSwapBytes(DWORD dwCertEncodingType,
2009  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2010  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2011 {
2012     BOOL ret;
2013
2014     __TRY
2015     {
2016         const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
2017         CRYPT_DATA_BLOB newBlob = { blob->cbData, NULL };
2018
2019         ret = TRUE;
2020         if (newBlob.cbData)
2021         {
2022             newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2023             if (newBlob.pbData)
2024             {
2025                 DWORD i;
2026
2027                 for (i = 0; i < newBlob.cbData; i++)
2028                     newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2029             }
2030             else
2031                 ret = FALSE;
2032         }
2033         if (ret)
2034             ret = CRYPT_AsnEncodeInteger(dwCertEncodingType, lpszStructType,
2035              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2036         CryptMemFree(newBlob.pbData);
2037     }
2038     __EXCEPT_PAGE_FAULT
2039     {
2040         SetLastError(STATUS_ACCESS_VIOLATION);
2041         ret = FALSE;
2042     }
2043     __ENDTRY
2044     return ret;
2045 }
2046
2047 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType,
2048  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2049  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2050 {
2051     BOOL ret;
2052
2053     __TRY
2054     {
2055         const CERT_AUTHORITY_KEY_ID_INFO *info =
2056          (const CERT_AUTHORITY_KEY_ID_INFO *)pvStructInfo;
2057         struct AsnEncodeSequenceItem items[3] = { { 0 } };
2058         struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2059         struct AsnConstructedItem constructed = { 0 };
2060         DWORD cItem = 0, cSwapped = 0;
2061
2062         if (info->KeyId.cbData)
2063         {
2064             swapped[cSwapped].tag = ASN_CONTEXT | 0;
2065             swapped[cSwapped].pvStructInfo = &info->KeyId;
2066             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeIntegerSwapBytes;
2067             items[cItem].pvStructInfo = &swapped[cSwapped];
2068             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2069             cSwapped++;
2070             cItem++;
2071         }
2072         if (info->CertIssuer.cbData)
2073         {
2074             constructed.tag = 1;
2075             constructed.pvStructInfo = &info->CertIssuer;
2076             constructed.encodeFunc = CRYPT_CopyEncodedBlob;
2077             items[cItem].pvStructInfo = &constructed;
2078             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2079             cItem++;
2080         }
2081         if (info->CertSerialNumber.cbData)
2082         {
2083             swapped[cSwapped].tag = ASN_CONTEXT | 2;
2084             swapped[cSwapped].pvStructInfo = &info->CertSerialNumber;
2085             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
2086             items[cItem].pvStructInfo = &swapped[cSwapped];
2087             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2088             cSwapped++;
2089             cItem++;
2090         }
2091         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
2092          pEncodePara, pbEncoded, pcbEncoded);
2093     }
2094     __EXCEPT_PAGE_FAULT
2095     {
2096         SetLastError(STATUS_ACCESS_VIOLATION);
2097         ret = FALSE;
2098     }
2099     __ENDTRY
2100     return ret;
2101 }
2102
2103 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
2104  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2105  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2106 {
2107     BOOL ret;
2108
2109     __TRY
2110     {
2111         const CERT_ALT_NAME_INFO *info =
2112          (const CERT_ALT_NAME_INFO *)pvStructInfo;
2113         DWORD bytesNeeded, dataLen, lenBytes, i;
2114
2115         ret = TRUE;
2116         /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
2117          * can't encode an erroneous entry index if it's bigger than this.
2118          */
2119         for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
2120         {
2121             DWORD len;
2122
2123             ret = CRYPT_AsnEncodeAltNameEntry(dwCertEncodingType, NULL,
2124              &info->rgAltEntry[i], 0, NULL, NULL, &len);
2125             if (ret)
2126                 dataLen += len;
2127             else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2128             {
2129                 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
2130                  * the bad character, now set the index of the bad
2131                  * entry
2132                  */
2133                 *pcbEncoded = (BYTE)i <<
2134                  CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
2135             }
2136         }
2137         if (ret)
2138         {
2139             CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2140             bytesNeeded = 1 + lenBytes + dataLen;
2141             if (!pbEncoded)
2142             {
2143                 *pcbEncoded = bytesNeeded;
2144                 ret = TRUE;
2145             }
2146             else
2147             {
2148                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2149                  pbEncoded, pcbEncoded, bytesNeeded)))
2150                 {
2151                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2152                         pbEncoded = *(BYTE **)pbEncoded;
2153                     *pbEncoded++ = ASN_SEQUENCEOF;
2154                     CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2155                     pbEncoded += lenBytes;
2156                     for (i = 0; ret && i < info->cAltEntry; i++)
2157                     {
2158                         DWORD len = dataLen;
2159
2160                         ret = CRYPT_AsnEncodeAltNameEntry(dwCertEncodingType,
2161                          NULL, &info->rgAltEntry[i], 0, NULL, pbEncoded, &len);
2162                         if (ret)
2163                         {
2164                             pbEncoded += len;
2165                             dataLen -= len;
2166                         }
2167                     }
2168                 }
2169             }
2170         }
2171     }
2172     __EXCEPT_PAGE_FAULT
2173     {
2174         SetLastError(STATUS_ACCESS_VIOLATION);
2175         ret = FALSE;
2176     }
2177     __ENDTRY
2178     return ret;
2179 }
2180
2181 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId2(DWORD dwCertEncodingType,
2182  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2183  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2184 {
2185     BOOL ret;
2186
2187     __TRY
2188     {
2189         const CERT_AUTHORITY_KEY_ID2_INFO *info =
2190          (const CERT_AUTHORITY_KEY_ID2_INFO *)pvStructInfo;
2191         struct AsnEncodeSequenceItem items[3] = { { 0 } };
2192         struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2193         DWORD cItem = 0, cSwapped = 0;
2194
2195         if (info->KeyId.cbData)
2196         {
2197             swapped[cSwapped].tag = ASN_CONTEXT | 0;
2198             swapped[cSwapped].pvStructInfo = &info->KeyId;
2199             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeIntegerSwapBytes;
2200             items[cItem].pvStructInfo = &swapped[cSwapped];
2201             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2202             cSwapped++;
2203             cItem++;
2204         }
2205         if (info->AuthorityCertIssuer.cAltEntry)
2206         {
2207             swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
2208             swapped[cSwapped].pvStructInfo = &info->AuthorityCertIssuer;
2209             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2210             items[cItem].pvStructInfo = &swapped[cSwapped];
2211             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2212             cSwapped++;
2213             cItem++;
2214         }
2215         if (info->AuthorityCertSerialNumber.cbData)
2216         {
2217             swapped[cSwapped].tag = ASN_CONTEXT | 2;
2218             swapped[cSwapped].pvStructInfo = &info->AuthorityCertSerialNumber;
2219             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
2220             items[cItem].pvStructInfo = &swapped[cSwapped];
2221             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2222             cSwapped++;
2223             cItem++;
2224         }
2225         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
2226          pEncodePara, pbEncoded, pcbEncoded);
2227     }
2228     __EXCEPT_PAGE_FAULT
2229     {
2230         SetLastError(STATUS_ACCESS_VIOLATION);
2231         ret = FALSE;
2232     }
2233     __ENDTRY
2234     return ret;
2235 }
2236
2237 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
2238  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2239  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2240 {
2241     BOOL ret;
2242
2243     __TRY
2244     {
2245         const CERT_BASIC_CONSTRAINTS_INFO *info =
2246          (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
2247         struct AsnEncodeSequenceItem items[3] = {
2248          { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
2249          { 0 }
2250         };
2251         DWORD cItem = 1;
2252
2253         if (info->fPathLenConstraint)
2254         {
2255             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2256             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2257             cItem++;
2258         }
2259         if (info->cSubtreesConstraint)
2260         {
2261             items[cItem].pvStructInfo = &info->cSubtreesConstraint;
2262             items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2263             cItem++;
2264         }
2265         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2266          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2267     }
2268     __EXCEPT_PAGE_FAULT
2269     {
2270         SetLastError(STATUS_ACCESS_VIOLATION);
2271         ret = FALSE;
2272     }
2273     __ENDTRY
2274     return ret;
2275 }
2276
2277 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
2278  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2279  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2280 {
2281     BOOL ret;
2282
2283     __TRY
2284     {
2285         const CERT_BASIC_CONSTRAINTS2_INFO *info =
2286          (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
2287         struct AsnEncodeSequenceItem items[2] = { { 0 } };
2288         DWORD cItem = 0;
2289
2290         if (info->fCA)
2291         {
2292             items[cItem].pvStructInfo = &info->fCA;
2293             items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
2294             cItem++;
2295         }
2296         if (info->fPathLenConstraint)
2297         {
2298             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2299             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2300             cItem++;
2301         }
2302         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2303          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2304     }
2305     __EXCEPT_PAGE_FAULT
2306     {
2307         SetLastError(STATUS_ACCESS_VIOLATION);
2308         ret = FALSE;
2309     }
2310     __ENDTRY
2311     return ret;
2312 }
2313
2314 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
2315  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2316  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2317 {
2318     BOOL ret;
2319
2320     __TRY
2321     {
2322         const BLOBHEADER *hdr =
2323          (const BLOBHEADER *)pvStructInfo;
2324
2325         if (hdr->bType != PUBLICKEYBLOB)
2326         {
2327             SetLastError(E_INVALIDARG);
2328             ret = FALSE;
2329         }
2330         else
2331         {
2332             const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
2333              ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
2334             CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
2335              (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
2336             struct AsnEncodeSequenceItem items[] = { 
2337              { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
2338              { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
2339             };
2340
2341             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
2342              sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
2343              pcbEncoded);
2344         }
2345     }
2346     __EXCEPT_PAGE_FAULT
2347     {
2348         SetLastError(STATUS_ACCESS_VIOLATION);
2349         ret = FALSE;
2350     }
2351     __ENDTRY
2352     return ret;
2353 }
2354
2355 BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
2356  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2357  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2358 {
2359     BOOL ret;
2360
2361     __TRY
2362     {
2363         const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
2364         DWORD bytesNeeded, lenBytes;
2365
2366         TRACE("(%d, %p), %08x, %p, %p, %d\n", blob->cbData, blob->pbData,
2367          dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
2368
2369         CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
2370         bytesNeeded = 1 + lenBytes + blob->cbData;
2371         if (!pbEncoded)
2372         {
2373             *pcbEncoded = bytesNeeded;
2374             ret = TRUE;
2375         }
2376         else
2377         {
2378             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2379              pcbEncoded, bytesNeeded)))
2380             {
2381                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2382                     pbEncoded = *(BYTE **)pbEncoded;
2383                 *pbEncoded++ = ASN_OCTETSTRING;
2384                 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
2385                 pbEncoded += lenBytes;
2386                 if (blob->cbData)
2387                     memcpy(pbEncoded, blob->pbData, blob->cbData);
2388             }
2389         }
2390     }
2391     __EXCEPT_PAGE_FAULT
2392     {
2393         SetLastError(STATUS_ACCESS_VIOLATION);
2394         ret = FALSE;
2395     }
2396     __ENDTRY
2397     TRACE("returning %d (%08x)\n", ret, GetLastError());
2398     return ret;
2399 }
2400
2401 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
2402  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2403  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2404 {
2405     BOOL ret;
2406
2407     __TRY
2408     {
2409         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2410         DWORD bytesNeeded, lenBytes, dataBytes;
2411         BYTE unusedBits;
2412
2413         /* yep, MS allows cUnusedBits to be >= 8 */
2414         if (!blob->cUnusedBits)
2415         {
2416             dataBytes = blob->cbData;
2417             unusedBits = 0;
2418         }
2419         else if (blob->cbData * 8 > blob->cUnusedBits)
2420         {
2421             dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
2422             unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
2423              blob->cUnusedBits;
2424         }
2425         else
2426         {
2427             dataBytes = 0;
2428             unusedBits = 0;
2429         }
2430         CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
2431         bytesNeeded = 1 + lenBytes + dataBytes + 1;
2432         if (!pbEncoded)
2433         {
2434             *pcbEncoded = bytesNeeded;
2435             ret = TRUE;
2436         }
2437         else
2438         {
2439             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2440              pcbEncoded, bytesNeeded)))
2441             {
2442                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2443                     pbEncoded = *(BYTE **)pbEncoded;
2444                 *pbEncoded++ = ASN_BITSTRING;
2445                 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
2446                 pbEncoded += lenBytes;
2447                 *pbEncoded++ = unusedBits;
2448                 if (dataBytes)
2449                 {
2450                     BYTE mask = 0xff << unusedBits;
2451
2452                     if (dataBytes > 1)
2453                     {
2454                         memcpy(pbEncoded, blob->pbData, dataBytes - 1);
2455                         pbEncoded += dataBytes - 1;
2456                     }
2457                     *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
2458                 }
2459             }
2460         }
2461     }
2462     __EXCEPT_PAGE_FAULT
2463     {
2464         SetLastError(STATUS_ACCESS_VIOLATION);
2465         ret = FALSE;
2466     }
2467     __ENDTRY
2468     return ret;
2469 }
2470
2471 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
2472  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2473  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2474 {
2475     BOOL ret;
2476
2477     __TRY
2478     {
2479         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2480         CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
2481
2482         ret = TRUE;
2483         if (newBlob.cbData)
2484         {
2485             newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2486             if (newBlob.pbData)
2487             {
2488                 DWORD i;
2489
2490                 for (i = 0; i < newBlob.cbData; i++)
2491                     newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2492             }
2493             else
2494                 ret = FALSE;
2495         }
2496         if (ret)
2497             ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
2498              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2499         CryptMemFree(newBlob.pbData);
2500     }
2501     __EXCEPT_PAGE_FAULT
2502     {
2503         SetLastError(STATUS_ACCESS_VIOLATION);
2504         ret = FALSE;
2505     }
2506     __ENDTRY
2507     return ret;
2508 }
2509
2510 BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
2511  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2512  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2513 {
2514     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
2515
2516     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
2517      &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2518 }
2519
2520 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
2521  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2522  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2523 {
2524     BOOL ret;
2525
2526     __TRY
2527     {
2528         DWORD significantBytes, lenBytes;
2529         BYTE padByte = 0, bytesNeeded;
2530         BOOL pad = FALSE;
2531         const CRYPT_INTEGER_BLOB *blob =
2532          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2533
2534         significantBytes = blob->cbData;
2535         if (significantBytes)
2536         {
2537             if (blob->pbData[significantBytes - 1] & 0x80)
2538             {
2539                 /* negative, lop off leading (little-endian) 0xffs */
2540                 for (; significantBytes > 0 &&
2541                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
2542                     ;
2543                 if (blob->pbData[significantBytes - 1] < 0x80)
2544                 {
2545                     padByte = 0xff;
2546                     pad = TRUE;
2547                 }
2548             }
2549             else
2550             {
2551                 /* positive, lop off leading (little-endian) zeroes */
2552                 for (; significantBytes > 0 &&
2553                  !blob->pbData[significantBytes - 1]; significantBytes--)
2554                     ;
2555                 if (significantBytes == 0)
2556                     significantBytes = 1;
2557                 if (blob->pbData[significantBytes - 1] > 0x7f)
2558                 {
2559                     padByte = 0;
2560                     pad = TRUE;
2561                 }
2562             }
2563         }
2564         if (pad)
2565             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2566         else
2567             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2568         bytesNeeded = 1 + lenBytes + significantBytes;
2569         if (pad)
2570             bytesNeeded++;
2571         if (!pbEncoded)
2572         {
2573             *pcbEncoded = bytesNeeded;
2574             ret = TRUE;
2575         }
2576         else
2577         {
2578             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2579              pcbEncoded, bytesNeeded)))
2580             {
2581                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2582                     pbEncoded = *(BYTE **)pbEncoded;
2583                 *pbEncoded++ = ASN_INTEGER;
2584                 if (pad)
2585                 {
2586                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2587                     pbEncoded += lenBytes;
2588                     *pbEncoded++ = padByte;
2589                 }
2590                 else
2591                 {
2592                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2593                     pbEncoded += lenBytes;
2594                 }
2595                 for (; significantBytes > 0; significantBytes--)
2596                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
2597             }
2598         }
2599     }
2600     __EXCEPT_PAGE_FAULT
2601     {
2602         SetLastError(STATUS_ACCESS_VIOLATION);
2603         ret = FALSE;
2604     }
2605     __ENDTRY
2606     return ret;
2607 }
2608
2609 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
2610  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2611  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2612 {
2613     BOOL ret;
2614
2615     __TRY
2616     {
2617         DWORD significantBytes, lenBytes;
2618         BYTE bytesNeeded;
2619         BOOL pad = FALSE;
2620         const CRYPT_INTEGER_BLOB *blob =
2621          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2622
2623         significantBytes = blob->cbData;
2624         if (significantBytes)
2625         {
2626             /* positive, lop off leading (little-endian) zeroes */
2627             for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2628              significantBytes--)
2629                 ;
2630             if (significantBytes == 0)
2631                 significantBytes = 1;
2632             if (blob->pbData[significantBytes - 1] > 0x7f)
2633                 pad = TRUE;
2634         }
2635         if (pad)
2636             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2637         else
2638             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2639         bytesNeeded = 1 + lenBytes + significantBytes;
2640         if (pad)
2641             bytesNeeded++;
2642         if (!pbEncoded)
2643         {
2644             *pcbEncoded = bytesNeeded;
2645             ret = TRUE;
2646         }
2647         else
2648         {
2649             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2650              pcbEncoded, bytesNeeded)))
2651             {
2652                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2653                     pbEncoded = *(BYTE **)pbEncoded;
2654                 *pbEncoded++ = ASN_INTEGER;
2655                 if (pad)
2656                 {
2657                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2658                     pbEncoded += lenBytes;
2659                     *pbEncoded++ = 0;
2660                 }
2661                 else
2662                 {
2663                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2664                     pbEncoded += lenBytes;
2665                 }
2666                 for (; significantBytes > 0; significantBytes--)
2667                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
2668             }
2669         }
2670     }
2671     __EXCEPT_PAGE_FAULT
2672     {
2673         SetLastError(STATUS_ACCESS_VIOLATION);
2674         ret = FALSE;
2675     }
2676     __ENDTRY
2677     return ret;
2678 }
2679
2680 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2681  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2682  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2683 {
2684     CRYPT_INTEGER_BLOB blob;
2685     BOOL ret;
2686
2687     /* Encode as an unsigned integer, then change the tag to enumerated */
2688     blob.cbData = sizeof(DWORD);
2689     blob.pbData = (BYTE *)pvStructInfo;
2690     ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2691      X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2692     if (ret && pbEncoded)
2693     {
2694         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2695             pbEncoded = *(BYTE **)pbEncoded;
2696         pbEncoded[0] = ASN_ENUMERATED;
2697     }
2698     return ret;
2699 }
2700
2701 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2702  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2703  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2704 {
2705     BOOL ret;
2706
2707     __TRY
2708     {
2709         SYSTEMTIME sysTime;
2710         /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
2711          * temporary buffer because the output buffer is not NULL-terminated.
2712          */
2713         char buf[16];
2714         static const DWORD bytesNeeded = sizeof(buf) - 1;
2715
2716         if (!pbEncoded)
2717         {
2718             *pcbEncoded = bytesNeeded;
2719             ret = TRUE;
2720         }
2721         else
2722         {
2723             /* Sanity check the year, this is a two-digit year format */
2724             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2725              &sysTime);
2726             if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2727             {
2728                 SetLastError(CRYPT_E_BAD_ENCODE);
2729                 ret = FALSE;
2730             }
2731             if (ret)
2732             {
2733                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2734                  pbEncoded, pcbEncoded, bytesNeeded)))
2735                 {
2736                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2737                         pbEncoded = *(BYTE **)pbEncoded;
2738                     buf[0] = ASN_UTCTIME;
2739                     buf[1] = bytesNeeded - 2;
2740                     snprintf(buf + 2, sizeof(buf) - 2,
2741                      "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2742                      sysTime.wYear - 2000 : sysTime.wYear - 1900,
2743                      sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2744                      sysTime.wMinute, sysTime.wSecond);
2745                     memcpy(pbEncoded, buf, bytesNeeded);
2746                 }
2747             }
2748         }
2749     }
2750     __EXCEPT_PAGE_FAULT
2751     {
2752         SetLastError(STATUS_ACCESS_VIOLATION);
2753         ret = FALSE;
2754     }
2755     __ENDTRY
2756     return ret;
2757 }
2758
2759 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2760  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2761  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2762 {
2763     BOOL ret;
2764
2765     __TRY
2766     {
2767         SYSTEMTIME sysTime;
2768         /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
2769          * temporary buffer because the output buffer is not NULL-terminated.
2770          */
2771         char buf[18];
2772         static const DWORD bytesNeeded = sizeof(buf) - 1;
2773
2774         if (!pbEncoded)
2775         {
2776             *pcbEncoded = bytesNeeded;
2777             ret = TRUE;
2778         }
2779         else
2780         {
2781             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2782              &sysTime);
2783             if (ret)
2784                 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2785                  pcbEncoded, bytesNeeded);
2786             if (ret)
2787             {
2788                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2789                     pbEncoded = *(BYTE **)pbEncoded;
2790                 buf[0] = ASN_GENERALTIME;
2791                 buf[1] = bytesNeeded - 2;
2792                 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2793                  sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2794                  sysTime.wMinute, sysTime.wSecond);
2795                 memcpy(pbEncoded, buf, bytesNeeded);
2796             }
2797         }
2798     }
2799     __EXCEPT_PAGE_FAULT
2800     {
2801         SetLastError(STATUS_ACCESS_VIOLATION);
2802         ret = FALSE;
2803     }
2804     __ENDTRY
2805     return ret;
2806 }
2807
2808 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2809  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2810  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2811 {
2812     BOOL ret;
2813
2814     __TRY
2815     {
2816         SYSTEMTIME sysTime;
2817
2818         /* Check the year, if it's in the UTCTime range call that encode func */
2819         if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2820             return FALSE;
2821         if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2822             ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2823              pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2824         else
2825             ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2826              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2827              pcbEncoded);
2828     }
2829     __EXCEPT_PAGE_FAULT
2830     {
2831         SetLastError(STATUS_ACCESS_VIOLATION);
2832         ret = FALSE;
2833     }
2834     __ENDTRY
2835     return ret;
2836 }
2837
2838 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2839  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2840  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2841 {
2842     BOOL ret;
2843
2844     __TRY
2845     {
2846         DWORD bytesNeeded, dataLen, lenBytes, i;
2847         const CRYPT_SEQUENCE_OF_ANY *seq =
2848          (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2849
2850         for (i = 0, dataLen = 0; i < seq->cValue; i++)
2851             dataLen += seq->rgValue[i].cbData;
2852         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2853         bytesNeeded = 1 + lenBytes + dataLen;
2854         if (!pbEncoded)
2855         {
2856             *pcbEncoded = bytesNeeded;
2857             ret = TRUE;
2858         }
2859         else
2860         {
2861             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2862              pcbEncoded, bytesNeeded)))
2863             {
2864                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2865                     pbEncoded = *(BYTE **)pbEncoded;
2866                 *pbEncoded++ = ASN_SEQUENCEOF;
2867                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2868                 pbEncoded += lenBytes;
2869                 for (i = 0; i < seq->cValue; i++)
2870                 {
2871                     memcpy(pbEncoded, seq->rgValue[i].pbData,
2872                      seq->rgValue[i].cbData);
2873                     pbEncoded += seq->rgValue[i].cbData;
2874                 }
2875             }
2876         }
2877     }
2878     __EXCEPT_PAGE_FAULT
2879     {
2880         SetLastError(STATUS_ACCESS_VIOLATION);
2881         ret = FALSE;
2882     }
2883     __ENDTRY
2884     return ret;
2885 }
2886
2887 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2888  BYTE *pbEncoded, DWORD *pcbEncoded)
2889 {
2890     BOOL ret = TRUE;
2891     struct AsnEncodeSequenceItem items[3] = { { 0 } };
2892     struct AsnConstructedItem constructed = { 0 };
2893     struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2894     DWORD cItem = 0, cSwapped = 0;
2895
2896     switch (distPoint->DistPointName.dwDistPointNameChoice)
2897     {
2898     case CRL_DIST_POINT_NO_NAME:
2899         /* do nothing */
2900         break;
2901     case CRL_DIST_POINT_FULL_NAME:
2902         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2903         swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2904         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2905         constructed.tag = 0;
2906         constructed.pvStructInfo = &swapped[cSwapped];
2907         constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2908         items[cItem].pvStructInfo = &constructed;
2909         items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2910         cSwapped++;
2911         cItem++;
2912         break;
2913     case CRL_DIST_POINT_ISSUER_RDN_NAME:
2914         FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2915         ret = FALSE;
2916         break;
2917     default:
2918         ret = FALSE;
2919     }
2920     if (ret && distPoint->ReasonFlags.cbData)
2921     {
2922         swapped[cSwapped].tag = ASN_CONTEXT | 1;
2923         swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2924         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2925         items[cItem].pvStructInfo = &swapped[cSwapped];
2926         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2927         cSwapped++;
2928         cItem++;
2929     }
2930     if (ret && distPoint->CRLIssuer.cAltEntry)
2931     {
2932         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2933         swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2934         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2935         items[cItem].pvStructInfo = &swapped[cSwapped];
2936         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2937         cSwapped++;
2938         cItem++;
2939     }
2940     if (ret)
2941         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2942          pbEncoded, pcbEncoded);
2943     return ret;
2944 }
2945
2946 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2947  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2948  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2949 {
2950     BOOL ret;
2951
2952     __TRY
2953     {
2954         const CRL_DIST_POINTS_INFO *info =
2955          (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2956
2957         if (!info->cDistPoint)
2958         {
2959             SetLastError(E_INVALIDARG);
2960             ret = FALSE;
2961         }
2962         else
2963         {
2964             DWORD bytesNeeded, dataLen, lenBytes, i;
2965
2966             ret = TRUE;
2967             for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2968             {
2969                 DWORD len;
2970
2971                 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2972                  &len);
2973                 if (ret)
2974                     dataLen += len;
2975                 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2976                 {
2977                     /* Have to propagate index of failing character */
2978                     *pcbEncoded = len;
2979                 }
2980             }
2981             if (ret)
2982             {
2983                 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2984                 bytesNeeded = 1 + lenBytes + dataLen;
2985                 if (!pbEncoded)
2986                 {
2987                     *pcbEncoded = bytesNeeded;
2988                     ret = TRUE;
2989                 }
2990                 else
2991                 {
2992                     if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2993                      pbEncoded, pcbEncoded, bytesNeeded)))
2994                     {
2995                         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2996                             pbEncoded = *(BYTE **)pbEncoded;
2997                         *pbEncoded++ = ASN_SEQUENCEOF;
2998                         CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2999                         pbEncoded += lenBytes;
3000                         for (i = 0; ret && i < info->cDistPoint; i++)
3001                         {
3002                             DWORD len = dataLen;
3003
3004                             ret = CRYPT_AsnEncodeDistPoint(
3005                              &info->rgDistPoint[i], pbEncoded, &len);
3006                             if (ret)
3007                             {
3008                                 pbEncoded += len;
3009                                 dataLen -= len;
3010                             }
3011                         }
3012                     }
3013                 }
3014             }
3015         }
3016     }
3017     __EXCEPT_PAGE_FAULT
3018     {
3019         SetLastError(STATUS_ACCESS_VIOLATION);
3020         ret = FALSE;
3021     }
3022     __ENDTRY
3023     return ret;
3024 }
3025
3026 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
3027  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3028  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3029 {
3030     BOOL ret;
3031
3032     __TRY
3033     {
3034         const CERT_ENHKEY_USAGE *usage =
3035          (const CERT_ENHKEY_USAGE *)pvStructInfo;
3036         DWORD bytesNeeded = 0, lenBytes, size, i;
3037
3038         ret = TRUE;
3039         for (i = 0; ret && i < usage->cUsageIdentifier; i++)
3040         {
3041             ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
3042              usage->rgpszUsageIdentifier[i],
3043              dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
3044             if (ret)
3045                 bytesNeeded += size;
3046         }
3047         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
3048         bytesNeeded += 1 + lenBytes;
3049         if (ret)
3050         {
3051             if (!pbEncoded)
3052                 *pcbEncoded = bytesNeeded;
3053             else
3054             {
3055                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
3056                  pbEncoded, pcbEncoded, bytesNeeded)))
3057                 {
3058                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3059                         pbEncoded = *(BYTE **)pbEncoded;
3060                     *pbEncoded++ = ASN_SEQUENCEOF;
3061                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
3062                      &lenBytes);
3063                     pbEncoded += lenBytes;
3064                     for (i = 0; ret && i < usage->cUsageIdentifier; i++)
3065                     {
3066                         size = bytesNeeded;
3067                         ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
3068                          usage->rgpszUsageIdentifier[i],
3069                          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
3070                          &size);
3071                         if (ret)
3072                         {
3073                             pbEncoded += size;
3074                             bytesNeeded -= size;
3075                         }
3076                     }
3077                 }
3078             }
3079         }
3080     }
3081     __EXCEPT_PAGE_FAULT
3082     {
3083         SetLastError(STATUS_ACCESS_VIOLATION);
3084         ret = FALSE;
3085     }
3086     __ENDTRY
3087     return ret;
3088 }
3089
3090 static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType,
3091  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3092  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3093 {
3094     BOOL ret;
3095
3096     __TRY
3097     {
3098         const CRL_ISSUING_DIST_POINT *point =
3099          (const CRL_ISSUING_DIST_POINT *)pvStructInfo;
3100         struct AsnEncodeSequenceItem items[6] = { { 0 } };
3101         struct AsnConstructedItem constructed = { 0 };
3102         struct AsnEncodeTagSwappedItem swapped[5] = { { 0 } };
3103         DWORD cItem = 0, cSwapped = 0;
3104
3105         ret = TRUE;
3106         switch (point->DistPointName.dwDistPointNameChoice)
3107         {
3108         case CRL_DIST_POINT_NO_NAME:
3109             /* do nothing */
3110             break;
3111         case CRL_DIST_POINT_FULL_NAME:
3112             swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
3113             swapped[cSwapped].pvStructInfo = &point->DistPointName.u.FullName;
3114             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
3115             constructed.tag = 0;
3116             constructed.pvStructInfo = &swapped[cSwapped];
3117             constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
3118             items[cItem].pvStructInfo = &constructed;
3119             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
3120             cSwapped++;
3121             cItem++;
3122             break;
3123         default:
3124             SetLastError(E_INVALIDARG);
3125             ret = FALSE;
3126         }
3127         if (ret && point->fOnlyContainsUserCerts)
3128         {
3129             swapped[cSwapped].tag = ASN_CONTEXT | 1;
3130             swapped[cSwapped].pvStructInfo = &point->fOnlyContainsUserCerts;
3131             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
3132             items[cItem].pvStructInfo = &swapped[cSwapped];
3133             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3134             cSwapped++;
3135             cItem++;
3136         }
3137         if (ret && point->fOnlyContainsCACerts)
3138         {
3139             swapped[cSwapped].tag = ASN_CONTEXT | 2;
3140             swapped[cSwapped].pvStructInfo = &point->fOnlyContainsCACerts;
3141             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
3142             items[cItem].pvStructInfo = &swapped[cSwapped];
3143             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3144             cSwapped++;
3145             cItem++;
3146         }
3147         if (ret && point->OnlySomeReasonFlags.cbData)
3148         {
3149             swapped[cSwapped].tag = ASN_CONTEXT | 3;
3150             swapped[cSwapped].pvStructInfo = &point->OnlySomeReasonFlags;
3151             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
3152             items[cItem].pvStructInfo = &swapped[cSwapped];
3153             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3154             cSwapped++;
3155             cItem++;
3156         }
3157         if (ret && point->fIndirectCRL)
3158         {
3159             swapped[cSwapped].tag = ASN_CONTEXT | 4;
3160             swapped[cSwapped].pvStructInfo = &point->fIndirectCRL;
3161             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
3162             items[cItem].pvStructInfo = &swapped[cSwapped];
3163             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3164             cSwapped++;
3165             cItem++;
3166         }
3167         if (ret)
3168             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
3169              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3170     }
3171     __EXCEPT_PAGE_FAULT
3172     {
3173         SetLastError(STATUS_ACCESS_VIOLATION);
3174         ret = FALSE;
3175     }
3176     __ENDTRY
3177     return ret;
3178 }
3179
3180 static BOOL WINAPI CRYPT_AsnEncodeGeneralSubtree(DWORD dwCertEncodingType,
3181  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3182  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3183 {
3184     BOOL ret;
3185     const CERT_GENERAL_SUBTREE *subtree =
3186      (const CERT_GENERAL_SUBTREE *)pvStructInfo;
3187     struct AsnEncodeSequenceItem items[3] = {
3188      { &subtree->Base, CRYPT_AsnEncodeAltNameEntry, 0 },
3189      { 0 }
3190     };
3191     struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
3192     DWORD cItem = 1, cSwapped = 0;
3193
3194     if (subtree->dwMinimum)
3195     {
3196         swapped[cSwapped].tag = ASN_CONTEXT | 0;
3197         swapped[cSwapped].pvStructInfo = &subtree->dwMinimum;
3198         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInt;
3199         items[cItem].pvStructInfo = &swapped[cSwapped];
3200         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3201         cSwapped++;
3202         cItem++;
3203     }
3204     if (subtree->fMaximum)
3205     {
3206         swapped[cSwapped].tag = ASN_CONTEXT | 1;
3207         swapped[cSwapped].pvStructInfo = &subtree->dwMaximum;
3208         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInt;
3209         items[cItem].pvStructInfo = &swapped[cSwapped];
3210         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3211         cSwapped++;
3212         cItem++;
3213     }
3214     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem, dwFlags,
3215      pEncodePara, pbEncoded, pcbEncoded);
3216     return ret;
3217 }
3218
3219 static BOOL WINAPI CRYPT_AsnEncodeNameConstraints(DWORD dwCertEncodingType,
3220  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3221  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3222 {
3223     BOOL ret = FALSE;
3224     CRYPT_SET_OF permitted = { 0, NULL }, excluded = { 0, NULL };
3225
3226     TRACE("%p\n", pvStructInfo);
3227
3228     __TRY
3229     {
3230         const CERT_NAME_CONSTRAINTS_INFO *constraints =
3231          (const CERT_NAME_CONSTRAINTS_INFO *)pvStructInfo;
3232         struct AsnEncodeSequenceItem items[2] = { { 0 } };
3233         struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
3234         DWORD i, cItem = 0, cSwapped = 0;
3235
3236         ret = TRUE;
3237         if (constraints->cPermittedSubtree)
3238         {
3239             permitted.rgValue = CryptMemAlloc(
3240              constraints->cPermittedSubtree * sizeof(CRYPT_DER_BLOB));
3241             if (permitted.rgValue)
3242             {
3243                 permitted.cValue = constraints->cPermittedSubtree;
3244                 memset(permitted.rgValue, 0,
3245                  permitted.cValue * sizeof(CRYPT_DER_BLOB));
3246                 for (i = 0; ret && i < permitted.cValue; i++)
3247                     ret = CRYPT_AsnEncodeGeneralSubtree(dwCertEncodingType,
3248                      NULL, &constraints->rgPermittedSubtree[i],
3249                      CRYPT_ENCODE_ALLOC_FLAG, NULL,
3250                      (BYTE *)&permitted.rgValue[i].pbData,
3251                      &permitted.rgValue[i].cbData);
3252                 if (ret)
3253                 {
3254                     swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
3255                     swapped[cSwapped].pvStructInfo = &permitted;
3256                     swapped[cSwapped].encodeFunc = CRYPT_DEREncodeSet;
3257                     items[cItem].pvStructInfo = &swapped[cSwapped];
3258                     items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3259                     cSwapped++;
3260                     cItem++;
3261                 }
3262             }
3263             else
3264                 ret = FALSE;
3265         }
3266         if (constraints->cExcludedSubtree)
3267         {
3268             excluded.rgValue = CryptMemAlloc(
3269              constraints->cExcludedSubtree * sizeof(CRYPT_DER_BLOB));
3270             if (excluded.rgValue)
3271             {
3272                 excluded.cValue = constraints->cExcludedSubtree;
3273                 memset(excluded.rgValue, 0,
3274                  excluded.cValue * sizeof(CRYPT_DER_BLOB));
3275                 for (i = 0; ret && i < excluded.cValue; i++)
3276                     ret = CRYPT_AsnEncodeGeneralSubtree(dwCertEncodingType,
3277                      NULL, &constraints->rgExcludedSubtree[i],
3278                      CRYPT_ENCODE_ALLOC_FLAG, NULL,
3279                      (BYTE *)&excluded.rgValue[i].pbData,
3280                      &excluded.rgValue[i].cbData);
3281                 if (ret)
3282                 {
3283                     swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
3284                     swapped[cSwapped].pvStructInfo = &excluded;
3285                     swapped[cSwapped].encodeFunc = CRYPT_DEREncodeSet;
3286                     items[cItem].pvStructInfo = &swapped[cSwapped];
3287                     items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3288                     cSwapped++;
3289                     cItem++;
3290                 }
3291             }
3292             else
3293                 ret = FALSE;
3294         }
3295         if (ret)
3296             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
3297              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3298         for (i = 0; i < permitted.cValue; i++)
3299             LocalFree(permitted.rgValue[i].pbData);
3300         for (i = 0; i < excluded.cValue; i++)
3301             LocalFree(excluded.rgValue[i].pbData);
3302     }
3303     __EXCEPT_PAGE_FAULT
3304     {
3305         SetLastError(STATUS_ACCESS_VIOLATION);
3306     }
3307     __ENDTRY
3308     CryptMemFree(permitted.rgValue);
3309     CryptMemFree(excluded.rgValue);
3310     TRACE("returning %d\n", ret);
3311     return ret;
3312 }
3313
3314 static BOOL WINAPI CRYPT_AsnEncodeIssuerSerialNumber(
3315  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
3316  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
3317  DWORD *pcbEncoded)
3318 {
3319     BOOL ret;
3320     const CERT_ISSUER_SERIAL_NUMBER *issuerSerial =
3321      (const CERT_ISSUER_SERIAL_NUMBER *)pvStructInfo;
3322     struct AsnEncodeSequenceItem items[] = {
3323      { &issuerSerial->Issuer,       CRYPT_CopyEncodedBlob, 0 },
3324      { &issuerSerial->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
3325     };
3326
3327     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
3328      sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
3329      pcbEncoded);
3330     return ret;
3331 }
3332
3333 static BOOL WINAPI CRYPT_AsnEncodePKCSSignerInfo(DWORD dwCertEncodingType,
3334  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3335  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3336 {
3337     BOOL ret = FALSE;
3338
3339     if (!(dwCertEncodingType & PKCS_7_ASN_ENCODING))
3340     {
3341         SetLastError(E_INVALIDARG);
3342         return FALSE;
3343     }
3344
3345     __TRY
3346     {
3347         const CMSG_SIGNER_INFO *info = (const CMSG_SIGNER_INFO *)pvStructInfo;
3348
3349         if (!info->Issuer.cbData)
3350             SetLastError(E_INVALIDARG);
3351         else
3352         {
3353             struct AsnEncodeSequenceItem items[7] = {
3354              { &info->dwVersion,     CRYPT_AsnEncodeInt, 0 },
3355              { &info->Issuer,        CRYPT_AsnEncodeIssuerSerialNumber, 0 },
3356              { &info->HashAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams,
3357                0 },
3358             };
3359             struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
3360             DWORD cItem = 3, cSwapped = 0;
3361
3362             if (info->AuthAttrs.cAttr)
3363             {
3364                 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
3365                 swapped[cSwapped].pvStructInfo = &info->AuthAttrs;
3366                 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodePKCSAttributes;
3367                 items[cItem].pvStructInfo = &swapped[cSwapped];
3368                 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3369                 cSwapped++;
3370                 cItem++;
3371             }
3372             items[cItem].pvStructInfo = &info->HashEncryptionAlgorithm;
3373             items[cItem].encodeFunc = CRYPT_AsnEncodeAlgorithmIdWithNullParams;
3374             cItem++;
3375             items[cItem].pvStructInfo = &info->EncryptedHash;
3376             items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
3377             cItem++;
3378             if (info->UnauthAttrs.cAttr)
3379             {
3380                 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
3381                 swapped[cSwapped].pvStructInfo = &info->UnauthAttrs;
3382                 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodePKCSAttributes;
3383                 items[cItem].pvStructInfo = &swapped[cSwapped];
3384                 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3385                 cSwapped++;
3386                 cItem++;
3387             }
3388             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
3389              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3390         }
3391     }
3392     __EXCEPT_PAGE_FAULT
3393     {
3394         SetLastError(STATUS_ACCESS_VIOLATION);
3395     }
3396     __ENDTRY
3397     return ret;
3398 }
3399
3400 BOOL CRYPT_AsnEncodePKCSSignedInfo(CRYPT_SIGNED_INFO *signedInfo, void *pvData,
3401  DWORD *pcbData)
3402 {
3403     struct AsnEncodeSequenceItem items[7] = {
3404      { &signedInfo->version, CRYPT_AsnEncodeInt, 0 },
3405     };
3406     struct DERSetDescriptor digestAlgorithmsSet = { 0 }, certSet = { 0 };
3407     struct DERSetDescriptor crlSet = { 0 }, signerSet = { 0 };
3408     struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
3409     DWORD cItem = 1, cSwapped = 0;
3410     BOOL ret = TRUE;
3411
3412     if (signedInfo->cSignerInfo)
3413     {
3414         digestAlgorithmsSet.cItems = signedInfo->cSignerInfo;
3415         digestAlgorithmsSet.items = signedInfo->rgSignerInfo;
3416         digestAlgorithmsSet.itemSize = sizeof(CMSG_SIGNER_INFO);
3417         digestAlgorithmsSet.itemOffset =
3418          offsetof(CMSG_SIGNER_INFO, HashAlgorithm);
3419         digestAlgorithmsSet.encode = CRYPT_AsnEncodeAlgorithmIdWithNullParams;
3420         items[cItem].pvStructInfo = &digestAlgorithmsSet;
3421         items[cItem].encodeFunc = CRYPT_DEREncodeItemsAsSet;
3422         cItem++;
3423     }
3424     items[cItem].pvStructInfo = &signedInfo->content;
3425     items[cItem].encodeFunc = CRYPT_AsnEncodePKCSContentInfoInternal;
3426     cItem++;
3427     if (signedInfo->cCertEncoded)
3428     {
3429         certSet.cItems = signedInfo->cCertEncoded;
3430         certSet.items = signedInfo->rgCertEncoded;
3431         certSet.itemSize = sizeof(CERT_BLOB);
3432         certSet.itemOffset = 0;
3433         certSet.encode = CRYPT_CopyEncodedBlob;
3434         swapped[cSwapped].tag = ASN_CONSTRUCTOR | ASN_CONTEXT | 0;
3435         swapped[cSwapped].pvStructInfo = &certSet;
3436         swapped[cSwapped].encodeFunc = CRYPT_DEREncodeItemsAsSet;
3437         items[cItem].pvStructInfo = &swapped[cSwapped];
3438         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3439         cSwapped++;
3440         cItem++;
3441     }
3442     if (signedInfo->cCrlEncoded)
3443     {
3444         crlSet.cItems = signedInfo->cCrlEncoded;
3445         crlSet.items = signedInfo->rgCrlEncoded;
3446         crlSet.itemSize = sizeof(CRL_BLOB);
3447         crlSet.itemOffset = 0;
3448         crlSet.encode = CRYPT_CopyEncodedBlob;
3449         swapped[cSwapped].tag = ASN_CONSTRUCTOR | ASN_CONTEXT | 1;
3450         swapped[cSwapped].pvStructInfo = &crlSet;
3451         swapped[cSwapped].encodeFunc = CRYPT_DEREncodeItemsAsSet;
3452         items[cItem].pvStructInfo = &swapped[cSwapped];
3453         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3454         cSwapped++;
3455         cItem++;
3456     }
3457     if (ret && signedInfo->cSignerInfo)
3458     {
3459         signerSet.cItems = signedInfo->cSignerInfo;
3460         signerSet.items = signedInfo->rgSignerInfo;
3461         signerSet.itemSize = sizeof(CMSG_SIGNER_INFO);
3462         signerSet.itemOffset = 0;
3463         signerSet.encode = CRYPT_AsnEncodePKCSSignerInfo;
3464         items[cItem].pvStructInfo = &signerSet;
3465         items[cItem].encodeFunc = CRYPT_DEREncodeItemsAsSet;
3466         cItem++;
3467     }
3468     if (ret)
3469         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
3470          items, cItem, 0, NULL, pvData, pcbData);
3471
3472     return ret;
3473 }
3474
3475 static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType,
3476  LPCSTR lpszStructType)
3477 {
3478     CryptEncodeObjectExFunc encodeFunc = NULL;
3479
3480     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
3481      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
3482     {
3483         SetLastError(ERROR_FILE_NOT_FOUND);
3484         return NULL;
3485     }
3486
3487     if (!HIWORD(lpszStructType))
3488     {
3489         switch (LOWORD(lpszStructType))
3490         {
3491         case LOWORD(X509_CERT):
3492             encodeFunc = CRYPT_AsnEncodeCert;
3493             break;
3494         case LOWORD(X509_CERT_TO_BE_SIGNED):
3495             encodeFunc = CRYPT_AsnEncodeCertInfo;
3496             break;
3497         case LOWORD(X509_CERT_CRL_TO_BE_SIGNED):
3498             encodeFunc = CRYPT_AsnEncodeCRLInfo;
3499             break;
3500         case LOWORD(X509_EXTENSIONS):
3501             encodeFunc = CRYPT_AsnEncodeExtensions;
3502             break;
3503         case LOWORD(X509_NAME_VALUE):
3504             encodeFunc = CRYPT_AsnEncodeNameValue;
3505             break;
3506         case LOWORD(X509_NAME):
3507             encodeFunc = CRYPT_AsnEncodeName;
3508             break;
3509         case LOWORD(X509_PUBLIC_KEY_INFO):
3510             encodeFunc = CRYPT_AsnEncodePubKeyInfo;
3511             break;
3512         case LOWORD(X509_AUTHORITY_KEY_ID):
3513             encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3514             break;
3515         case LOWORD(X509_ALTERNATE_NAME):
3516             encodeFunc = CRYPT_AsnEncodeAltName;
3517             break;
3518         case LOWORD(X509_BASIC_CONSTRAINTS):
3519             encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3520             break;
3521         case LOWORD(X509_BASIC_CONSTRAINTS2):
3522             encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3523             break;
3524         case LOWORD(RSA_CSP_PUBLICKEYBLOB):
3525             encodeFunc = CRYPT_AsnEncodeRsaPubKey;
3526             break;
3527         case LOWORD(X509_UNICODE_NAME):
3528             encodeFunc = CRYPT_AsnEncodeUnicodeName;
3529             break;
3530         case LOWORD(PKCS_CONTENT_INFO):
3531             encodeFunc = CRYPT_AsnEncodePKCSContentInfo;
3532             break;
3533         case LOWORD(PKCS_ATTRIBUTE):
3534             encodeFunc = CRYPT_AsnEncodePKCSAttribute;
3535             break;
3536         case LOWORD(X509_UNICODE_NAME_VALUE):
3537             encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
3538             break;
3539         case LOWORD(X509_OCTET_STRING):
3540             encodeFunc = CRYPT_AsnEncodeOctets;
3541             break;
3542         case LOWORD(X509_BITS):
3543         case LOWORD(X509_KEY_USAGE):
3544             encodeFunc = CRYPT_AsnEncodeBits;
3545             break;
3546         case LOWORD(X509_INTEGER):
3547             encodeFunc = CRYPT_AsnEncodeInt;
3548             break;
3549         case LOWORD(X509_MULTI_BYTE_INTEGER):
3550             encodeFunc = CRYPT_AsnEncodeInteger;
3551             break;
3552         case LOWORD(X509_MULTI_BYTE_UINT):
3553             encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
3554             break;
3555         case LOWORD(X509_ENUMERATED):
3556             encodeFunc = CRYPT_AsnEncodeEnumerated;
3557             break;
3558         case LOWORD(X509_CHOICE_OF_TIME):
3559             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
3560             break;
3561         case LOWORD(X509_AUTHORITY_KEY_ID2):
3562             encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
3563             break;
3564         case LOWORD(X509_SEQUENCE_OF_ANY):
3565             encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
3566             break;
3567         case LOWORD(PKCS_UTC_TIME):
3568             encodeFunc = CRYPT_AsnEncodeUtcTime;
3569             break;
3570         case LOWORD(X509_CRL_DIST_POINTS):
3571             encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3572             break;
3573         case LOWORD(X509_ENHANCED_KEY_USAGE):
3574             encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3575             break;
3576         case LOWORD(PKCS_ATTRIBUTES):
3577             encodeFunc = CRYPT_AsnEncodePKCSAttributes;
3578             break;
3579         case LOWORD(X509_ISSUING_DIST_POINT):
3580             encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3581             break;
3582         case LOWORD(X509_NAME_CONSTRAINTS):
3583             encodeFunc = CRYPT_AsnEncodeNameConstraints;
3584             break;
3585         case LOWORD(PKCS7_SIGNER_INFO):
3586             encodeFunc = CRYPT_AsnEncodePKCSSignerInfo;
3587             break;
3588         }
3589     }
3590     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
3591         encodeFunc = CRYPT_AsnEncodeExtensions;
3592     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
3593         encodeFunc = CRYPT_AsnEncodeUtcTime;
3594     else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
3595         encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3596     else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
3597         encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
3598     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
3599         encodeFunc = CRYPT_AsnEncodeEnumerated;
3600     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
3601         encodeFunc = CRYPT_AsnEncodeBits;
3602     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
3603         encodeFunc = CRYPT_AsnEncodeOctets;
3604     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
3605         encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3606     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
3607         encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3608     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
3609         encodeFunc = CRYPT_AsnEncodeAltName;
3610     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
3611         encodeFunc = CRYPT_AsnEncodeAltName;
3612     else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
3613         encodeFunc = CRYPT_AsnEncodeAltName;
3614     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
3615         encodeFunc = CRYPT_AsnEncodeAltName;
3616     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
3617         encodeFunc = CRYPT_AsnEncodeAltName;
3618     else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
3619         encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3620     else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
3621         encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3622     else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
3623         encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3624     else if (!strcmp(lpszStructType, szOID_NAME_CONSTRAINTS))
3625         encodeFunc = CRYPT_AsnEncodeNameConstraints;
3626     return encodeFunc;
3627 }
3628
3629 static CryptEncodeObjectFunc CRYPT_LoadEncoderFunc(DWORD dwCertEncodingType,
3630  LPCSTR lpszStructType, HCRYPTOIDFUNCADDR *hFunc)
3631 {
3632     static HCRYPTOIDFUNCSET set = NULL;
3633     CryptEncodeObjectFunc encodeFunc = NULL;
3634
3635     if (!set)
3636         set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_FUNC, 0);
3637     CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
3638      (void **)&encodeFunc, hFunc);
3639     return encodeFunc;
3640 }
3641
3642 static CryptEncodeObjectExFunc CRYPT_LoadEncoderExFunc(DWORD dwCertEncodingType,
3643  LPCSTR lpszStructType, HCRYPTOIDFUNCADDR *hFunc)
3644 {
3645     static HCRYPTOIDFUNCSET set = NULL;
3646     CryptEncodeObjectExFunc encodeFunc = NULL;
3647
3648     if (!set)
3649         set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
3650     CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
3651      (void **)&encodeFunc, hFunc);
3652     return encodeFunc;
3653 }
3654
3655 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
3656  const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
3657 {
3658     BOOL ret = FALSE;
3659     HCRYPTOIDFUNCADDR hFunc = NULL;
3660     CryptEncodeObjectFunc pCryptEncodeObject = NULL;
3661     CryptEncodeObjectExFunc pCryptEncodeObjectEx = NULL;
3662
3663     TRACE_(crypt)("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
3664      debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
3665      pcbEncoded);
3666
3667     if (!pbEncoded && !pcbEncoded)
3668     {
3669         SetLastError(ERROR_INVALID_PARAMETER);
3670         return FALSE;
3671     }
3672
3673     if (!(pCryptEncodeObjectEx = CRYPT_GetBuiltinEncoder(dwCertEncodingType,
3674      lpszStructType)))
3675     {
3676         TRACE_(crypt)("OID %s not found or unimplemented, looking for DLL\n",
3677          debugstr_a(lpszStructType));
3678         pCryptEncodeObject = CRYPT_LoadEncoderFunc(dwCertEncodingType,
3679          lpszStructType, &hFunc);
3680         if (!pCryptEncodeObject)
3681             pCryptEncodeObjectEx = CRYPT_LoadEncoderExFunc(dwCertEncodingType,
3682              lpszStructType, &hFunc);
3683     }
3684     if (pCryptEncodeObject)
3685         ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
3686          pvStructInfo, pbEncoded, pcbEncoded);
3687     else if (pCryptEncodeObjectEx)
3688         ret = pCryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
3689          pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
3690     if (hFunc)
3691         CryptFreeOIDFunctionAddress(hFunc, 0);
3692     TRACE_(crypt)("returning %d\n", ret);
3693     return ret;
3694 }
3695
3696 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
3697  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
3698  void *pvEncoded, DWORD *pcbEncoded)
3699 {
3700     BOOL ret = FALSE;
3701     HCRYPTOIDFUNCADDR hFunc = NULL;
3702     CryptEncodeObjectExFunc encodeFunc = NULL;
3703
3704     TRACE_(crypt)("(0x%08x, %s, %p, 0x%08x, %p, %p, %p)\n", dwCertEncodingType,
3705      debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
3706      pvEncoded, pcbEncoded);
3707
3708     if (!pvEncoded && !pcbEncoded)
3709     {
3710         SetLastError(ERROR_INVALID_PARAMETER);
3711         return FALSE;
3712     }
3713
3714     SetLastError(NOERROR);
3715     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
3716         *(BYTE **)pvEncoded = NULL;
3717     encodeFunc = CRYPT_GetBuiltinEncoder(dwCertEncodingType, lpszStructType);
3718     if (!encodeFunc)
3719     {
3720         TRACE_(crypt)("OID %s not found or unimplemented, looking for DLL\n",
3721          debugstr_a(lpszStructType));
3722         encodeFunc = CRYPT_LoadEncoderExFunc(dwCertEncodingType, lpszStructType,
3723          &hFunc);
3724     }
3725     if (encodeFunc)
3726         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
3727          dwFlags, pEncodePara, pvEncoded, pcbEncoded);
3728     else
3729     {
3730         CryptEncodeObjectFunc pCryptEncodeObject =
3731          CRYPT_LoadEncoderFunc(dwCertEncodingType, lpszStructType, &hFunc);
3732
3733         if (pCryptEncodeObject)
3734         {
3735             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3736             {
3737                 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
3738                  pvStructInfo, NULL, pcbEncoded);
3739                 if (ret && (ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
3740                  pvEncoded, pcbEncoded, *pcbEncoded)))
3741                     ret = pCryptEncodeObject(dwCertEncodingType,
3742                      lpszStructType, pvStructInfo, *(BYTE **)pvEncoded,
3743                      pcbEncoded);
3744             }
3745             else
3746                 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
3747                  pvStructInfo, pvEncoded, pcbEncoded);
3748         }
3749     }
3750     if (hFunc)
3751         CryptFreeOIDFunctionAddress(hFunc, 0);
3752     TRACE_(crypt)("returning %d\n", ret);
3753     return ret;
3754 }
3755
3756 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, DWORD dwKeySpec,
3757  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3758 {
3759     return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
3760      NULL, 0, NULL, pInfo, pcbInfo);
3761 }
3762
3763 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
3764  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3765  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3766 {
3767     BOOL ret;
3768     HCRYPTKEY key;
3769     static CHAR oid[] = szOID_RSA_RSA;
3770
3771     TRACE_(crypt)("(%08lx, %d, %08x, %s, %08x, %p, %p, %d)\n", hCryptProv,
3772      dwKeySpec, dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags,
3773      pvAuxInfo, pInfo, pInfo ? *pcbInfo : 0);
3774
3775     if (!pszPublicKeyObjId)
3776         pszPublicKeyObjId = oid;
3777     if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
3778     {
3779         DWORD keySize = 0;
3780
3781         ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
3782         if (ret)
3783         {
3784             LPBYTE pubKey = CryptMemAlloc(keySize);
3785
3786             if (pubKey)
3787             {
3788                 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
3789                  &keySize);
3790                 if (ret)
3791                 {
3792                     DWORD encodedLen = 0;
3793
3794                     ret = CryptEncodeObject(dwCertEncodingType,
3795                      RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
3796                     if (ret)
3797                     {
3798                         DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
3799                          strlen(pszPublicKeyObjId) + 1 + encodedLen;
3800
3801                         if (!pInfo)
3802                             *pcbInfo = sizeNeeded;
3803                         else if (*pcbInfo < sizeNeeded)
3804                         {
3805                             SetLastError(ERROR_MORE_DATA);
3806                             *pcbInfo = sizeNeeded;
3807                             ret = FALSE;
3808                         }
3809                         else
3810                         {
3811                             pInfo->Algorithm.pszObjId = (char *)pInfo +
3812                              sizeof(CERT_PUBLIC_KEY_INFO);
3813                             lstrcpyA(pInfo->Algorithm.pszObjId,
3814                              pszPublicKeyObjId);
3815                             pInfo->Algorithm.Parameters.cbData = 0;
3816                             pInfo->Algorithm.Parameters.pbData = NULL;
3817                             pInfo->PublicKey.pbData =
3818                              (BYTE *)pInfo->Algorithm.pszObjId
3819                              + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
3820                             pInfo->PublicKey.cbData = encodedLen;
3821                             pInfo->PublicKey.cUnusedBits = 0;
3822                             ret = CryptEncodeObject(dwCertEncodingType,
3823                              RSA_CSP_PUBLICKEYBLOB, pubKey,
3824                              pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
3825                         }
3826                     }
3827                 }
3828                 CryptMemFree(pubKey);
3829             }
3830             else
3831                 ret = FALSE;
3832         }
3833         CryptDestroyKey(key);
3834     }
3835     return ret;
3836 }
3837
3838 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
3839  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3840  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
3841
3842 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, DWORD dwKeySpec,
3843  DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
3844  void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3845 {
3846     static HCRYPTOIDFUNCSET set = NULL;
3847     BOOL ret;
3848     ExportPublicKeyInfoExFunc exportFunc = NULL;
3849     HCRYPTOIDFUNCADDR hFunc = NULL;
3850
3851     TRACE_(crypt)("(%08lx, %d, %08x, %s, %08x, %p, %p, %d)\n", hCryptProv,
3852      dwKeySpec, dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags,
3853      pvAuxInfo, pInfo, pInfo ? *pcbInfo : 0);
3854
3855     if (!hCryptProv)
3856     {
3857         SetLastError(ERROR_INVALID_PARAMETER);
3858         return FALSE;
3859     }
3860
3861     if (pszPublicKeyObjId)
3862     {
3863         if (!set)
3864             set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
3865              0);
3866         CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
3867          0, (void **)&exportFunc, &hFunc);
3868     }
3869     if (!exportFunc)
3870         exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
3871     ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
3872      pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
3873     if (hFunc)
3874         CryptFreeOIDFunctionAddress(hFunc, 0);
3875     return ret;
3876 }
3877
3878 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
3879  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
3880 {
3881     return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
3882      0, 0, NULL, phKey);
3883 }
3884
3885 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3886  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3887  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3888 {
3889     BOOL ret;
3890     DWORD pubKeySize = 0;
3891
3892     TRACE_(crypt)("(%08lx, %08x, %p, %08x, %08x, %p, %p)\n", hCryptProv,
3893      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3894
3895     ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3896      pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
3897     if (ret)
3898     {
3899         LPBYTE pubKey = CryptMemAlloc(pubKeySize);
3900
3901         if (pubKey)
3902         {
3903             ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3904              pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
3905              &pubKeySize);
3906             if (ret)
3907                 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
3908                  phKey);
3909             CryptMemFree(pubKey);
3910         }
3911         else
3912             ret = FALSE;
3913     }
3914     return ret;
3915 }
3916
3917 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3918  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3919  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
3920
3921 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3922  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3923  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3924 {
3925     static HCRYPTOIDFUNCSET set = NULL;
3926     BOOL ret;
3927     ImportPublicKeyInfoExFunc importFunc = NULL;
3928     HCRYPTOIDFUNCADDR hFunc = NULL;
3929
3930     TRACE_(crypt)("(%08lx, %08x, %p, %08x, %08x, %p, %p)\n", hCryptProv,
3931      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3932
3933     if (!set)
3934         set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
3935     CryptGetOIDFunctionAddress(set, dwCertEncodingType,
3936      pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
3937     if (!importFunc)
3938         importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
3939     ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
3940      pvAuxInfo, phKey);
3941     if (hFunc)
3942         CryptFreeOIDFunctionAddress(hFunc, 0);
3943     return ret;
3944 }