crypt32: Add tests for encoding/decoding cert policy constraints.
[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_AsnEncodeIntegerSwapBytes(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 CRYPT_DATA_BLOB *blob = pvStructInfo;
2450         CRYPT_DATA_BLOB newBlob = { blob->cbData, NULL };
2451
2452         ret = TRUE;
2453         if (newBlob.cbData)
2454         {
2455             newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2456             if (newBlob.pbData)
2457             {
2458                 DWORD i;
2459
2460                 for (i = 0; i < newBlob.cbData; i++)
2461                     newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2462             }
2463             else
2464                 ret = FALSE;
2465         }
2466         if (ret)
2467             ret = CRYPT_AsnEncodeInteger(dwCertEncodingType, lpszStructType,
2468              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2469         CryptMemFree(newBlob.pbData);
2470     }
2471     __EXCEPT_PAGE_FAULT
2472     {
2473         SetLastError(STATUS_ACCESS_VIOLATION);
2474         ret = FALSE;
2475     }
2476     __ENDTRY
2477     return ret;
2478 }
2479
2480 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType,
2481  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2482  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2483 {
2484     BOOL ret;
2485
2486     __TRY
2487     {
2488         const CERT_AUTHORITY_KEY_ID_INFO *info = pvStructInfo;
2489         struct AsnEncodeSequenceItem items[3] = { { 0 } };
2490         struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2491         struct AsnConstructedItem constructed = { 0 };
2492         DWORD cItem = 0, cSwapped = 0;
2493
2494         if (info->KeyId.cbData)
2495         {
2496             swapped[cSwapped].tag = ASN_CONTEXT | 0;
2497             swapped[cSwapped].pvStructInfo = &info->KeyId;
2498             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeIntegerSwapBytes;
2499             items[cItem].pvStructInfo = &swapped[cSwapped];
2500             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2501             cSwapped++;
2502             cItem++;
2503         }
2504         if (info->CertIssuer.cbData)
2505         {
2506             constructed.tag = 1;
2507             constructed.pvStructInfo = &info->CertIssuer;
2508             constructed.encodeFunc = CRYPT_CopyEncodedBlob;
2509             items[cItem].pvStructInfo = &constructed;
2510             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2511             cItem++;
2512         }
2513         if (info->CertSerialNumber.cbData)
2514         {
2515             swapped[cSwapped].tag = ASN_CONTEXT | 2;
2516             swapped[cSwapped].pvStructInfo = &info->CertSerialNumber;
2517             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
2518             items[cItem].pvStructInfo = &swapped[cSwapped];
2519             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2520             cSwapped++;
2521             cItem++;
2522         }
2523         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
2524          pEncodePara, pbEncoded, pcbEncoded);
2525     }
2526     __EXCEPT_PAGE_FAULT
2527     {
2528         SetLastError(STATUS_ACCESS_VIOLATION);
2529         ret = FALSE;
2530     }
2531     __ENDTRY
2532     return ret;
2533 }
2534
2535 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
2536  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2537  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2538 {
2539     BOOL ret;
2540
2541     __TRY
2542     {
2543         const CERT_ALT_NAME_INFO *info = pvStructInfo;
2544         DWORD bytesNeeded, dataLen, lenBytes, i;
2545
2546         ret = TRUE;
2547         /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
2548          * can't encode an erroneous entry index if it's bigger than this.
2549          */
2550         for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
2551         {
2552             DWORD len;
2553
2554             ret = CRYPT_AsnEncodeAltNameEntry(dwCertEncodingType, NULL,
2555              &info->rgAltEntry[i], 0, NULL, NULL, &len);
2556             if (ret)
2557                 dataLen += len;
2558             else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2559             {
2560                 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
2561                  * the bad character, now set the index of the bad
2562                  * entry
2563                  */
2564                 *pcbEncoded = (BYTE)i <<
2565                  CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
2566             }
2567         }
2568         if (ret)
2569         {
2570             CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2571             bytesNeeded = 1 + lenBytes + dataLen;
2572             if (!pbEncoded)
2573             {
2574                 *pcbEncoded = bytesNeeded;
2575                 ret = TRUE;
2576             }
2577             else
2578             {
2579                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2580                  pbEncoded, pcbEncoded, bytesNeeded)))
2581                 {
2582                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2583                         pbEncoded = *(BYTE **)pbEncoded;
2584                     *pbEncoded++ = ASN_SEQUENCEOF;
2585                     CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2586                     pbEncoded += lenBytes;
2587                     for (i = 0; ret && i < info->cAltEntry; i++)
2588                     {
2589                         DWORD len = dataLen;
2590
2591                         ret = CRYPT_AsnEncodeAltNameEntry(dwCertEncodingType,
2592                          NULL, &info->rgAltEntry[i], 0, NULL, pbEncoded, &len);
2593                         if (ret)
2594                         {
2595                             pbEncoded += len;
2596                             dataLen -= len;
2597                         }
2598                     }
2599                 }
2600             }
2601         }
2602     }
2603     __EXCEPT_PAGE_FAULT
2604     {
2605         SetLastError(STATUS_ACCESS_VIOLATION);
2606         ret = FALSE;
2607     }
2608     __ENDTRY
2609     return ret;
2610 }
2611
2612 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId2(DWORD dwCertEncodingType,
2613  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2614  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2615 {
2616     BOOL ret;
2617
2618     __TRY
2619     {
2620         const CERT_AUTHORITY_KEY_ID2_INFO *info = pvStructInfo;
2621         struct AsnEncodeSequenceItem items[3] = { { 0 } };
2622         struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2623         DWORD cItem = 0, cSwapped = 0;
2624
2625         if (info->KeyId.cbData)
2626         {
2627             swapped[cSwapped].tag = ASN_CONTEXT | 0;
2628             swapped[cSwapped].pvStructInfo = &info->KeyId;
2629             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeIntegerSwapBytes;
2630             items[cItem].pvStructInfo = &swapped[cSwapped];
2631             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2632             cSwapped++;
2633             cItem++;
2634         }
2635         if (info->AuthorityCertIssuer.cAltEntry)
2636         {
2637             swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
2638             swapped[cSwapped].pvStructInfo = &info->AuthorityCertIssuer;
2639             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2640             items[cItem].pvStructInfo = &swapped[cSwapped];
2641             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2642             cSwapped++;
2643             cItem++;
2644         }
2645         if (info->AuthorityCertSerialNumber.cbData)
2646         {
2647             swapped[cSwapped].tag = ASN_CONTEXT | 2;
2648             swapped[cSwapped].pvStructInfo = &info->AuthorityCertSerialNumber;
2649             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
2650             items[cItem].pvStructInfo = &swapped[cSwapped];
2651             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2652             cSwapped++;
2653             cItem++;
2654         }
2655         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
2656          pEncodePara, pbEncoded, pcbEncoded);
2657     }
2658     __EXCEPT_PAGE_FAULT
2659     {
2660         SetLastError(STATUS_ACCESS_VIOLATION);
2661         ret = FALSE;
2662     }
2663     __ENDTRY
2664     return ret;
2665 }
2666
2667 static BOOL CRYPT_AsnEncodeAccessDescription(
2668  const CERT_ACCESS_DESCRIPTION *descr, BYTE *pbEncoded, DWORD *pcbEncoded)
2669 {
2670     struct AsnEncodeSequenceItem items[] = {
2671      { descr->pszAccessMethod, CRYPT_AsnEncodeOid, 0 },
2672      { &descr->AccessLocation, CRYPT_AsnEncodeAltNameEntry, 0 },
2673     };
2674
2675     if (!descr->pszAccessMethod)
2676     {
2677         SetLastError(E_INVALIDARG);
2678         return FALSE;
2679     }
2680     return CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items,
2681      sizeof(items) / sizeof(items[0]), 0, NULL, pbEncoded, pcbEncoded);
2682 }
2683
2684 static BOOL WINAPI CRYPT_AsnEncodeAuthorityInfoAccess(DWORD dwCertEncodingType,
2685  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2686  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2687 {
2688     BOOL ret;
2689
2690     __TRY
2691     {
2692         DWORD bytesNeeded, dataLen, lenBytes, i;
2693         const CERT_AUTHORITY_INFO_ACCESS *info = pvStructInfo;
2694
2695         ret = TRUE;
2696         for (i = 0, dataLen = 0; ret && i < info->cAccDescr; i++)
2697         {
2698             DWORD size;
2699
2700             ret = CRYPT_AsnEncodeAccessDescription(&info->rgAccDescr[i], NULL,
2701              &size);
2702             if (ret)
2703                 dataLen += size;
2704         }
2705         if (ret)
2706         {
2707             CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2708             bytesNeeded = 1 + lenBytes + dataLen;
2709             if (!pbEncoded)
2710                 *pcbEncoded = bytesNeeded;
2711             else
2712             {
2713                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2714                  pbEncoded, pcbEncoded, bytesNeeded)))
2715                 {
2716                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2717                         pbEncoded = *(BYTE **)pbEncoded;
2718                     *pbEncoded++ = ASN_SEQUENCEOF;
2719                     CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2720                     pbEncoded += lenBytes;
2721                     for (i = 0; i < info->cAccDescr; i++)
2722                     {
2723                         DWORD size = dataLen;
2724
2725                         ret = CRYPT_AsnEncodeAccessDescription(
2726                          &info->rgAccDescr[i], pbEncoded, &size);
2727                         pbEncoded += size;
2728                         dataLen -= size;
2729                     }
2730                 }
2731             }
2732         }
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_AsnEncodeBasicConstraints(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_CONSTRAINTS_INFO *info = pvStructInfo;
2752         struct AsnEncodeSequenceItem items[3] = {
2753          { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
2754          { 0 }
2755         };
2756         DWORD cItem = 1;
2757
2758         if (info->fPathLenConstraint)
2759         {
2760             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2761             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2762             cItem++;
2763         }
2764         if (info->cSubtreesConstraint)
2765         {
2766             items[cItem].pvStructInfo = &info->cSubtreesConstraint;
2767             items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2768             cItem++;
2769         }
2770         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2771          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2772     }
2773     __EXCEPT_PAGE_FAULT
2774     {
2775         SetLastError(STATUS_ACCESS_VIOLATION);
2776         ret = FALSE;
2777     }
2778     __ENDTRY
2779     return ret;
2780 }
2781
2782 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
2783  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2784  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2785 {
2786     BOOL ret;
2787
2788     __TRY
2789     {
2790         const CERT_BASIC_CONSTRAINTS2_INFO *info = pvStructInfo;
2791         struct AsnEncodeSequenceItem items[2] = { { 0 } };
2792         DWORD cItem = 0;
2793
2794         if (info->fCA)
2795         {
2796             items[cItem].pvStructInfo = &info->fCA;
2797             items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
2798             cItem++;
2799         }
2800         if (info->fPathLenConstraint)
2801         {
2802             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2803             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2804             cItem++;
2805         }
2806         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2807          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2808     }
2809     __EXCEPT_PAGE_FAULT
2810     {
2811         SetLastError(STATUS_ACCESS_VIOLATION);
2812         ret = FALSE;
2813     }
2814     __ENDTRY
2815     return ret;
2816 }
2817
2818 static BOOL WINAPI CRYPT_AsnEncodeCertPolicyQualifiers(DWORD dwCertEncodingType,
2819  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2820  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2821 {
2822     const CERT_POLICY_INFO *info = pvStructInfo;
2823     BOOL ret;
2824
2825     if (!info->cPolicyQualifier)
2826     {
2827         *pcbEncoded = 0;
2828         ret = TRUE;
2829     }
2830     else
2831     {
2832         struct AsnEncodeSequenceItem items[2] = {
2833          { NULL, CRYPT_AsnEncodeOid, 0 },
2834          { NULL, CRYPT_CopyEncodedBlob, 0 },
2835         };
2836         DWORD bytesNeeded = 0, lenBytes, size, i;
2837
2838         ret = TRUE;
2839         for (i = 0; ret && i < info->cPolicyQualifier; i++)
2840         {
2841             items[0].pvStructInfo =
2842              info->rgPolicyQualifier[i].pszPolicyQualifierId;
2843             items[1].pvStructInfo = &info->rgPolicyQualifier[i].Qualifier;
2844             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
2845              sizeof(items) / sizeof(items[0]),
2846              dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
2847             if (ret)
2848                 bytesNeeded += size;
2849         }
2850         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2851         bytesNeeded += 1 + lenBytes;
2852         if (ret)
2853         {
2854             if (!pbEncoded)
2855                 *pcbEncoded = bytesNeeded;
2856             else
2857             {
2858                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2859                  pbEncoded, pcbEncoded, bytesNeeded)))
2860                 {
2861                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2862                         pbEncoded = *(BYTE **)pbEncoded;
2863                     *pbEncoded++ = ASN_SEQUENCEOF;
2864                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2865                      &lenBytes);
2866                     pbEncoded += lenBytes;
2867                     for (i = 0; ret && i < info->cPolicyQualifier; i++)
2868                     {
2869                         items[0].pvStructInfo =
2870                          info->rgPolicyQualifier[i].pszPolicyQualifierId;
2871                         items[1].pvStructInfo =
2872                          &info->rgPolicyQualifier[i].Qualifier;
2873                         size = bytesNeeded;
2874                         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
2875                          sizeof(items) / sizeof(items[0]),
2876                          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
2877                          &size);
2878                         if (ret)
2879                         {
2880                             pbEncoded += size;
2881                             bytesNeeded -= size;
2882                         }
2883                     }
2884                 }
2885             }
2886         }
2887     }
2888     return ret;
2889 }
2890
2891 static BOOL CRYPT_AsnEncodeCertPolicy(DWORD dwCertEncodingType,
2892  const CERT_POLICY_INFO *info, DWORD dwFlags, BYTE *pbEncoded,
2893  DWORD *pcbEncoded)
2894 {
2895     struct AsnEncodeSequenceItem items[2] = {
2896      { info->pszPolicyIdentifier, CRYPT_AsnEncodeOid, 0 },
2897      { info,                      CRYPT_AsnEncodeCertPolicyQualifiers, 0 },
2898     };
2899     BOOL ret;
2900
2901     if (!info->pszPolicyIdentifier)
2902     {
2903         SetLastError(E_INVALIDARG);
2904         return FALSE;
2905     }
2906     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
2907      sizeof(items) / sizeof(items[0]), dwFlags, NULL, pbEncoded, pcbEncoded);
2908     return ret;
2909 }
2910
2911 static BOOL WINAPI CRYPT_AsnEncodeCertPolicies(DWORD dwCertEncodingType,
2912  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2913  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2914 {
2915     BOOL ret = FALSE;
2916
2917     __TRY
2918     {
2919         const CERT_POLICIES_INFO *info = pvStructInfo;
2920         DWORD bytesNeeded = 0, lenBytes, size, i;
2921
2922         ret = TRUE;
2923         for (i = 0; ret && i < info->cPolicyInfo; i++)
2924         {
2925             ret = CRYPT_AsnEncodeCertPolicy(dwCertEncodingType,
2926              &info->rgPolicyInfo[i], dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
2927              &size);
2928             if (ret)
2929                 bytesNeeded += size;
2930         }
2931         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2932         bytesNeeded += 1 + lenBytes;
2933         if (ret)
2934         {
2935             if (!pbEncoded)
2936                 *pcbEncoded = bytesNeeded;
2937             else
2938             {
2939                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2940                  pbEncoded, pcbEncoded, bytesNeeded)))
2941                 {
2942                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2943                         pbEncoded = *(BYTE **)pbEncoded;
2944                     *pbEncoded++ = ASN_SEQUENCEOF;
2945                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2946                      &lenBytes);
2947                     pbEncoded += lenBytes;
2948                     for (i = 0; ret && i < info->cPolicyInfo; i++)
2949                     {
2950                         size = bytesNeeded;
2951                         ret = CRYPT_AsnEncodeCertPolicy(dwCertEncodingType,
2952                          &info->rgPolicyInfo[i],
2953                          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, pbEncoded, &size);
2954                         if (ret)
2955                         {
2956                             pbEncoded += size;
2957                             bytesNeeded -= size;
2958                         }
2959                     }
2960                 }
2961             }
2962         }
2963     }
2964     __EXCEPT_PAGE_FAULT
2965     {
2966         SetLastError(STATUS_ACCESS_VIOLATION);
2967     }
2968     __ENDTRY
2969     return ret;
2970 }
2971
2972 static BOOL CRYPT_AsnEncodeCertPolicyMapping(DWORD dwCertEncodingType,
2973  const CERT_POLICY_MAPPING *mapping, DWORD dwFlags, BYTE *pbEncoded,
2974  DWORD *pcbEncoded)
2975 {
2976     struct AsnEncodeSequenceItem items[] = {
2977      { mapping->pszIssuerDomainPolicy,  CRYPT_AsnEncodeOid, 0 },
2978      { mapping->pszSubjectDomainPolicy, CRYPT_AsnEncodeOid, 0 },
2979     };
2980
2981     if (!mapping->pszIssuerDomainPolicy || !mapping->pszSubjectDomainPolicy)
2982     {
2983         SetLastError(E_INVALIDARG);
2984         return FALSE;
2985     }
2986     return CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
2987      sizeof(items) / sizeof(items[0]), dwFlags, NULL, pbEncoded, pcbEncoded);
2988 }
2989
2990 static BOOL WINAPI CRYPT_AsnEncodeCertPolicyMappings(DWORD dwCertEncodingType,
2991  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2992  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2993 {
2994     BOOL ret = FALSE;
2995
2996     __TRY
2997     {
2998         const CERT_POLICY_MAPPINGS_INFO *info = pvStructInfo;
2999         DWORD bytesNeeded = 0, lenBytes, size, i;
3000
3001         ret = TRUE;
3002         for (i = 0; ret && i < info->cPolicyMapping; i++)
3003         {
3004             ret = CRYPT_AsnEncodeCertPolicyMapping(dwCertEncodingType,
3005              &info->rgPolicyMapping[i], dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
3006              NULL, &size);
3007             if (ret)
3008                 bytesNeeded += size;
3009         }
3010         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
3011         bytesNeeded += 1 + lenBytes;
3012         if (ret)
3013         {
3014             if (!pbEncoded)
3015                 *pcbEncoded = bytesNeeded;
3016             else
3017             {
3018                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
3019                  pbEncoded, pcbEncoded, bytesNeeded)))
3020                 {
3021                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3022                         pbEncoded = *(BYTE **)pbEncoded;
3023                     *pbEncoded++ = ASN_SEQUENCEOF;
3024                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
3025                      &lenBytes);
3026                     pbEncoded += lenBytes;
3027                     for (i = 0; ret && i < info->cPolicyMapping; i++)
3028                     {
3029                         size = bytesNeeded;
3030                         ret = CRYPT_AsnEncodeCertPolicyMapping(
3031                          dwCertEncodingType, &info->rgPolicyMapping[i],
3032                          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, pbEncoded, &size);
3033                         if (ret)
3034                         {
3035                             pbEncoded += size;
3036                             bytesNeeded -= size;
3037                         }
3038                     }
3039                 }
3040             }
3041         }
3042     }
3043     __EXCEPT_PAGE_FAULT
3044     {
3045         SetLastError(STATUS_ACCESS_VIOLATION);
3046     }
3047     __ENDTRY
3048     return ret;
3049 }
3050
3051 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
3052  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3053  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3054 {
3055     BOOL ret;
3056
3057     __TRY
3058     {
3059         const BLOBHEADER *hdr = pvStructInfo;
3060
3061         if (hdr->bType != PUBLICKEYBLOB)
3062         {
3063             SetLastError(E_INVALIDARG);
3064             ret = FALSE;
3065         }
3066         else
3067         {
3068             const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
3069              ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
3070             CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
3071              (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
3072             struct AsnEncodeSequenceItem items[] = { 
3073              { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
3074              { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
3075             };
3076
3077             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
3078              sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
3079              pcbEncoded);
3080         }
3081     }
3082     __EXCEPT_PAGE_FAULT
3083     {
3084         SetLastError(STATUS_ACCESS_VIOLATION);
3085         ret = FALSE;
3086     }
3087     __ENDTRY
3088     return ret;
3089 }
3090
3091 BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
3092  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3093  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3094 {
3095     BOOL ret;
3096
3097     __TRY
3098     {
3099         const CRYPT_DATA_BLOB *blob = pvStructInfo;
3100         DWORD bytesNeeded, lenBytes;
3101
3102         TRACE("(%d, %p), %08x, %p, %p, %d\n", blob->cbData, blob->pbData,
3103          dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
3104
3105         CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
3106         bytesNeeded = 1 + lenBytes + blob->cbData;
3107         if (!pbEncoded)
3108         {
3109             *pcbEncoded = bytesNeeded;
3110             ret = TRUE;
3111         }
3112         else
3113         {
3114             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
3115              pcbEncoded, bytesNeeded)))
3116             {
3117                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3118                     pbEncoded = *(BYTE **)pbEncoded;
3119                 *pbEncoded++ = ASN_OCTETSTRING;
3120                 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
3121                 pbEncoded += lenBytes;
3122                 if (blob->cbData)
3123                     memcpy(pbEncoded, blob->pbData, blob->cbData);
3124             }
3125         }
3126     }
3127     __EXCEPT_PAGE_FAULT
3128     {
3129         SetLastError(STATUS_ACCESS_VIOLATION);
3130         ret = FALSE;
3131     }
3132     __ENDTRY
3133     TRACE("returning %d (%08x)\n", ret, GetLastError());
3134     return ret;
3135 }
3136
3137 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
3138  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3139  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3140 {
3141     BOOL ret;
3142
3143     __TRY
3144     {
3145         const CRYPT_BIT_BLOB *blob = pvStructInfo;
3146         DWORD bytesNeeded, lenBytes, dataBytes;
3147         BYTE unusedBits;
3148
3149         /* yep, MS allows cUnusedBits to be >= 8 */
3150         if (!blob->cUnusedBits)
3151         {
3152             dataBytes = blob->cbData;
3153             unusedBits = 0;
3154         }
3155         else if (blob->cbData * 8 > blob->cUnusedBits)
3156         {
3157             dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
3158             unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
3159              blob->cUnusedBits;
3160         }
3161         else
3162         {
3163             dataBytes = 0;
3164             unusedBits = 0;
3165         }
3166         CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
3167         bytesNeeded = 1 + lenBytes + dataBytes + 1;
3168         if (!pbEncoded)
3169         {
3170             *pcbEncoded = bytesNeeded;
3171             ret = TRUE;
3172         }
3173         else
3174         {
3175             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
3176              pcbEncoded, bytesNeeded)))
3177             {
3178                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3179                     pbEncoded = *(BYTE **)pbEncoded;
3180                 *pbEncoded++ = ASN_BITSTRING;
3181                 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
3182                 pbEncoded += lenBytes;
3183                 *pbEncoded++ = unusedBits;
3184                 if (dataBytes)
3185                 {
3186                     BYTE mask = 0xff << unusedBits;
3187
3188                     if (dataBytes > 1)
3189                     {
3190                         memcpy(pbEncoded, blob->pbData, dataBytes - 1);
3191                         pbEncoded += dataBytes - 1;
3192                     }
3193                     *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
3194                 }
3195             }
3196         }
3197     }
3198     __EXCEPT_PAGE_FAULT
3199     {
3200         SetLastError(STATUS_ACCESS_VIOLATION);
3201         ret = FALSE;
3202     }
3203     __ENDTRY
3204     return ret;
3205 }
3206
3207 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
3208  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3209  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3210 {
3211     BOOL ret;
3212
3213     __TRY
3214     {
3215         const CRYPT_BIT_BLOB *blob = pvStructInfo;
3216         CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
3217
3218         ret = TRUE;
3219         if (newBlob.cbData)
3220         {
3221             newBlob.pbData = CryptMemAlloc(newBlob.cbData);
3222             if (newBlob.pbData)
3223             {
3224                 DWORD i;
3225
3226                 for (i = 0; i < newBlob.cbData; i++)
3227                     newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
3228             }
3229             else
3230                 ret = FALSE;
3231         }
3232         if (ret)
3233             ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
3234              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3235         CryptMemFree(newBlob.pbData);
3236     }
3237     __EXCEPT_PAGE_FAULT
3238     {
3239         SetLastError(STATUS_ACCESS_VIOLATION);
3240         ret = FALSE;
3241     }
3242     __ENDTRY
3243     return ret;
3244 }
3245
3246 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
3247  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3248  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3249 {
3250     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
3251
3252     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
3253      &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3254 }
3255
3256 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
3257  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3258  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3259 {
3260     BOOL ret;
3261
3262     __TRY
3263     {
3264         DWORD significantBytes, lenBytes, bytesNeeded;
3265         BYTE padByte = 0;
3266         BOOL pad = FALSE;
3267         const CRYPT_INTEGER_BLOB *blob = pvStructInfo;
3268
3269         significantBytes = blob->cbData;
3270         if (significantBytes)
3271         {
3272             if (blob->pbData[significantBytes - 1] & 0x80)
3273             {
3274                 /* negative, lop off leading (little-endian) 0xffs */
3275                 for (; significantBytes > 0 &&
3276                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
3277                     ;
3278                 if (blob->pbData[significantBytes - 1] < 0x80)
3279                 {
3280                     padByte = 0xff;
3281                     pad = TRUE;
3282                 }
3283             }
3284             else
3285             {
3286                 /* positive, lop off leading (little-endian) zeroes */
3287                 for (; significantBytes > 0 &&
3288                  !blob->pbData[significantBytes - 1]; significantBytes--)
3289                     ;
3290                 if (significantBytes == 0)
3291                     significantBytes = 1;
3292                 if (blob->pbData[significantBytes - 1] > 0x7f)
3293                 {
3294                     padByte = 0;
3295                     pad = TRUE;
3296                 }
3297             }
3298         }
3299         if (pad)
3300             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
3301         else
3302             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
3303         bytesNeeded = 1 + lenBytes + significantBytes;
3304         if (pad)
3305             bytesNeeded++;
3306         if (!pbEncoded)
3307         {
3308             *pcbEncoded = bytesNeeded;
3309             ret = TRUE;
3310         }
3311         else
3312         {
3313             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
3314              pcbEncoded, bytesNeeded)))
3315             {
3316                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3317                     pbEncoded = *(BYTE **)pbEncoded;
3318                 *pbEncoded++ = ASN_INTEGER;
3319                 if (pad)
3320                 {
3321                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
3322                     pbEncoded += lenBytes;
3323                     *pbEncoded++ = padByte;
3324                 }
3325                 else
3326                 {
3327                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
3328                     pbEncoded += lenBytes;
3329                 }
3330                 for (; significantBytes > 0; significantBytes--)
3331                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
3332             }
3333         }
3334     }
3335     __EXCEPT_PAGE_FAULT
3336     {
3337         SetLastError(STATUS_ACCESS_VIOLATION);
3338         ret = FALSE;
3339     }
3340     __ENDTRY
3341     return ret;
3342 }
3343
3344 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
3345  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3346  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3347 {
3348     BOOL ret;
3349
3350     __TRY
3351     {
3352         DWORD significantBytes, lenBytes, bytesNeeded;
3353         BOOL pad = FALSE;
3354         const CRYPT_INTEGER_BLOB *blob = pvStructInfo;
3355
3356         significantBytes = blob->cbData;
3357         if (significantBytes)
3358         {
3359             /* positive, lop off leading (little-endian) zeroes */
3360             for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
3361              significantBytes--)
3362                 ;
3363             if (significantBytes == 0)
3364                 significantBytes = 1;
3365             if (blob->pbData[significantBytes - 1] > 0x7f)
3366                 pad = TRUE;
3367         }
3368         if (pad)
3369             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
3370         else
3371             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
3372         bytesNeeded = 1 + lenBytes + significantBytes;
3373         if (pad)
3374             bytesNeeded++;
3375         if (!pbEncoded)
3376         {
3377             *pcbEncoded = bytesNeeded;
3378             ret = TRUE;
3379         }
3380         else
3381         {
3382             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
3383              pcbEncoded, bytesNeeded)))
3384             {
3385                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3386                     pbEncoded = *(BYTE **)pbEncoded;
3387                 *pbEncoded++ = ASN_INTEGER;
3388                 if (pad)
3389                 {
3390                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
3391                     pbEncoded += lenBytes;
3392                     *pbEncoded++ = 0;
3393                 }
3394                 else
3395                 {
3396                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
3397                     pbEncoded += lenBytes;
3398                 }
3399                 for (; significantBytes > 0; significantBytes--)
3400                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
3401             }
3402         }
3403     }
3404     __EXCEPT_PAGE_FAULT
3405     {
3406         SetLastError(STATUS_ACCESS_VIOLATION);
3407         ret = FALSE;
3408     }
3409     __ENDTRY
3410     return ret;
3411 }
3412
3413 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
3414  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3415  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3416 {
3417     CRYPT_INTEGER_BLOB blob;
3418     BOOL ret;
3419
3420     /* Encode as an unsigned integer, then change the tag to enumerated */
3421     blob.cbData = sizeof(DWORD);
3422     blob.pbData = (BYTE *)pvStructInfo;
3423     ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
3424      X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3425     if (ret && pbEncoded)
3426     {
3427         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3428             pbEncoded = *(BYTE **)pbEncoded;
3429         pbEncoded[0] = ASN_ENUMERATED;
3430     }
3431     return ret;
3432 }
3433
3434 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
3435  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3436  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3437 {
3438     BOOL ret;
3439
3440     __TRY
3441     {
3442         SYSTEMTIME sysTime;
3443         /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
3444          * temporary buffer because the output buffer is not NULL-terminated.
3445          */
3446         char buf[16];
3447         static const DWORD bytesNeeded = sizeof(buf) - 1;
3448
3449         if (!pbEncoded)
3450         {
3451             *pcbEncoded = bytesNeeded;
3452             ret = TRUE;
3453         }
3454         else
3455         {
3456             /* Sanity check the year, this is a two-digit year format */
3457             ret = FileTimeToSystemTime(pvStructInfo, &sysTime);
3458             if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
3459             {
3460                 SetLastError(CRYPT_E_BAD_ENCODE);
3461                 ret = FALSE;
3462             }
3463             if (ret)
3464             {
3465                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
3466                  pbEncoded, pcbEncoded, bytesNeeded)))
3467                 {
3468                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3469                         pbEncoded = *(BYTE **)pbEncoded;
3470                     buf[0] = ASN_UTCTIME;
3471                     buf[1] = bytesNeeded - 2;
3472                     snprintf(buf + 2, sizeof(buf) - 2,
3473                      "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
3474                      sysTime.wYear - 2000 : sysTime.wYear - 1900,
3475                      sysTime.wMonth, sysTime.wDay, sysTime.wHour,
3476                      sysTime.wMinute, sysTime.wSecond);
3477                     memcpy(pbEncoded, buf, bytesNeeded);
3478                 }
3479             }
3480         }
3481     }
3482     __EXCEPT_PAGE_FAULT
3483     {
3484         SetLastError(STATUS_ACCESS_VIOLATION);
3485         ret = FALSE;
3486     }
3487     __ENDTRY
3488     return ret;
3489 }
3490
3491 static BOOL CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
3492  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3493  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3494 {
3495     BOOL ret;
3496
3497     __TRY
3498     {
3499         SYSTEMTIME sysTime;
3500         /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
3501          * temporary buffer because the output buffer is not NULL-terminated.
3502          */
3503         char buf[18];
3504         static const DWORD bytesNeeded = sizeof(buf) - 1;
3505
3506         if (!pbEncoded)
3507         {
3508             *pcbEncoded = bytesNeeded;
3509             ret = TRUE;
3510         }
3511         else
3512         {
3513             ret = FileTimeToSystemTime(pvStructInfo, &sysTime);
3514             if (ret)
3515                 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
3516                  pcbEncoded, bytesNeeded);
3517             if (ret)
3518             {
3519                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3520                     pbEncoded = *(BYTE **)pbEncoded;
3521                 buf[0] = ASN_GENERALTIME;
3522                 buf[1] = bytesNeeded - 2;
3523                 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
3524                  sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
3525                  sysTime.wMinute, sysTime.wSecond);
3526                 memcpy(pbEncoded, buf, bytesNeeded);
3527             }
3528         }
3529     }
3530     __EXCEPT_PAGE_FAULT
3531     {
3532         SetLastError(STATUS_ACCESS_VIOLATION);
3533         ret = FALSE;
3534     }
3535     __ENDTRY
3536     return ret;
3537 }
3538
3539 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
3540  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3541  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3542 {
3543     BOOL ret;
3544
3545     __TRY
3546     {
3547         SYSTEMTIME sysTime;
3548
3549         /* Check the year, if it's in the UTCTime range call that encode func */
3550         if (!FileTimeToSystemTime(pvStructInfo, &sysTime))
3551             return FALSE;
3552         if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
3553             ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
3554              pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3555         else
3556             ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
3557              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
3558              pcbEncoded);
3559     }
3560     __EXCEPT_PAGE_FAULT
3561     {
3562         SetLastError(STATUS_ACCESS_VIOLATION);
3563         ret = FALSE;
3564     }
3565     __ENDTRY
3566     return ret;
3567 }
3568
3569 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
3570  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3571  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3572 {
3573     BOOL ret;
3574
3575     __TRY
3576     {
3577         DWORD bytesNeeded, dataLen, lenBytes, i;
3578         const CRYPT_SEQUENCE_OF_ANY *seq = pvStructInfo;
3579
3580         for (i = 0, dataLen = 0; i < seq->cValue; i++)
3581             dataLen += seq->rgValue[i].cbData;
3582         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
3583         bytesNeeded = 1 + lenBytes + dataLen;
3584         if (!pbEncoded)
3585         {
3586             *pcbEncoded = bytesNeeded;
3587             ret = TRUE;
3588         }
3589         else
3590         {
3591             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
3592              pcbEncoded, bytesNeeded)))
3593             {
3594                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3595                     pbEncoded = *(BYTE **)pbEncoded;
3596                 *pbEncoded++ = ASN_SEQUENCEOF;
3597                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
3598                 pbEncoded += lenBytes;
3599                 for (i = 0; i < seq->cValue; i++)
3600                 {
3601                     memcpy(pbEncoded, seq->rgValue[i].pbData,
3602                      seq->rgValue[i].cbData);
3603                     pbEncoded += seq->rgValue[i].cbData;
3604                 }
3605             }
3606         }
3607     }
3608     __EXCEPT_PAGE_FAULT
3609     {
3610         SetLastError(STATUS_ACCESS_VIOLATION);
3611         ret = FALSE;
3612     }
3613     __ENDTRY
3614     return ret;
3615 }
3616
3617 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
3618  BYTE *pbEncoded, DWORD *pcbEncoded)
3619 {
3620     BOOL ret = TRUE;
3621     struct AsnEncodeSequenceItem items[3] = { { 0 } };
3622     struct AsnConstructedItem constructed = { 0 };
3623     struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
3624     DWORD cItem = 0, cSwapped = 0;
3625
3626     switch (distPoint->DistPointName.dwDistPointNameChoice)
3627     {
3628     case CRL_DIST_POINT_NO_NAME:
3629         /* do nothing */
3630         break;
3631     case CRL_DIST_POINT_FULL_NAME:
3632         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
3633         swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
3634         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
3635         constructed.tag = 0;
3636         constructed.pvStructInfo = &swapped[cSwapped];
3637         constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
3638         items[cItem].pvStructInfo = &constructed;
3639         items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
3640         cSwapped++;
3641         cItem++;
3642         break;
3643     case CRL_DIST_POINT_ISSUER_RDN_NAME:
3644         FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
3645         ret = FALSE;
3646         break;
3647     default:
3648         ret = FALSE;
3649     }
3650     if (ret && distPoint->ReasonFlags.cbData)
3651     {
3652         swapped[cSwapped].tag = ASN_CONTEXT | 1;
3653         swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
3654         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
3655         items[cItem].pvStructInfo = &swapped[cSwapped];
3656         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3657         cSwapped++;
3658         cItem++;
3659     }
3660     if (ret && distPoint->CRLIssuer.cAltEntry)
3661     {
3662         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
3663         swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
3664         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
3665         items[cItem].pvStructInfo = &swapped[cSwapped];
3666         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3667         cSwapped++;
3668         cItem++;
3669     }
3670     if (ret)
3671         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
3672          pbEncoded, pcbEncoded);
3673     return ret;
3674 }
3675
3676 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
3677  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3678  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3679 {
3680     BOOL ret;
3681
3682     __TRY
3683     {
3684         const CRL_DIST_POINTS_INFO *info = pvStructInfo;
3685
3686         if (!info->cDistPoint)
3687         {
3688             SetLastError(E_INVALIDARG);
3689             ret = FALSE;
3690         }
3691         else
3692         {
3693             DWORD bytesNeeded, dataLen, lenBytes, i;
3694
3695             ret = TRUE;
3696             for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
3697             {
3698                 DWORD len;
3699
3700                 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
3701                  &len);
3702                 if (ret)
3703                     dataLen += len;
3704                 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
3705                 {
3706                     /* Have to propagate index of failing character */
3707                     *pcbEncoded = len;
3708                 }
3709             }
3710             if (ret)
3711             {
3712                 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
3713                 bytesNeeded = 1 + lenBytes + dataLen;
3714                 if (!pbEncoded)
3715                 {
3716                     *pcbEncoded = bytesNeeded;
3717                     ret = TRUE;
3718                 }
3719                 else
3720                 {
3721                     if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
3722                      pbEncoded, pcbEncoded, bytesNeeded)))
3723                     {
3724                         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3725                             pbEncoded = *(BYTE **)pbEncoded;
3726                         *pbEncoded++ = ASN_SEQUENCEOF;
3727                         CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
3728                         pbEncoded += lenBytes;
3729                         for (i = 0; ret && i < info->cDistPoint; i++)
3730                         {
3731                             DWORD len = dataLen;
3732
3733                             ret = CRYPT_AsnEncodeDistPoint(
3734                              &info->rgDistPoint[i], pbEncoded, &len);
3735                             if (ret)
3736                             {
3737                                 pbEncoded += len;
3738                                 dataLen -= len;
3739                             }
3740                         }
3741                     }
3742                 }
3743             }
3744         }
3745     }
3746     __EXCEPT_PAGE_FAULT
3747     {
3748         SetLastError(STATUS_ACCESS_VIOLATION);
3749         ret = FALSE;
3750     }
3751     __ENDTRY
3752     return ret;
3753 }
3754
3755 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
3756  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3757  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3758 {
3759     BOOL ret;
3760
3761     __TRY
3762     {
3763         const CERT_ENHKEY_USAGE *usage = pvStructInfo;
3764         DWORD bytesNeeded = 0, lenBytes, size, i;
3765
3766         ret = TRUE;
3767         for (i = 0; ret && i < usage->cUsageIdentifier; i++)
3768         {
3769             ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
3770              usage->rgpszUsageIdentifier[i],
3771              dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
3772             if (ret)
3773                 bytesNeeded += size;
3774         }
3775         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
3776         bytesNeeded += 1 + lenBytes;
3777         if (ret)
3778         {
3779             if (!pbEncoded)
3780                 *pcbEncoded = bytesNeeded;
3781             else
3782             {
3783                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
3784                  pbEncoded, pcbEncoded, bytesNeeded)))
3785                 {
3786                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
3787                         pbEncoded = *(BYTE **)pbEncoded;
3788                     *pbEncoded++ = ASN_SEQUENCEOF;
3789                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
3790                      &lenBytes);
3791                     pbEncoded += lenBytes;
3792                     for (i = 0; ret && i < usage->cUsageIdentifier; i++)
3793                     {
3794                         size = bytesNeeded;
3795                         ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
3796                          usage->rgpszUsageIdentifier[i],
3797                          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
3798                          &size);
3799                         if (ret)
3800                         {
3801                             pbEncoded += size;
3802                             bytesNeeded -= size;
3803                         }
3804                     }
3805                 }
3806             }
3807         }
3808     }
3809     __EXCEPT_PAGE_FAULT
3810     {
3811         SetLastError(STATUS_ACCESS_VIOLATION);
3812         ret = FALSE;
3813     }
3814     __ENDTRY
3815     return ret;
3816 }
3817
3818 static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType,
3819  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3820  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3821 {
3822     BOOL ret;
3823
3824     __TRY
3825     {
3826         const CRL_ISSUING_DIST_POINT *point = pvStructInfo;
3827         struct AsnEncodeSequenceItem items[6] = { { 0 } };
3828         struct AsnConstructedItem constructed = { 0 };
3829         struct AsnEncodeTagSwappedItem swapped[5] = { { 0 } };
3830         DWORD cItem = 0, cSwapped = 0;
3831
3832         ret = TRUE;
3833         switch (point->DistPointName.dwDistPointNameChoice)
3834         {
3835         case CRL_DIST_POINT_NO_NAME:
3836             /* do nothing */
3837             break;
3838         case CRL_DIST_POINT_FULL_NAME:
3839             swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
3840             swapped[cSwapped].pvStructInfo = &point->DistPointName.u.FullName;
3841             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
3842             constructed.tag = 0;
3843             constructed.pvStructInfo = &swapped[cSwapped];
3844             constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
3845             items[cItem].pvStructInfo = &constructed;
3846             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
3847             cSwapped++;
3848             cItem++;
3849             break;
3850         default:
3851             SetLastError(E_INVALIDARG);
3852             ret = FALSE;
3853         }
3854         if (ret && point->fOnlyContainsUserCerts)
3855         {
3856             swapped[cSwapped].tag = ASN_CONTEXT | 1;
3857             swapped[cSwapped].pvStructInfo = &point->fOnlyContainsUserCerts;
3858             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
3859             items[cItem].pvStructInfo = &swapped[cSwapped];
3860             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3861             cSwapped++;
3862             cItem++;
3863         }
3864         if (ret && point->fOnlyContainsCACerts)
3865         {
3866             swapped[cSwapped].tag = ASN_CONTEXT | 2;
3867             swapped[cSwapped].pvStructInfo = &point->fOnlyContainsCACerts;
3868             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
3869             items[cItem].pvStructInfo = &swapped[cSwapped];
3870             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3871             cSwapped++;
3872             cItem++;
3873         }
3874         if (ret && point->OnlySomeReasonFlags.cbData)
3875         {
3876             swapped[cSwapped].tag = ASN_CONTEXT | 3;
3877             swapped[cSwapped].pvStructInfo = &point->OnlySomeReasonFlags;
3878             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
3879             items[cItem].pvStructInfo = &swapped[cSwapped];
3880             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3881             cSwapped++;
3882             cItem++;
3883         }
3884         if (ret && point->fIndirectCRL)
3885         {
3886             swapped[cSwapped].tag = ASN_CONTEXT | 4;
3887             swapped[cSwapped].pvStructInfo = &point->fIndirectCRL;
3888             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
3889             items[cItem].pvStructInfo = &swapped[cSwapped];
3890             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3891             cSwapped++;
3892             cItem++;
3893         }
3894         if (ret)
3895             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
3896              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
3897     }
3898     __EXCEPT_PAGE_FAULT
3899     {
3900         SetLastError(STATUS_ACCESS_VIOLATION);
3901         ret = FALSE;
3902     }
3903     __ENDTRY
3904     return ret;
3905 }
3906
3907 static BOOL CRYPT_AsnEncodeGeneralSubtree(DWORD dwCertEncodingType,
3908  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3909  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3910 {
3911     BOOL ret;
3912     const CERT_GENERAL_SUBTREE *subtree = pvStructInfo;
3913     struct AsnEncodeSequenceItem items[3] = {
3914      { &subtree->Base, CRYPT_AsnEncodeAltNameEntry, 0 },
3915      { 0 }
3916     };
3917     struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
3918     DWORD cItem = 1, cSwapped = 0;
3919
3920     if (subtree->dwMinimum)
3921     {
3922         swapped[cSwapped].tag = ASN_CONTEXT | 0;
3923         swapped[cSwapped].pvStructInfo = &subtree->dwMinimum;
3924         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInt;
3925         items[cItem].pvStructInfo = &swapped[cSwapped];
3926         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3927         cSwapped++;
3928         cItem++;
3929     }
3930     if (subtree->fMaximum)
3931     {
3932         swapped[cSwapped].tag = ASN_CONTEXT | 1;
3933         swapped[cSwapped].pvStructInfo = &subtree->dwMaximum;
3934         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInt;
3935         items[cItem].pvStructInfo = &swapped[cSwapped];
3936         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3937         cSwapped++;
3938         cItem++;
3939     }
3940     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem, dwFlags,
3941      pEncodePara, pbEncoded, pcbEncoded);
3942     return ret;
3943 }
3944
3945 static BOOL WINAPI CRYPT_AsnEncodeNameConstraints(DWORD dwCertEncodingType,
3946  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
3947  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
3948 {
3949     BOOL ret = FALSE;
3950     CRYPT_BLOB_ARRAY permitted = { 0, NULL }, excluded = { 0, NULL };
3951
3952     TRACE("%p\n", pvStructInfo);
3953
3954     __TRY
3955     {
3956         const CERT_NAME_CONSTRAINTS_INFO *constraints = pvStructInfo;
3957         struct AsnEncodeSequenceItem items[2] = { { 0 } };
3958         struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
3959         DWORD i, cItem = 0, cSwapped = 0;
3960
3961         ret = TRUE;
3962         if (constraints->cPermittedSubtree)
3963         {
3964             permitted.rgBlob = CryptMemAlloc(
3965              constraints->cPermittedSubtree * sizeof(CRYPT_DER_BLOB));
3966             if (permitted.rgBlob)
3967             {
3968                 permitted.cBlob = constraints->cPermittedSubtree;
3969                 memset(permitted.rgBlob, 0,
3970                  permitted.cBlob * sizeof(CRYPT_DER_BLOB));
3971                 for (i = 0; ret && i < permitted.cBlob; i++)
3972                     ret = CRYPT_AsnEncodeGeneralSubtree(dwCertEncodingType,
3973                      NULL, &constraints->rgPermittedSubtree[i],
3974                      CRYPT_ENCODE_ALLOC_FLAG, NULL,
3975                      (BYTE *)&permitted.rgBlob[i].pbData,
3976                      &permitted.rgBlob[i].cbData);
3977                 if (ret)
3978                 {
3979                     swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
3980                     swapped[cSwapped].pvStructInfo = &permitted;
3981                     swapped[cSwapped].encodeFunc = CRYPT_DEREncodeSet;
3982                     items[cItem].pvStructInfo = &swapped[cSwapped];
3983                     items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
3984                     cSwapped++;
3985                     cItem++;
3986                 }
3987             }
3988             else
3989                 ret = FALSE;
3990         }
3991         if (constraints->cExcludedSubtree)
3992         {
3993             excluded.rgBlob = CryptMemAlloc(
3994              constraints->cExcludedSubtree * sizeof(CRYPT_DER_BLOB));
3995             if (excluded.rgBlob)
3996             {
3997                 excluded.cBlob = constraints->cExcludedSubtree;
3998                 memset(excluded.rgBlob, 0,
3999                  excluded.cBlob * sizeof(CRYPT_DER_BLOB));
4000                 for (i = 0; ret && i < excluded.cBlob; i++)
4001                     ret = CRYPT_AsnEncodeGeneralSubtree(dwCertEncodingType,
4002                      NULL, &constraints->rgExcludedSubtree[i],
4003                      CRYPT_ENCODE_ALLOC_FLAG, NULL,
4004                      (BYTE *)&excluded.rgBlob[i].pbData,
4005                      &excluded.rgBlob[i].cbData);
4006                 if (ret)
4007                 {
4008                     swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
4009                     swapped[cSwapped].pvStructInfo = &excluded;
4010                     swapped[cSwapped].encodeFunc = CRYPT_DEREncodeSet;
4011                     items[cItem].pvStructInfo = &swapped[cSwapped];
4012                     items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
4013                     cSwapped++;
4014                     cItem++;
4015                 }
4016             }
4017             else
4018                 ret = FALSE;
4019         }
4020         if (ret)
4021             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
4022              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
4023         for (i = 0; i < permitted.cBlob; i++)
4024             LocalFree(permitted.rgBlob[i].pbData);
4025         for (i = 0; i < excluded.cBlob; i++)
4026             LocalFree(excluded.rgBlob[i].pbData);
4027     }
4028     __EXCEPT_PAGE_FAULT
4029     {
4030         SetLastError(STATUS_ACCESS_VIOLATION);
4031     }
4032     __ENDTRY
4033     CryptMemFree(permitted.rgBlob);
4034     CryptMemFree(excluded.rgBlob);
4035     TRACE("returning %d\n", ret);
4036     return ret;
4037 }
4038
4039 static BOOL WINAPI CRYPT_AsnEncodeIssuerSerialNumber(
4040  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
4041  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
4042  DWORD *pcbEncoded)
4043 {
4044     BOOL ret;
4045     const CERT_ISSUER_SERIAL_NUMBER *issuerSerial = pvStructInfo;
4046     struct AsnEncodeSequenceItem items[] = {
4047      { &issuerSerial->Issuer,       CRYPT_CopyEncodedBlob, 0 },
4048      { &issuerSerial->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
4049     };
4050
4051     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
4052      sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
4053      pcbEncoded);
4054     return ret;
4055 }
4056
4057 static BOOL WINAPI CRYPT_AsnEncodePKCSSignerInfo(DWORD dwCertEncodingType,
4058  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
4059  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
4060 {
4061     BOOL ret = FALSE;
4062
4063     if (!(dwCertEncodingType & PKCS_7_ASN_ENCODING))
4064     {
4065         SetLastError(E_INVALIDARG);
4066         return FALSE;
4067     }
4068
4069     __TRY
4070     {
4071         const CMSG_SIGNER_INFO *info = pvStructInfo;
4072
4073         if (!info->Issuer.cbData)
4074             SetLastError(E_INVALIDARG);
4075         else
4076         {
4077             struct AsnEncodeSequenceItem items[7] = {
4078              { &info->dwVersion,     CRYPT_AsnEncodeInt, 0 },
4079              { &info->Issuer,        CRYPT_AsnEncodeIssuerSerialNumber, 0 },
4080              { &info->HashAlgorithm, CRYPT_AsnEncodeAlgorithmIdWithNullParams,
4081                0 },
4082             };
4083             struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
4084             DWORD cItem = 3, cSwapped = 0;
4085
4086             if (info->AuthAttrs.cAttr)
4087             {
4088                 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
4089                 swapped[cSwapped].pvStructInfo = &info->AuthAttrs;
4090                 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodePKCSAttributes;
4091                 items[cItem].pvStructInfo = &swapped[cSwapped];
4092                 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
4093                 cSwapped++;
4094                 cItem++;
4095             }
4096             items[cItem].pvStructInfo = &info->HashEncryptionAlgorithm;
4097             items[cItem].encodeFunc = CRYPT_AsnEncodeAlgorithmIdWithNullParams;
4098             cItem++;
4099             items[cItem].pvStructInfo = &info->EncryptedHash;
4100             items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
4101             cItem++;
4102             if (info->UnauthAttrs.cAttr)
4103             {
4104                 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
4105                 swapped[cSwapped].pvStructInfo = &info->UnauthAttrs;
4106                 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodePKCSAttributes;
4107                 items[cItem].pvStructInfo = &swapped[cSwapped];
4108                 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
4109                 cSwapped++;
4110                 cItem++;
4111             }
4112             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
4113              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
4114         }
4115     }
4116     __EXCEPT_PAGE_FAULT
4117     {
4118         SetLastError(STATUS_ACCESS_VIOLATION);
4119     }
4120     __ENDTRY
4121     return ret;
4122 }
4123
4124 static BOOL WINAPI CRYPT_AsnEncodeCMSSignerInfo(DWORD dwCertEncodingType,
4125  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
4126  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
4127 {
4128     BOOL ret = FALSE;
4129
4130     if (!(dwCertEncodingType & PKCS_7_ASN_ENCODING))
4131     {
4132         SetLastError(E_INVALIDARG);
4133         return FALSE;
4134     }
4135
4136     __TRY
4137     {
4138         const CMSG_CMS_SIGNER_INFO *info = pvStructInfo;
4139
4140         if (info->SignerId.dwIdChoice != CERT_ID_ISSUER_SERIAL_NUMBER &&
4141          info->SignerId.dwIdChoice != CERT_ID_KEY_IDENTIFIER)
4142             SetLastError(E_INVALIDARG);
4143         else if (info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER &&
4144          !info->SignerId.u.IssuerSerialNumber.Issuer.cbData)
4145             SetLastError(E_INVALIDARG);
4146         else
4147         {
4148             struct AsnEncodeSequenceItem items[7] = {
4149              { &info->dwVersion,     CRYPT_AsnEncodeInt, 0 },
4150             };
4151             struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
4152             DWORD cItem = 1, cSwapped = 0;
4153
4154             if (info->SignerId.dwIdChoice == CERT_ID_ISSUER_SERIAL_NUMBER)
4155             {
4156                 items[cItem].pvStructInfo =
4157                  &info->SignerId.u.IssuerSerialNumber.Issuer;
4158                 items[cItem].encodeFunc =
4159                  CRYPT_AsnEncodeIssuerSerialNumber;
4160                 cItem++;
4161             }
4162             else
4163             {
4164                 swapped[cSwapped].tag = ASN_CONTEXT | 0;
4165                 swapped[cSwapped].pvStructInfo = &info->SignerId.u.KeyId;
4166                 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeOctets;
4167                 items[cItem].pvStructInfo = &swapped[cSwapped];
4168                 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
4169                 cSwapped++;
4170                 cItem++;
4171             }
4172             items[cItem].pvStructInfo = &info->HashAlgorithm;
4173             items[cItem].encodeFunc = CRYPT_AsnEncodeAlgorithmIdWithNullParams;
4174             cItem++;
4175             if (info->AuthAttrs.cAttr)
4176             {
4177                 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
4178                 swapped[cSwapped].pvStructInfo = &info->AuthAttrs;
4179                 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodePKCSAttributes;
4180                 items[cItem].pvStructInfo = &swapped[cSwapped];
4181                 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
4182                 cSwapped++;
4183                 cItem++;
4184             }
4185             items[cItem].pvStructInfo = &info->HashEncryptionAlgorithm;
4186             items[cItem].encodeFunc = CRYPT_AsnEncodeAlgorithmIdWithNullParams;
4187             cItem++;
4188             items[cItem].pvStructInfo = &info->EncryptedHash;
4189             items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
4190             cItem++;
4191             if (info->UnauthAttrs.cAttr)
4192             {
4193                 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 1;
4194                 swapped[cSwapped].pvStructInfo = &info->UnauthAttrs;
4195                 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodePKCSAttributes;
4196                 items[cItem].pvStructInfo = &swapped[cSwapped];
4197                 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
4198                 cSwapped++;
4199                 cItem++;
4200             }
4201             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
4202              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
4203         }
4204     }
4205     __EXCEPT_PAGE_FAULT
4206     {
4207         SetLastError(STATUS_ACCESS_VIOLATION);
4208     }
4209     __ENDTRY
4210     return ret;
4211 }
4212
4213 BOOL CRYPT_AsnEncodeCMSSignedInfo(CRYPT_SIGNED_INFO *signedInfo, void *pvData,
4214  DWORD *pcbData)
4215 {
4216     struct AsnEncodeSequenceItem items[7] = {
4217      { &signedInfo->version, CRYPT_AsnEncodeInt, 0 },
4218     };
4219     struct DERSetDescriptor digestAlgorithmsSet = { 0 }, certSet = { 0 };
4220     struct DERSetDescriptor crlSet = { 0 }, signerSet = { 0 };
4221     struct AsnEncodeTagSwappedItem swapped[2] = { { 0 } };
4222     DWORD cItem = 1, cSwapped = 0;
4223     BOOL ret = TRUE;
4224
4225     if (signedInfo->cSignerInfo)
4226     {
4227         digestAlgorithmsSet.cItems = signedInfo->cSignerInfo;
4228         digestAlgorithmsSet.items = signedInfo->rgSignerInfo;
4229         digestAlgorithmsSet.itemSize = sizeof(CMSG_CMS_SIGNER_INFO);
4230         digestAlgorithmsSet.itemOffset =
4231          offsetof(CMSG_CMS_SIGNER_INFO, HashAlgorithm);
4232         digestAlgorithmsSet.encode = CRYPT_AsnEncodeAlgorithmIdWithNullParams;
4233         items[cItem].pvStructInfo = &digestAlgorithmsSet;
4234         items[cItem].encodeFunc = CRYPT_DEREncodeItemsAsSet;
4235         cItem++;
4236     }
4237     items[cItem].pvStructInfo = &signedInfo->content;
4238     items[cItem].encodeFunc = CRYPT_AsnEncodePKCSContentInfoInternal;
4239     cItem++;
4240     if (signedInfo->cCertEncoded)
4241     {
4242         certSet.cItems = signedInfo->cCertEncoded;
4243         certSet.items = signedInfo->rgCertEncoded;
4244         certSet.itemSize = sizeof(CERT_BLOB);
4245         certSet.itemOffset = 0;
4246         certSet.encode = CRYPT_CopyEncodedBlob;
4247         swapped[cSwapped].tag = ASN_CONSTRUCTOR | ASN_CONTEXT | 0;
4248         swapped[cSwapped].pvStructInfo = &certSet;
4249         swapped[cSwapped].encodeFunc = CRYPT_DEREncodeItemsAsSet;
4250         items[cItem].pvStructInfo = &swapped[cSwapped];
4251         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
4252         cSwapped++;
4253         cItem++;
4254     }
4255     if (signedInfo->cCrlEncoded)
4256     {
4257         crlSet.cItems = signedInfo->cCrlEncoded;
4258         crlSet.items = signedInfo->rgCrlEncoded;
4259         crlSet.itemSize = sizeof(CRL_BLOB);
4260         crlSet.itemOffset = 0;
4261         crlSet.encode = CRYPT_CopyEncodedBlob;
4262         swapped[cSwapped].tag = ASN_CONSTRUCTOR | ASN_CONTEXT | 1;
4263         swapped[cSwapped].pvStructInfo = &crlSet;
4264         swapped[cSwapped].encodeFunc = CRYPT_DEREncodeItemsAsSet;
4265         items[cItem].pvStructInfo = &swapped[cSwapped];
4266         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
4267         cSwapped++;
4268         cItem++;
4269     }
4270     if (ret && signedInfo->cSignerInfo)
4271     {
4272         signerSet.cItems = signedInfo->cSignerInfo;
4273         signerSet.items = signedInfo->rgSignerInfo;
4274         signerSet.itemSize = sizeof(CMSG_CMS_SIGNER_INFO);
4275         signerSet.itemOffset = 0;
4276         signerSet.encode = CRYPT_AsnEncodeCMSSignerInfo;
4277         items[cItem].pvStructInfo = &signerSet;
4278         items[cItem].encodeFunc = CRYPT_DEREncodeItemsAsSet;
4279         cItem++;
4280     }
4281     if (ret)
4282         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING | PKCS_7_ASN_ENCODING,
4283          items, cItem, 0, NULL, pvData, pcbData);
4284
4285     return ret;
4286 }
4287
4288 static CryptEncodeObjectExFunc CRYPT_GetBuiltinEncoder(DWORD dwCertEncodingType,
4289  LPCSTR lpszStructType)
4290 {
4291     CryptEncodeObjectExFunc encodeFunc = NULL;
4292
4293     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
4294      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
4295     {
4296         SetLastError(ERROR_FILE_NOT_FOUND);
4297         return NULL;
4298     }
4299
4300     if (!HIWORD(lpszStructType))
4301     {
4302         switch (LOWORD(lpszStructType))
4303         {
4304         case LOWORD(X509_CERT):
4305             encodeFunc = CRYPT_AsnEncodeCert;
4306             break;
4307         case LOWORD(X509_CERT_TO_BE_SIGNED):
4308             encodeFunc = CRYPT_AsnEncodeCertInfo;
4309             break;
4310         case LOWORD(X509_CERT_CRL_TO_BE_SIGNED):
4311             encodeFunc = CRYPT_AsnEncodeCRLInfo;
4312             break;
4313         case LOWORD(X509_EXTENSIONS):
4314             encodeFunc = CRYPT_AsnEncodeExtensions;
4315             break;
4316         case LOWORD(X509_NAME_VALUE):
4317             encodeFunc = CRYPT_AsnEncodeNameValue;
4318             break;
4319         case LOWORD(X509_NAME):
4320             encodeFunc = CRYPT_AsnEncodeName;
4321             break;
4322         case LOWORD(X509_PUBLIC_KEY_INFO):
4323             encodeFunc = CRYPT_AsnEncodePubKeyInfo;
4324             break;
4325         case LOWORD(X509_AUTHORITY_KEY_ID):
4326             encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
4327             break;
4328         case LOWORD(X509_ALTERNATE_NAME):
4329             encodeFunc = CRYPT_AsnEncodeAltName;
4330             break;
4331         case LOWORD(X509_BASIC_CONSTRAINTS):
4332             encodeFunc = CRYPT_AsnEncodeBasicConstraints;
4333             break;
4334         case LOWORD(X509_BASIC_CONSTRAINTS2):
4335             encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
4336             break;
4337         case LOWORD(X509_CERT_POLICIES):
4338             encodeFunc = CRYPT_AsnEncodeCertPolicies;
4339             break;
4340         case LOWORD(RSA_CSP_PUBLICKEYBLOB):
4341             encodeFunc = CRYPT_AsnEncodeRsaPubKey;
4342             break;
4343         case LOWORD(X509_UNICODE_NAME):
4344             encodeFunc = CRYPT_AsnEncodeUnicodeName;
4345             break;
4346         case LOWORD(PKCS_CONTENT_INFO):
4347             encodeFunc = CRYPT_AsnEncodePKCSContentInfo;
4348             break;
4349         case LOWORD(PKCS_ATTRIBUTE):
4350             encodeFunc = CRYPT_AsnEncodePKCSAttribute;
4351             break;
4352         case LOWORD(X509_UNICODE_NAME_VALUE):
4353             encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
4354             break;
4355         case LOWORD(X509_OCTET_STRING):
4356             encodeFunc = CRYPT_AsnEncodeOctets;
4357             break;
4358         case LOWORD(X509_BITS):
4359         case LOWORD(X509_KEY_USAGE):
4360             encodeFunc = CRYPT_AsnEncodeBits;
4361             break;
4362         case LOWORD(X509_INTEGER):
4363             encodeFunc = CRYPT_AsnEncodeInt;
4364             break;
4365         case LOWORD(X509_MULTI_BYTE_INTEGER):
4366             encodeFunc = CRYPT_AsnEncodeInteger;
4367             break;
4368         case LOWORD(X509_MULTI_BYTE_UINT):
4369             encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
4370             break;
4371         case LOWORD(X509_ENUMERATED):
4372             encodeFunc = CRYPT_AsnEncodeEnumerated;
4373             break;
4374         case LOWORD(X509_CHOICE_OF_TIME):
4375             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
4376             break;
4377         case LOWORD(X509_AUTHORITY_KEY_ID2):
4378             encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
4379             break;
4380         case LOWORD(X509_AUTHORITY_INFO_ACCESS):
4381             encodeFunc = CRYPT_AsnEncodeAuthorityInfoAccess;
4382             break;
4383         case LOWORD(X509_SEQUENCE_OF_ANY):
4384             encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
4385             break;
4386         case LOWORD(PKCS_UTC_TIME):
4387             encodeFunc = CRYPT_AsnEncodeUtcTime;
4388             break;
4389         case LOWORD(X509_CRL_DIST_POINTS):
4390             encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
4391             break;
4392         case LOWORD(X509_ENHANCED_KEY_USAGE):
4393             encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
4394             break;
4395         case LOWORD(PKCS_CTL):
4396             encodeFunc = CRYPT_AsnEncodeCTL;
4397             break;
4398         case LOWORD(PKCS_SMIME_CAPABILITIES):
4399             encodeFunc = CRYPT_AsnEncodeSMIMECapabilities;
4400             break;
4401         case LOWORD(X509_PKIX_POLICY_QUALIFIER_USERNOTICE):
4402             encodeFunc = CRYPT_AsnEncodePolicyQualifierUserNotice;
4403             break;
4404         case LOWORD(PKCS_ATTRIBUTES):
4405             encodeFunc = CRYPT_AsnEncodePKCSAttributes;
4406             break;
4407         case LOWORD(X509_ISSUING_DIST_POINT):
4408             encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
4409             break;
4410         case LOWORD(X509_NAME_CONSTRAINTS):
4411             encodeFunc = CRYPT_AsnEncodeNameConstraints;
4412             break;
4413         case LOWORD(X509_POLICY_MAPPINGS):
4414             encodeFunc = CRYPT_AsnEncodeCertPolicyMappings;
4415             break;
4416         case LOWORD(PKCS7_SIGNER_INFO):
4417             encodeFunc = CRYPT_AsnEncodePKCSSignerInfo;
4418             break;
4419         case LOWORD(CMS_SIGNER_INFO):
4420             encodeFunc = CRYPT_AsnEncodeCMSSignerInfo;
4421             break;
4422         }
4423     }
4424     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
4425         encodeFunc = CRYPT_AsnEncodeExtensions;
4426     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
4427         encodeFunc = CRYPT_AsnEncodeUtcTime;
4428     else if (!strcmp(lpszStructType, szOID_RSA_SMIMECapabilities))
4429         encodeFunc = CRYPT_AsnEncodeUtcTime;
4430     else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
4431         encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
4432     else if (!strcmp(lpszStructType, szOID_LEGACY_POLICY_MAPPINGS))
4433         encodeFunc = CRYPT_AsnEncodeCertPolicyMappings;
4434     else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER2))
4435         encodeFunc = CRYPT_AsnEncodeAuthorityKeyId2;
4436     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
4437         encodeFunc = CRYPT_AsnEncodeEnumerated;
4438     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
4439         encodeFunc = CRYPT_AsnEncodeBits;
4440     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
4441         encodeFunc = CRYPT_AsnEncodeOctets;
4442     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
4443         encodeFunc = CRYPT_AsnEncodeBasicConstraints;
4444     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
4445         encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
4446     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
4447         encodeFunc = CRYPT_AsnEncodeAltName;
4448     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
4449         encodeFunc = CRYPT_AsnEncodeAltName;
4450     else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
4451         encodeFunc = CRYPT_AsnEncodeAltName;
4452     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
4453         encodeFunc = CRYPT_AsnEncodeAltName;
4454     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
4455         encodeFunc = CRYPT_AsnEncodeAltName;
4456     else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
4457         encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
4458     else if (!strcmp(lpszStructType, szOID_CERT_POLICIES))
4459         encodeFunc = CRYPT_AsnEncodeCertPolicies;
4460     else if (!strcmp(lpszStructType, szOID_POLICY_MAPPINGS))
4461         encodeFunc = CRYPT_AsnEncodeCertPolicyMappings;
4462     else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
4463         encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
4464     else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
4465         encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
4466     else if (!strcmp(lpszStructType, szOID_NAME_CONSTRAINTS))
4467         encodeFunc = CRYPT_AsnEncodeNameConstraints;
4468     else if (!strcmp(lpszStructType, szOID_AUTHORITY_INFO_ACCESS))
4469         encodeFunc = CRYPT_AsnEncodeAuthorityInfoAccess;
4470     else if (!strcmp(lpszStructType, szOID_PKIX_POLICY_QUALIFIER_USERNOTICE))
4471         encodeFunc = CRYPT_AsnEncodePolicyQualifierUserNotice;
4472     else if (!strcmp(lpszStructType, szOID_CTL))
4473         encodeFunc = CRYPT_AsnEncodeCTL;
4474     return encodeFunc;
4475 }
4476
4477 static CryptEncodeObjectFunc CRYPT_LoadEncoderFunc(DWORD dwCertEncodingType,
4478  LPCSTR lpszStructType, HCRYPTOIDFUNCADDR *hFunc)
4479 {
4480     static HCRYPTOIDFUNCSET set = NULL;
4481     CryptEncodeObjectFunc encodeFunc = NULL;
4482
4483     if (!set)
4484         set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_FUNC, 0);
4485     CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
4486      (void **)&encodeFunc, hFunc);
4487     return encodeFunc;
4488 }
4489
4490 static CryptEncodeObjectExFunc CRYPT_LoadEncoderExFunc(DWORD dwCertEncodingType,
4491  LPCSTR lpszStructType, HCRYPTOIDFUNCADDR *hFunc)
4492 {
4493     static HCRYPTOIDFUNCSET set = NULL;
4494     CryptEncodeObjectExFunc encodeFunc = NULL;
4495
4496     if (!set)
4497         set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
4498     CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
4499      (void **)&encodeFunc, hFunc);
4500     return encodeFunc;
4501 }
4502
4503 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
4504  const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
4505 {
4506     BOOL ret = FALSE;
4507     HCRYPTOIDFUNCADDR hFunc = NULL;
4508     CryptEncodeObjectFunc pCryptEncodeObject = NULL;
4509     CryptEncodeObjectExFunc pCryptEncodeObjectEx = NULL;
4510
4511     TRACE_(crypt)("(0x%08x, %s, %p, %p, %p)\n", dwCertEncodingType,
4512      debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
4513      pcbEncoded);
4514
4515     if (!pbEncoded && !pcbEncoded)
4516     {
4517         SetLastError(ERROR_INVALID_PARAMETER);
4518         return FALSE;
4519     }
4520
4521     if (!(pCryptEncodeObjectEx = CRYPT_GetBuiltinEncoder(dwCertEncodingType,
4522      lpszStructType)))
4523     {
4524         TRACE_(crypt)("OID %s not found or unimplemented, looking for DLL\n",
4525          debugstr_a(lpszStructType));
4526         pCryptEncodeObject = CRYPT_LoadEncoderFunc(dwCertEncodingType,
4527          lpszStructType, &hFunc);
4528         if (!pCryptEncodeObject)
4529             pCryptEncodeObjectEx = CRYPT_LoadEncoderExFunc(dwCertEncodingType,
4530              lpszStructType, &hFunc);
4531     }
4532     if (pCryptEncodeObject)
4533         ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
4534          pvStructInfo, pbEncoded, pcbEncoded);
4535     else if (pCryptEncodeObjectEx)
4536         ret = pCryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
4537          pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
4538     if (hFunc)
4539         CryptFreeOIDFunctionAddress(hFunc, 0);
4540     TRACE_(crypt)("returning %d\n", ret);
4541     return ret;
4542 }
4543
4544 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
4545  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
4546  void *pvEncoded, DWORD *pcbEncoded)
4547 {
4548     BOOL ret = FALSE;
4549     HCRYPTOIDFUNCADDR hFunc = NULL;
4550     CryptEncodeObjectExFunc encodeFunc = NULL;
4551
4552     TRACE_(crypt)("(0x%08x, %s, %p, 0x%08x, %p, %p, %p)\n", dwCertEncodingType,
4553      debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
4554      pvEncoded, pcbEncoded);
4555
4556     if (!pvEncoded && !pcbEncoded)
4557     {
4558         SetLastError(ERROR_INVALID_PARAMETER);
4559         return FALSE;
4560     }
4561
4562     SetLastError(NOERROR);
4563     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
4564         *(BYTE **)pvEncoded = NULL;
4565     encodeFunc = CRYPT_GetBuiltinEncoder(dwCertEncodingType, lpszStructType);
4566     if (!encodeFunc)
4567     {
4568         TRACE_(crypt)("OID %s not found or unimplemented, looking for DLL\n",
4569          debugstr_a(lpszStructType));
4570         encodeFunc = CRYPT_LoadEncoderExFunc(dwCertEncodingType, lpszStructType,
4571          &hFunc);
4572     }
4573     if (encodeFunc)
4574         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
4575          dwFlags, pEncodePara, pvEncoded, pcbEncoded);
4576     else
4577     {
4578         CryptEncodeObjectFunc pCryptEncodeObject =
4579          CRYPT_LoadEncoderFunc(dwCertEncodingType, lpszStructType, &hFunc);
4580
4581         if (pCryptEncodeObject)
4582         {
4583             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
4584             {
4585                 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
4586                  pvStructInfo, NULL, pcbEncoded);
4587                 if (ret && (ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
4588                  pvEncoded, pcbEncoded, *pcbEncoded)))
4589                     ret = pCryptEncodeObject(dwCertEncodingType,
4590                      lpszStructType, pvStructInfo, *(BYTE **)pvEncoded,
4591                      pcbEncoded);
4592             }
4593             else
4594                 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
4595                  pvStructInfo, pvEncoded, pcbEncoded);
4596         }
4597     }
4598     if (hFunc)
4599         CryptFreeOIDFunctionAddress(hFunc, 0);
4600     TRACE_(crypt)("returning %d\n", ret);
4601     return ret;
4602 }
4603
4604 BOOL WINAPI PFXExportCertStore(HCERTSTORE hStore, CRYPT_DATA_BLOB *pPFX,
4605  LPCWSTR szPassword, DWORD dwFlags)
4606 {
4607     return PFXExportCertStoreEx(hStore, pPFX, szPassword, NULL, dwFlags);
4608 }
4609
4610 BOOL WINAPI PFXExportCertStoreEx(HCERTSTORE hStore, CRYPT_DATA_BLOB *pPFX,
4611  LPCWSTR szPassword, void *pvReserved, DWORD dwFlags)
4612 {
4613     FIXME_(crypt)("(%p, %p, %p, %p, %08x): stub\n", hStore, pPFX, szPassword,
4614      pvReserved, dwFlags);
4615     return FALSE;
4616 }
4617
4618 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, DWORD dwKeySpec,
4619  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
4620 {
4621     return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
4622      NULL, 0, NULL, pInfo, pcbInfo);
4623 }
4624
4625 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
4626  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
4627  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
4628 {
4629     BOOL ret;
4630     HCRYPTKEY key;
4631     static CHAR oid[] = szOID_RSA_RSA;
4632
4633     TRACE_(crypt)("(%08lx, %d, %08x, %s, %08x, %p, %p, %d)\n", hCryptProv,
4634      dwKeySpec, dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags,
4635      pvAuxInfo, pInfo, pInfo ? *pcbInfo : 0);
4636
4637     if (!pszPublicKeyObjId)
4638         pszPublicKeyObjId = oid;
4639     if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
4640     {
4641         DWORD keySize = 0;
4642
4643         ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
4644         if (ret)
4645         {
4646             LPBYTE pubKey = CryptMemAlloc(keySize);
4647
4648             if (pubKey)
4649             {
4650                 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
4651                  &keySize);
4652                 if (ret)
4653                 {
4654                     DWORD encodedLen = 0;
4655
4656                     ret = CryptEncodeObject(dwCertEncodingType,
4657                      RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
4658                     if (ret)
4659                     {
4660                         DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
4661                          strlen(pszPublicKeyObjId) + 1 + encodedLen;
4662
4663                         if (!pInfo)
4664                             *pcbInfo = sizeNeeded;
4665                         else if (*pcbInfo < sizeNeeded)
4666                         {
4667                             SetLastError(ERROR_MORE_DATA);
4668                             *pcbInfo = sizeNeeded;
4669                             ret = FALSE;
4670                         }
4671                         else
4672                         {
4673                             *pcbInfo = sizeNeeded;
4674                             pInfo->Algorithm.pszObjId = (char *)pInfo +
4675                              sizeof(CERT_PUBLIC_KEY_INFO);
4676                             lstrcpyA(pInfo->Algorithm.pszObjId,
4677                              pszPublicKeyObjId);
4678                             pInfo->Algorithm.Parameters.cbData = 0;
4679                             pInfo->Algorithm.Parameters.pbData = NULL;
4680                             pInfo->PublicKey.pbData =
4681                              (BYTE *)pInfo->Algorithm.pszObjId
4682                              + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
4683                             pInfo->PublicKey.cbData = encodedLen;
4684                             pInfo->PublicKey.cUnusedBits = 0;
4685                             ret = CryptEncodeObject(dwCertEncodingType,
4686                              RSA_CSP_PUBLICKEYBLOB, pubKey,
4687                              pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
4688                         }
4689                     }
4690                 }
4691                 CryptMemFree(pubKey);
4692             }
4693             else
4694                 ret = FALSE;
4695         }
4696         CryptDestroyKey(key);
4697     }
4698     return ret;
4699 }
4700
4701 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv,
4702  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
4703  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
4704
4705 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE hCryptProv, DWORD dwKeySpec,
4706  DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
4707  void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
4708 {
4709     static HCRYPTOIDFUNCSET set = NULL;
4710     BOOL ret;
4711     ExportPublicKeyInfoExFunc exportFunc = NULL;
4712     HCRYPTOIDFUNCADDR hFunc = NULL;
4713
4714     TRACE_(crypt)("(%08lx, %d, %08x, %s, %08x, %p, %p, %d)\n", hCryptProv,
4715      dwKeySpec, dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags,
4716      pvAuxInfo, pInfo, pInfo ? *pcbInfo : 0);
4717
4718     if (!hCryptProv)
4719     {
4720         SetLastError(ERROR_INVALID_PARAMETER);
4721         return FALSE;
4722     }
4723
4724     if (pszPublicKeyObjId)
4725     {
4726         if (!set)
4727             set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
4728              0);
4729         CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
4730          0, (void **)&exportFunc, &hFunc);
4731     }
4732     if (!exportFunc)
4733         exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
4734     ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
4735      pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
4736     if (hFunc)
4737         CryptFreeOIDFunctionAddress(hFunc, 0);
4738     return ret;
4739 }
4740
4741 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
4742  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
4743 {
4744     return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
4745      0, 0, NULL, phKey);
4746 }
4747
4748 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
4749  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
4750  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
4751 {
4752     BOOL ret;
4753     DWORD pubKeySize = 0;
4754
4755     TRACE_(crypt)("(%08lx, %08x, %p, %08x, %08x, %p, %p)\n", hCryptProv,
4756      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
4757
4758     ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
4759      pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
4760     if (ret)
4761     {
4762         LPBYTE pubKey = CryptMemAlloc(pubKeySize);
4763
4764         if (pubKey)
4765         {
4766             ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
4767              pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
4768              &pubKeySize);
4769             if (ret)
4770             {
4771                 if(aiKeyAlg)
4772                   ((BLOBHEADER*)pubKey)->aiKeyAlg = aiKeyAlg;
4773                 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
4774                  phKey);
4775             }
4776             CryptMemFree(pubKey);
4777         }
4778         else
4779             ret = FALSE;
4780     }
4781     return ret;
4782 }
4783
4784 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
4785  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
4786  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
4787
4788 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
4789  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
4790  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
4791 {
4792     static HCRYPTOIDFUNCSET set = NULL;
4793     BOOL ret;
4794     ImportPublicKeyInfoExFunc importFunc = NULL;
4795     HCRYPTOIDFUNCADDR hFunc = NULL;
4796
4797     TRACE_(crypt)("(%08lx, %08x, %p, %08x, %08x, %p, %p)\n", hCryptProv,
4798      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
4799
4800     if (!set)
4801         set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
4802     CryptGetOIDFunctionAddress(set, dwCertEncodingType,
4803      pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
4804     if (!importFunc)
4805         importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
4806     ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
4807      pvAuxInfo, phKey);
4808     if (hFunc)
4809         CryptFreeOIDFunctionAddress(hFunc, 0);
4810     return ret;
4811 }