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