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