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