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