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