comctl32: Update Polish translation.
[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%08lx, %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, %ld, %08lx, %p, %p, %ld\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 (%08lx)\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 (%08lx)\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, %ld\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 (%08lx)\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 %ld 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 %ld 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 (%08lx)\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 %ld 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 (%08lx)\n", ret, GetLastError());
1809     return ret;
1810 }
1811
1812 static BOOL WINAPI CRYPT_AsnEncodeAltName(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_ALT_NAME_INFO *info =
1821          (const CERT_ALT_NAME_INFO *)pvStructInfo;
1822         DWORD bytesNeeded, dataLen, lenBytes, i;
1823
1824         ret = TRUE;
1825         /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1826          * can't encode an erroneous entry index if it's bigger than this.
1827          */
1828         for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1829         {
1830             DWORD len;
1831
1832             ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1833              &len);
1834             if (ret)
1835                 dataLen += len;
1836             else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1837             {
1838                 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1839                  * the bad character, now set the index of the bad
1840                  * entry
1841                  */
1842                 *pcbEncoded = (BYTE)i <<
1843                  CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1844             }
1845         }
1846         if (ret)
1847         {
1848             CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1849             bytesNeeded = 1 + lenBytes + dataLen;
1850             if (!pbEncoded)
1851             {
1852                 *pcbEncoded = bytesNeeded;
1853                 ret = TRUE;
1854             }
1855             else
1856             {
1857                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1858                  pbEncoded, pcbEncoded, bytesNeeded)))
1859                 {
1860                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1861                         pbEncoded = *(BYTE **)pbEncoded;
1862                     *pbEncoded++ = ASN_SEQUENCEOF;
1863                     CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1864                     pbEncoded += lenBytes;
1865                     for (i = 0; ret && i < info->cAltEntry; i++)
1866                     {
1867                         DWORD len = dataLen;
1868
1869                         ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1870                          pbEncoded, &len);
1871                         if (ret)
1872                         {
1873                             pbEncoded += len;
1874                             dataLen -= len;
1875                         }
1876                     }
1877                 }
1878             }
1879         }
1880     }
1881     __EXCEPT_PAGE_FAULT
1882     {
1883         SetLastError(STATUS_ACCESS_VIOLATION);
1884         ret = FALSE;
1885     }
1886     __ENDTRY
1887     return ret;
1888 }
1889
1890 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
1891  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1892  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1893 {
1894     BOOL ret;
1895
1896     __TRY
1897     {
1898         const CERT_BASIC_CONSTRAINTS_INFO *info =
1899          (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
1900         struct AsnEncodeSequenceItem items[3] = {
1901          { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
1902          { 0 }
1903         };
1904         DWORD cItem = 1;
1905
1906         if (info->fPathLenConstraint)
1907         {
1908             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1909             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1910             cItem++;
1911         }
1912         if (info->cSubtreesConstraint)
1913         {
1914             items[cItem].pvStructInfo = &info->cSubtreesConstraint;
1915             items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
1916             cItem++;
1917         }
1918         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1919          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1920     }
1921     __EXCEPT_PAGE_FAULT
1922     {
1923         SetLastError(STATUS_ACCESS_VIOLATION);
1924         ret = FALSE;
1925     }
1926     __ENDTRY
1927     return ret;
1928 }
1929
1930 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1931  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1932  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1933 {
1934     BOOL ret;
1935
1936     __TRY
1937     {
1938         const CERT_BASIC_CONSTRAINTS2_INFO *info =
1939          (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1940         struct AsnEncodeSequenceItem items[2] = { { 0 } };
1941         DWORD cItem = 0;
1942
1943         if (info->fCA)
1944         {
1945             items[cItem].pvStructInfo = &info->fCA;
1946             items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1947             cItem++;
1948         }
1949         if (info->fPathLenConstraint)
1950         {
1951             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1952             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1953             cItem++;
1954         }
1955         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1956          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1957     }
1958     __EXCEPT_PAGE_FAULT
1959     {
1960         SetLastError(STATUS_ACCESS_VIOLATION);
1961         ret = FALSE;
1962     }
1963     __ENDTRY
1964     return ret;
1965 }
1966
1967 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
1968  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1969  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1970 {
1971     BOOL ret;
1972
1973     __TRY
1974     {
1975         const BLOBHEADER *hdr =
1976          (const BLOBHEADER *)pvStructInfo;
1977
1978         if (hdr->bType != PUBLICKEYBLOB)
1979         {
1980             SetLastError(E_INVALIDARG);
1981             ret = FALSE;
1982         }
1983         else
1984         {
1985             const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
1986              ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
1987             CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
1988              (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
1989             struct AsnEncodeSequenceItem items[] = { 
1990              { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
1991              { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
1992             };
1993
1994             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1995              sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1996              pcbEncoded);
1997         }
1998     }
1999     __EXCEPT_PAGE_FAULT
2000     {
2001         SetLastError(STATUS_ACCESS_VIOLATION);
2002         ret = FALSE;
2003     }
2004     __ENDTRY
2005     return ret;
2006 }
2007
2008 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
2009  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2010  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2011 {
2012     BOOL ret;
2013
2014     __TRY
2015     {
2016         const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
2017         DWORD bytesNeeded, lenBytes;
2018
2019         TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
2020          dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
2021
2022         CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
2023         bytesNeeded = 1 + lenBytes + blob->cbData;
2024         if (!pbEncoded)
2025         {
2026             *pcbEncoded = bytesNeeded;
2027             ret = TRUE;
2028         }
2029         else
2030         {
2031             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2032              pcbEncoded, bytesNeeded)))
2033             {
2034                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2035                     pbEncoded = *(BYTE **)pbEncoded;
2036                 *pbEncoded++ = ASN_OCTETSTRING;
2037                 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
2038                 pbEncoded += lenBytes;
2039                 if (blob->cbData)
2040                     memcpy(pbEncoded, blob->pbData, blob->cbData);
2041             }
2042         }
2043     }
2044     __EXCEPT_PAGE_FAULT
2045     {
2046         SetLastError(STATUS_ACCESS_VIOLATION);
2047         ret = FALSE;
2048     }
2049     __ENDTRY
2050     TRACE("returning %d (%08lx)\n", ret, GetLastError());
2051     return ret;
2052 }
2053
2054 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
2055  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2056  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2057 {
2058     BOOL ret;
2059
2060     __TRY
2061     {
2062         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2063         DWORD bytesNeeded, lenBytes, dataBytes;
2064         BYTE unusedBits;
2065
2066         /* yep, MS allows cUnusedBits to be >= 8 */
2067         if (!blob->cUnusedBits)
2068         {
2069             dataBytes = blob->cbData;
2070             unusedBits = 0;
2071         }
2072         else if (blob->cbData * 8 > blob->cUnusedBits)
2073         {
2074             dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
2075             unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
2076              blob->cUnusedBits;
2077         }
2078         else
2079         {
2080             dataBytes = 0;
2081             unusedBits = 0;
2082         }
2083         CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
2084         bytesNeeded = 1 + lenBytes + dataBytes + 1;
2085         if (!pbEncoded)
2086         {
2087             *pcbEncoded = bytesNeeded;
2088             ret = TRUE;
2089         }
2090         else
2091         {
2092             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2093              pcbEncoded, bytesNeeded)))
2094             {
2095                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2096                     pbEncoded = *(BYTE **)pbEncoded;
2097                 *pbEncoded++ = ASN_BITSTRING;
2098                 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
2099                 pbEncoded += lenBytes;
2100                 *pbEncoded++ = unusedBits;
2101                 if (dataBytes)
2102                 {
2103                     BYTE mask = 0xff << unusedBits;
2104
2105                     if (dataBytes > 1)
2106                     {
2107                         memcpy(pbEncoded, blob->pbData, dataBytes - 1);
2108                         pbEncoded += dataBytes - 1;
2109                     }
2110                     *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
2111                 }
2112             }
2113         }
2114     }
2115     __EXCEPT_PAGE_FAULT
2116     {
2117         SetLastError(STATUS_ACCESS_VIOLATION);
2118         ret = FALSE;
2119     }
2120     __ENDTRY
2121     return ret;
2122 }
2123
2124 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
2125  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2126  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2127 {
2128     BOOL ret;
2129
2130     __TRY
2131     {
2132         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2133         CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
2134
2135         ret = TRUE;
2136         if (newBlob.cbData)
2137         {
2138             newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2139             if (newBlob.pbData)
2140             {
2141                 DWORD i;
2142
2143                 for (i = 0; i < newBlob.cbData; i++)
2144                     newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2145             }
2146             else
2147                 ret = FALSE;
2148         }
2149         if (ret)
2150             ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
2151              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2152         CryptMemFree(newBlob.pbData);
2153     }
2154     __EXCEPT_PAGE_FAULT
2155     {
2156         SetLastError(STATUS_ACCESS_VIOLATION);
2157         ret = FALSE;
2158     }
2159     __ENDTRY
2160     return ret;
2161 }
2162
2163 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
2164  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2165  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2166 {
2167     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
2168
2169     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
2170      &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2171 }
2172
2173 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
2174  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2175  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2176 {
2177     BOOL ret;
2178
2179     __TRY
2180     {
2181         DWORD significantBytes, lenBytes;
2182         BYTE padByte = 0, bytesNeeded;
2183         BOOL pad = FALSE;
2184         const CRYPT_INTEGER_BLOB *blob =
2185          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2186
2187         significantBytes = blob->cbData;
2188         if (significantBytes)
2189         {
2190             if (blob->pbData[significantBytes - 1] & 0x80)
2191             {
2192                 /* negative, lop off leading (little-endian) 0xffs */
2193                 for (; significantBytes > 0 &&
2194                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
2195                     ;
2196                 if (blob->pbData[significantBytes - 1] < 0x80)
2197                 {
2198                     padByte = 0xff;
2199                     pad = TRUE;
2200                 }
2201             }
2202             else
2203             {
2204                 /* positive, lop off leading (little-endian) zeroes */
2205                 for (; significantBytes > 0 &&
2206                  !blob->pbData[significantBytes - 1]; significantBytes--)
2207                     ;
2208                 if (significantBytes == 0)
2209                     significantBytes = 1;
2210                 if (blob->pbData[significantBytes - 1] > 0x7f)
2211                 {
2212                     padByte = 0;
2213                     pad = TRUE;
2214                 }
2215             }
2216         }
2217         if (pad)
2218             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2219         else
2220             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2221         bytesNeeded = 1 + lenBytes + significantBytes;
2222         if (pad)
2223             bytesNeeded++;
2224         if (!pbEncoded)
2225         {
2226             *pcbEncoded = bytesNeeded;
2227             ret = TRUE;
2228         }
2229         else
2230         {
2231             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2232              pcbEncoded, bytesNeeded)))
2233             {
2234                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2235                     pbEncoded = *(BYTE **)pbEncoded;
2236                 *pbEncoded++ = ASN_INTEGER;
2237                 if (pad)
2238                 {
2239                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2240                     pbEncoded += lenBytes;
2241                     *pbEncoded++ = padByte;
2242                 }
2243                 else
2244                 {
2245                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2246                     pbEncoded += lenBytes;
2247                 }
2248                 for (; significantBytes > 0; significantBytes--)
2249                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
2250             }
2251         }
2252     }
2253     __EXCEPT_PAGE_FAULT
2254     {
2255         SetLastError(STATUS_ACCESS_VIOLATION);
2256         ret = FALSE;
2257     }
2258     __ENDTRY
2259     return ret;
2260 }
2261
2262 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
2263  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2264  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2265 {
2266     BOOL ret;
2267
2268     __TRY
2269     {
2270         DWORD significantBytes, lenBytes;
2271         BYTE bytesNeeded;
2272         BOOL pad = FALSE;
2273         const CRYPT_INTEGER_BLOB *blob =
2274          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2275
2276         significantBytes = blob->cbData;
2277         if (significantBytes)
2278         {
2279             /* positive, lop off leading (little-endian) zeroes */
2280             for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2281              significantBytes--)
2282                 ;
2283             if (significantBytes == 0)
2284                 significantBytes = 1;
2285             if (blob->pbData[significantBytes - 1] > 0x7f)
2286                 pad = TRUE;
2287         }
2288         if (pad)
2289             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2290         else
2291             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2292         bytesNeeded = 1 + lenBytes + significantBytes;
2293         if (pad)
2294             bytesNeeded++;
2295         if (!pbEncoded)
2296         {
2297             *pcbEncoded = bytesNeeded;
2298             ret = TRUE;
2299         }
2300         else
2301         {
2302             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2303              pcbEncoded, bytesNeeded)))
2304             {
2305                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2306                     pbEncoded = *(BYTE **)pbEncoded;
2307                 *pbEncoded++ = ASN_INTEGER;
2308                 if (pad)
2309                 {
2310                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2311                     pbEncoded += lenBytes;
2312                     *pbEncoded++ = 0;
2313                 }
2314                 else
2315                 {
2316                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2317                     pbEncoded += lenBytes;
2318                 }
2319                 for (; significantBytes > 0; significantBytes--)
2320                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
2321             }
2322         }
2323     }
2324     __EXCEPT_PAGE_FAULT
2325     {
2326         SetLastError(STATUS_ACCESS_VIOLATION);
2327         ret = FALSE;
2328     }
2329     __ENDTRY
2330     return ret;
2331 }
2332
2333 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2334  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2335  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2336 {
2337     CRYPT_INTEGER_BLOB blob;
2338     BOOL ret;
2339
2340     /* Encode as an unsigned integer, then change the tag to enumerated */
2341     blob.cbData = sizeof(DWORD);
2342     blob.pbData = (BYTE *)pvStructInfo;
2343     ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2344      X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2345     if (ret && pbEncoded)
2346     {
2347         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2348             pbEncoded = *(BYTE **)pbEncoded;
2349         pbEncoded[0] = ASN_ENUMERATED;
2350     }
2351     return ret;
2352 }
2353
2354 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2355  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2356  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2357 {
2358     BOOL ret;
2359
2360     __TRY
2361     {
2362         SYSTEMTIME sysTime;
2363         /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
2364          * temporary buffer because the output buffer is not NULL-terminated.
2365          */
2366         char buf[16];
2367         static const DWORD bytesNeeded = sizeof(buf) - 1;
2368
2369         if (!pbEncoded)
2370         {
2371             *pcbEncoded = bytesNeeded;
2372             ret = TRUE;
2373         }
2374         else
2375         {
2376             /* Sanity check the year, this is a two-digit year format */
2377             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2378              &sysTime);
2379             if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2380             {
2381                 SetLastError(CRYPT_E_BAD_ENCODE);
2382                 ret = FALSE;
2383             }
2384             if (ret)
2385             {
2386                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2387                  pbEncoded, pcbEncoded, bytesNeeded)))
2388                 {
2389                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2390                         pbEncoded = *(BYTE **)pbEncoded;
2391                     buf[0] = ASN_UTCTIME;
2392                     buf[1] = bytesNeeded - 2;
2393                     snprintf(buf + 2, sizeof(buf) - 2,
2394                      "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2395                      sysTime.wYear - 2000 : sysTime.wYear - 1900,
2396                      sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2397                      sysTime.wMinute, sysTime.wSecond);
2398                     memcpy(pbEncoded, buf, bytesNeeded);
2399                 }
2400             }
2401         }
2402     }
2403     __EXCEPT_PAGE_FAULT
2404     {
2405         SetLastError(STATUS_ACCESS_VIOLATION);
2406         ret = FALSE;
2407     }
2408     __ENDTRY
2409     return ret;
2410 }
2411
2412 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2413  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2414  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2415 {
2416     BOOL ret;
2417
2418     __TRY
2419     {
2420         SYSTEMTIME sysTime;
2421         /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
2422          * temporary buffer because the output buffer is not NULL-terminated.
2423          */
2424         char buf[18];
2425         static const DWORD bytesNeeded = sizeof(buf) - 1;
2426
2427         if (!pbEncoded)
2428         {
2429             *pcbEncoded = bytesNeeded;
2430             ret = TRUE;
2431         }
2432         else
2433         {
2434             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2435              &sysTime);
2436             if (ret)
2437                 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2438                  pcbEncoded, bytesNeeded);
2439             if (ret)
2440             {
2441                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2442                     pbEncoded = *(BYTE **)pbEncoded;
2443                 buf[0] = ASN_GENERALTIME;
2444                 buf[1] = bytesNeeded - 2;
2445                 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2446                  sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2447                  sysTime.wMinute, sysTime.wSecond);
2448                 memcpy(pbEncoded, buf, bytesNeeded);
2449             }
2450         }
2451     }
2452     __EXCEPT_PAGE_FAULT
2453     {
2454         SetLastError(STATUS_ACCESS_VIOLATION);
2455         ret = FALSE;
2456     }
2457     __ENDTRY
2458     return ret;
2459 }
2460
2461 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2462  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2463  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2464 {
2465     BOOL ret;
2466
2467     __TRY
2468     {
2469         SYSTEMTIME sysTime;
2470
2471         /* Check the year, if it's in the UTCTime range call that encode func */
2472         if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2473             return FALSE;
2474         if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2475             ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2476              pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2477         else
2478             ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2479              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2480              pcbEncoded);
2481     }
2482     __EXCEPT_PAGE_FAULT
2483     {
2484         SetLastError(STATUS_ACCESS_VIOLATION);
2485         ret = FALSE;
2486     }
2487     __ENDTRY
2488     return ret;
2489 }
2490
2491 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2492  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2493  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2494 {
2495     BOOL ret;
2496
2497     __TRY
2498     {
2499         DWORD bytesNeeded, dataLen, lenBytes, i;
2500         const CRYPT_SEQUENCE_OF_ANY *seq =
2501          (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2502
2503         for (i = 0, dataLen = 0; i < seq->cValue; i++)
2504             dataLen += seq->rgValue[i].cbData;
2505         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2506         bytesNeeded = 1 + lenBytes + dataLen;
2507         if (!pbEncoded)
2508         {
2509             *pcbEncoded = bytesNeeded;
2510             ret = TRUE;
2511         }
2512         else
2513         {
2514             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2515              pcbEncoded, bytesNeeded)))
2516             {
2517                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2518                     pbEncoded = *(BYTE **)pbEncoded;
2519                 *pbEncoded++ = ASN_SEQUENCEOF;
2520                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2521                 pbEncoded += lenBytes;
2522                 for (i = 0; i < seq->cValue; i++)
2523                 {
2524                     memcpy(pbEncoded, seq->rgValue[i].pbData,
2525                      seq->rgValue[i].cbData);
2526                     pbEncoded += seq->rgValue[i].cbData;
2527                 }
2528             }
2529         }
2530     }
2531     __EXCEPT_PAGE_FAULT
2532     {
2533         SetLastError(STATUS_ACCESS_VIOLATION);
2534         ret = FALSE;
2535     }
2536     __ENDTRY
2537     return ret;
2538 }
2539
2540 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2541  BYTE *pbEncoded, DWORD *pcbEncoded)
2542 {
2543     BOOL ret = TRUE;
2544     struct AsnEncodeSequenceItem items[3] = { { 0 } };
2545     struct AsnConstructedItem constructed = { 0 };
2546     struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2547     DWORD cItem = 0, cSwapped = 0;
2548
2549     switch (distPoint->DistPointName.dwDistPointNameChoice)
2550     {
2551     case CRL_DIST_POINT_NO_NAME:
2552         /* do nothing */
2553         break;
2554     case CRL_DIST_POINT_FULL_NAME:
2555         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2556         swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2557         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2558         constructed.tag = 0;
2559         constructed.pvStructInfo = &swapped[cSwapped];
2560         constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2561         items[cItem].pvStructInfo = &constructed;
2562         items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2563         cSwapped++;
2564         cItem++;
2565         break;
2566     case CRL_DIST_POINT_ISSUER_RDN_NAME:
2567         FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2568         ret = FALSE;
2569         break;
2570     default:
2571         ret = FALSE;
2572     }
2573     if (ret && distPoint->ReasonFlags.cbData)
2574     {
2575         swapped[cSwapped].tag = ASN_CONTEXT | 1;
2576         swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2577         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2578         items[cItem].pvStructInfo = &swapped[cSwapped];
2579         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2580         cSwapped++;
2581         cItem++;
2582     }
2583     if (ret && distPoint->CRLIssuer.cAltEntry)
2584     {
2585         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2586         swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2587         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2588         items[cItem].pvStructInfo = &swapped[cSwapped];
2589         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2590         cSwapped++;
2591         cItem++;
2592     }
2593     if (ret)
2594         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2595          pbEncoded, pcbEncoded);
2596     return ret;
2597 }
2598
2599 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2600  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2601  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2602 {
2603     BOOL ret;
2604
2605     __TRY
2606     {
2607         const CRL_DIST_POINTS_INFO *info =
2608          (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2609
2610         if (!info->cDistPoint)
2611         {
2612             SetLastError(E_INVALIDARG);
2613             ret = FALSE;
2614         }
2615         else
2616         {
2617             DWORD bytesNeeded, dataLen, lenBytes, i;
2618
2619             ret = TRUE;
2620             for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2621             {
2622                 DWORD len;
2623
2624                 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2625                  &len);
2626                 if (ret)
2627                     dataLen += len;
2628                 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2629                 {
2630                     /* Have to propagate index of failing character */
2631                     *pcbEncoded = len;
2632                 }
2633             }
2634             if (ret)
2635             {
2636                 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2637                 bytesNeeded = 1 + lenBytes + dataLen;
2638                 if (!pbEncoded)
2639                 {
2640                     *pcbEncoded = bytesNeeded;
2641                     ret = TRUE;
2642                 }
2643                 else
2644                 {
2645                     if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2646                      pbEncoded, pcbEncoded, bytesNeeded)))
2647                     {
2648                         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2649                             pbEncoded = *(BYTE **)pbEncoded;
2650                         *pbEncoded++ = ASN_SEQUENCEOF;
2651                         CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2652                         pbEncoded += lenBytes;
2653                         for (i = 0; ret && i < info->cDistPoint; i++)
2654                         {
2655                             DWORD len = dataLen;
2656
2657                             ret = CRYPT_AsnEncodeDistPoint(
2658                              &info->rgDistPoint[i], pbEncoded, &len);
2659                             if (ret)
2660                             {
2661                                 pbEncoded += len;
2662                                 dataLen -= len;
2663                             }
2664                         }
2665                     }
2666                 }
2667             }
2668         }
2669     }
2670     __EXCEPT_PAGE_FAULT
2671     {
2672         SetLastError(STATUS_ACCESS_VIOLATION);
2673         ret = FALSE;
2674     }
2675     __ENDTRY
2676     return ret;
2677 }
2678
2679 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
2680  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2681  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2682 {
2683     BOOL ret;
2684
2685     __TRY
2686     {
2687         const CERT_ENHKEY_USAGE *usage =
2688          (const CERT_ENHKEY_USAGE *)pvStructInfo;
2689         DWORD bytesNeeded = 0, lenBytes, size, i;
2690
2691         ret = TRUE;
2692         for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2693         {
2694             ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2695              usage->rgpszUsageIdentifier[i],
2696              dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
2697             if (ret)
2698                 bytesNeeded += size;
2699         }
2700         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2701         bytesNeeded += 1 + lenBytes;
2702         if (ret)
2703         {
2704             if (!pbEncoded)
2705                 *pcbEncoded = bytesNeeded;
2706             else
2707             {
2708                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2709                  pbEncoded, pcbEncoded, bytesNeeded)))
2710                 {
2711                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2712                         pbEncoded = *(BYTE **)pbEncoded;
2713                     *pbEncoded++ = ASN_SEQUENCEOF;
2714                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2715                      &lenBytes);
2716                     pbEncoded += lenBytes;
2717                     for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2718                     {
2719                         size = bytesNeeded;
2720                         ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2721                          usage->rgpszUsageIdentifier[i],
2722                          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
2723                          &size);
2724                         if (ret)
2725                         {
2726                             pbEncoded += size;
2727                             bytesNeeded -= size;
2728                         }
2729                     }
2730                 }
2731             }
2732         }
2733     }
2734     __EXCEPT_PAGE_FAULT
2735     {
2736         SetLastError(STATUS_ACCESS_VIOLATION);
2737         ret = FALSE;
2738     }
2739     __ENDTRY
2740     return ret;
2741 }
2742
2743 static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType,
2744  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2745  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2746 {
2747     BOOL ret;
2748
2749     __TRY
2750     {
2751         const CRL_ISSUING_DIST_POINT *point =
2752          (const CRL_ISSUING_DIST_POINT *)pvStructInfo;
2753         struct AsnEncodeSequenceItem items[6] = { { 0 } };
2754         struct AsnConstructedItem constructed = { 0 };
2755         struct AsnEncodeTagSwappedItem swapped[5] = { { 0 } };
2756         DWORD cItem = 0, cSwapped = 0;
2757
2758         ret = TRUE;
2759         switch (point->DistPointName.dwDistPointNameChoice)
2760         {
2761         case CRL_DIST_POINT_NO_NAME:
2762             /* do nothing */
2763             break;
2764         case CRL_DIST_POINT_FULL_NAME:
2765             swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2766             swapped[cSwapped].pvStructInfo = &point->DistPointName.u.FullName;
2767             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2768             constructed.tag = 0;
2769             constructed.pvStructInfo = &swapped[cSwapped];
2770             constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2771             items[cItem].pvStructInfo = &constructed;
2772             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2773             cSwapped++;
2774             cItem++;
2775             break;
2776         default:
2777             SetLastError(E_INVALIDARG);
2778             ret = FALSE;
2779         }
2780         if (ret && point->fOnlyContainsUserCerts)
2781         {
2782             swapped[cSwapped].tag = ASN_CONTEXT | 1;
2783             swapped[cSwapped].pvStructInfo = &point->fOnlyContainsUserCerts;
2784             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2785             items[cItem].pvStructInfo = &swapped[cSwapped];
2786             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2787             cSwapped++;
2788             cItem++;
2789         }
2790         if (ret && point->fOnlyContainsCACerts)
2791         {
2792             swapped[cSwapped].tag = ASN_CONTEXT | 2;
2793             swapped[cSwapped].pvStructInfo = &point->fOnlyContainsCACerts;
2794             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2795             items[cItem].pvStructInfo = &swapped[cSwapped];
2796             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2797             cSwapped++;
2798             cItem++;
2799         }
2800         if (ret && point->OnlySomeReasonFlags.cbData)
2801         {
2802             swapped[cSwapped].tag = ASN_CONTEXT | 3;
2803             swapped[cSwapped].pvStructInfo = &point->OnlySomeReasonFlags;
2804             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2805             items[cItem].pvStructInfo = &swapped[cSwapped];
2806             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2807             cSwapped++;
2808             cItem++;
2809         }
2810         if (ret && point->fIndirectCRL)
2811         {
2812             swapped[cSwapped].tag = ASN_CONTEXT | 4;
2813             swapped[cSwapped].pvStructInfo = &point->fIndirectCRL;
2814             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2815             items[cItem].pvStructInfo = &swapped[cSwapped];
2816             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2817             cSwapped++;
2818             cItem++;
2819         }
2820         if (ret)
2821             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2822              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2823     }
2824     __EXCEPT_PAGE_FAULT
2825     {
2826         SetLastError(STATUS_ACCESS_VIOLATION);
2827         ret = FALSE;
2828     }
2829     __ENDTRY
2830     return ret;
2831 }
2832
2833 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2834  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2835  void *pvEncoded, DWORD *pcbEncoded)
2836 {
2837     static HCRYPTOIDFUNCSET set = NULL;
2838     BOOL ret = FALSE;
2839     CryptEncodeObjectExFunc encodeFunc = NULL;
2840     HCRYPTOIDFUNCADDR hFunc = NULL;
2841
2842     TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2843      debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2844      pvEncoded, pcbEncoded);
2845
2846     if (!pvEncoded && !pcbEncoded)
2847     {
2848         SetLastError(ERROR_INVALID_PARAMETER);
2849         return FALSE;
2850     }
2851     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2852      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2853     {
2854         SetLastError(ERROR_FILE_NOT_FOUND);
2855         return FALSE;
2856     }
2857
2858     SetLastError(NOERROR);
2859     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2860         *(BYTE **)pvEncoded = NULL;
2861     if (!HIWORD(lpszStructType))
2862     {
2863         switch (LOWORD(lpszStructType))
2864         {
2865         case (WORD)X509_CERT:
2866             encodeFunc = CRYPT_AsnEncodeCert;
2867             break;
2868         case (WORD)X509_CERT_TO_BE_SIGNED:
2869             encodeFunc = CRYPT_AsnEncodeCertInfo;
2870             break;
2871         case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2872             encodeFunc = CRYPT_AsnEncodeCRLInfo;
2873             break;
2874         case (WORD)X509_EXTENSIONS:
2875             encodeFunc = CRYPT_AsnEncodeExtensions;
2876             break;
2877         case (WORD)X509_NAME_VALUE:
2878             encodeFunc = CRYPT_AsnEncodeNameValue;
2879             break;
2880         case (WORD)X509_NAME:
2881             encodeFunc = CRYPT_AsnEncodeName;
2882             break;
2883         case (WORD)X509_PUBLIC_KEY_INFO:
2884             encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2885             break;
2886         case (WORD)X509_ALTERNATE_NAME:
2887             encodeFunc = CRYPT_AsnEncodeAltName;
2888             break;
2889         case (WORD)X509_BASIC_CONSTRAINTS:
2890             encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2891             break;
2892         case (WORD)X509_BASIC_CONSTRAINTS2:
2893             encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2894             break;
2895         case (WORD)RSA_CSP_PUBLICKEYBLOB:
2896             encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2897             break;
2898         case (WORD)X509_UNICODE_NAME:
2899             encodeFunc = CRYPT_AsnEncodeUnicodeName;
2900             break;
2901         case (WORD)X509_UNICODE_NAME_VALUE:
2902             encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
2903             break;
2904         case (WORD)X509_OCTET_STRING:
2905             encodeFunc = CRYPT_AsnEncodeOctets;
2906             break;
2907         case (WORD)X509_BITS:
2908         case (WORD)X509_KEY_USAGE:
2909             encodeFunc = CRYPT_AsnEncodeBits;
2910             break;
2911         case (WORD)X509_INTEGER:
2912             encodeFunc = CRYPT_AsnEncodeInt;
2913             break;
2914         case (WORD)X509_MULTI_BYTE_INTEGER:
2915             encodeFunc = CRYPT_AsnEncodeInteger;
2916             break;
2917         case (WORD)X509_MULTI_BYTE_UINT:
2918             encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2919             break;
2920         case (WORD)X509_ENUMERATED:
2921             encodeFunc = CRYPT_AsnEncodeEnumerated;
2922             break;
2923         case (WORD)X509_CHOICE_OF_TIME:
2924             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2925             break;
2926         case (WORD)X509_SEQUENCE_OF_ANY:
2927             encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2928             break;
2929         case (WORD)PKCS_UTC_TIME:
2930             encodeFunc = CRYPT_AsnEncodeUtcTime;
2931             break;
2932         case (WORD)X509_CRL_DIST_POINTS:
2933             encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2934             break;
2935         case (WORD)X509_ENHANCED_KEY_USAGE:
2936             encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2937             break;
2938         case (WORD)X509_ISSUING_DIST_POINT:
2939             encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
2940             break;
2941         default:
2942             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2943         }
2944     }
2945     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2946         encodeFunc = CRYPT_AsnEncodeExtensions;
2947     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2948         encodeFunc = CRYPT_AsnEncodeUtcTime;
2949     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2950         encodeFunc = CRYPT_AsnEncodeEnumerated;
2951     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2952         encodeFunc = CRYPT_AsnEncodeBits;
2953     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2954         encodeFunc = CRYPT_AsnEncodeOctets;
2955     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
2956         encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2957     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2958         encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2959     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2960         encodeFunc = CRYPT_AsnEncodeAltName;
2961     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2962         encodeFunc = CRYPT_AsnEncodeAltName;
2963     else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2964         encodeFunc = CRYPT_AsnEncodeAltName;
2965     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2966         encodeFunc = CRYPT_AsnEncodeAltName;
2967     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2968         encodeFunc = CRYPT_AsnEncodeAltName;
2969     else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2970         encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2971     else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2972         encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2973     else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
2974         encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
2975     else
2976         TRACE("OID %s not found or unimplemented, looking for DLL\n",
2977          debugstr_a(lpszStructType));
2978     if (!encodeFunc)
2979     {
2980         if (!set)
2981             set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
2982         CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2983          (void **)&encodeFunc, &hFunc);
2984     }
2985     if (encodeFunc)
2986         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2987          dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2988     else
2989         SetLastError(ERROR_FILE_NOT_FOUND);
2990     if (hFunc)
2991         CryptFreeOIDFunctionAddress(hFunc, 0);
2992     return ret;
2993 }
2994
2995 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
2996  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
2997 {
2998     return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
2999      NULL, 0, NULL, pInfo, pcbInfo);
3000 }
3001
3002 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3003  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3004  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3005 {
3006     BOOL ret;
3007     HCRYPTKEY key;
3008     static CHAR oid[] = szOID_RSA_RSA;
3009
3010     TRACE("(%08lx, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3011      dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3012      pInfo, pcbInfo);
3013
3014     if (!pszPublicKeyObjId)
3015         pszPublicKeyObjId = oid;
3016     if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
3017     {
3018         DWORD keySize = 0;
3019
3020         ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
3021         if (ret)
3022         {
3023             LPBYTE pubKey = CryptMemAlloc(keySize);
3024
3025             if (pubKey)
3026             {
3027                 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
3028                  &keySize);
3029                 if (ret)
3030                 {
3031                     DWORD encodedLen = 0;
3032
3033                     ret = CryptEncodeObject(dwCertEncodingType,
3034                      RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
3035                     if (ret)
3036                     {
3037                         DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
3038                          strlen(pszPublicKeyObjId) + 1 + encodedLen;
3039
3040                         if (!pInfo)
3041                             *pcbInfo = sizeNeeded;
3042                         else if (*pcbInfo < sizeNeeded)
3043                         {
3044                             SetLastError(ERROR_MORE_DATA);
3045                             *pcbInfo = sizeNeeded;
3046                             ret = FALSE;
3047                         }
3048                         else
3049                         {
3050                             pInfo->Algorithm.pszObjId = (char *)pInfo +
3051                              sizeof(CERT_PUBLIC_KEY_INFO);
3052                             lstrcpyA(pInfo->Algorithm.pszObjId,
3053                              pszPublicKeyObjId);
3054                             pInfo->Algorithm.Parameters.cbData = 0;
3055                             pInfo->Algorithm.Parameters.pbData = NULL;
3056                             pInfo->PublicKey.pbData =
3057                              (BYTE *)pInfo->Algorithm.pszObjId
3058                              + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
3059                             pInfo->PublicKey.cbData = encodedLen;
3060                             pInfo->PublicKey.cUnusedBits = 0;
3061                             ret = CryptEncodeObject(dwCertEncodingType,
3062                              RSA_CSP_PUBLICKEYBLOB, pubKey,
3063                              pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
3064                         }
3065                     }
3066                 }
3067                 CryptMemFree(pubKey);
3068             }
3069             else
3070                 ret = FALSE;
3071         }
3072         CryptDestroyKey(key);
3073     }
3074     return ret;
3075 }
3076
3077 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3078  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3079  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
3080
3081 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3082  DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
3083  void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3084 {
3085     static HCRYPTOIDFUNCSET set = NULL;
3086     BOOL ret;
3087     ExportPublicKeyInfoExFunc exportFunc = NULL;
3088     HCRYPTOIDFUNCADDR hFunc = NULL;
3089
3090     TRACE("(%08lx, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3091      dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3092      pInfo, pcbInfo);
3093
3094     if (!hCryptProv)
3095     {
3096         SetLastError(ERROR_INVALID_PARAMETER);
3097         return FALSE;
3098     }
3099
3100     if (pszPublicKeyObjId)
3101     {
3102         if (!set)
3103             set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
3104              0);
3105         CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
3106          0, (void **)&exportFunc, &hFunc);
3107     }
3108     if (!exportFunc)
3109         exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
3110     ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
3111      pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
3112     if (hFunc)
3113         CryptFreeOIDFunctionAddress(hFunc, 0);
3114     return ret;
3115 }
3116
3117 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
3118  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
3119 {
3120     return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
3121      0, 0, NULL, phKey);
3122 }
3123
3124 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3125  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3126  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3127 {
3128     BOOL ret;
3129     DWORD pubKeySize = 0;
3130
3131     TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
3132      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3133
3134     ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3135      pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
3136     if (ret)
3137     {
3138         LPBYTE pubKey = CryptMemAlloc(pubKeySize);
3139
3140         if (pubKey)
3141         {
3142             ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3143              pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
3144              &pubKeySize);
3145             if (ret)
3146                 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
3147                  phKey);
3148             CryptMemFree(pubKey);
3149         }
3150         else
3151             ret = FALSE;
3152     }
3153     return ret;
3154 }
3155
3156 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3157  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3158  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
3159
3160 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3161  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3162  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3163 {
3164     static HCRYPTOIDFUNCSET set = NULL;
3165     BOOL ret;
3166     ImportPublicKeyInfoExFunc importFunc = NULL;
3167     HCRYPTOIDFUNCADDR hFunc = NULL;
3168
3169     TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
3170      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3171
3172     if (!set)
3173         set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
3174     CryptGetOIDFunctionAddress(set, dwCertEncodingType,
3175      pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
3176     if (!importFunc)
3177         importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
3178     ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
3179      pvAuxInfo, phKey);
3180     if (hFunc)
3181         CryptFreeOIDFunctionAddress(hFunc, 0);
3182     return ret;
3183 }