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