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