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