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