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