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