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