user: Added fast 16->32 mapping for the remaining messages.
[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         DWORD cItem = 4;
679
680         if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
681         {
682             items[cItem].pvStructInfo = &info->NextUpdate;
683             items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
684             cItem++;
685         }
686         if (info->cCRLEntry)
687         {
688             items[cItem].pvStructInfo = &info->cCRLEntry;
689             items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
690             cItem++;
691         }
692         if (info->cExtension)
693         {
694             items[cItem].pvStructInfo = &info->cExtension;
695             items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
696             cItem++;
697         }
698
699         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
700          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
701     }
702     __EXCEPT_PAGE_FAULT
703     {
704         SetLastError(STATUS_ACCESS_VIOLATION);
705         ret = FALSE;
706     }
707     __ENDTRY
708     return ret;
709 }
710
711 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
712  DWORD *pcbEncoded)
713 {
714     BOOL ret;
715     struct AsnEncodeSequenceItem items[3] = {
716      { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
717      { NULL, NULL, 0 },
718      { NULL, NULL, 0 },
719     };
720     DWORD cItem = 1;
721
722     TRACE("%p, %p, %ld\n", ext, pbEncoded, *pcbEncoded);
723
724     if (ext->fCritical)
725     {
726         items[cItem].pvStructInfo = &ext->fCritical;
727         items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
728         cItem++;
729     }
730     items[cItem].pvStructInfo = &ext->Value;
731     items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
732     cItem++;
733
734     ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
735      pbEncoded, pcbEncoded);
736     TRACE("returning %d (%08lx)\n", ret, GetLastError());
737     return ret;
738 }
739
740 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
741  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
742  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
743 {
744     BOOL ret;
745
746     __TRY
747     {
748         DWORD bytesNeeded, dataLen, lenBytes, i;
749         const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
750
751         ret = TRUE;
752         for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
753         {
754             DWORD size;
755
756             ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
757             if (ret)
758                 dataLen += size;
759         }
760         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
761         bytesNeeded = 1 + lenBytes + dataLen;
762         if (!pbEncoded)
763             *pcbEncoded = bytesNeeded;
764         else
765         {
766             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
767              pcbEncoded, bytesNeeded)))
768             {
769                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
770                     pbEncoded = *(BYTE **)pbEncoded;
771                 *pbEncoded++ = ASN_SEQUENCEOF;
772                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
773                 pbEncoded += lenBytes;
774                 for (i = 0; i < exts->cExtension; i++)
775                 {
776                     DWORD size = dataLen;
777
778                     ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
779                      pbEncoded, &size);
780                     pbEncoded += size;
781                     dataLen -= size;
782                 }
783             }
784         }
785     }
786     __EXCEPT_PAGE_FAULT
787     {
788         SetLastError(STATUS_ACCESS_VIOLATION);
789         ret = FALSE;
790     }
791     __ENDTRY
792     return ret;
793 }
794
795 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
796  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
797  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
798 {
799     LPCSTR pszObjId = (LPCSTR)pvStructInfo;
800     DWORD bytesNeeded = 0, lenBytes;
801     BOOL ret = TRUE;
802     int firstPos = 0;
803     BYTE firstByte = 0;
804
805     TRACE("%s\n", debugstr_a(pszObjId));
806
807     if (pszObjId)
808     {
809         const char *ptr;
810         int val1, val2;
811
812         if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
813         {
814             SetLastError(CRYPT_E_ASN1_ERROR);
815             return FALSE;
816         }
817         bytesNeeded++;
818         firstByte = val1 * 40 + val2;
819         ptr = pszObjId + firstPos;
820         while (ret && *ptr)
821         {
822             int pos;
823
824             /* note I assume each component is at most 32-bits long in base 2 */
825             if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
826             {
827                 if (val1 >= 0x10000000)
828                     bytesNeeded += 5;
829                 else if (val1 >= 0x200000)
830                     bytesNeeded += 4;
831                 else if (val1 >= 0x4000)
832                     bytesNeeded += 3;
833                 else if (val1 >= 0x80)
834                     bytesNeeded += 2;
835                 else
836                     bytesNeeded += 1;
837                 ptr += pos;
838                 if (*ptr == '.')
839                     ptr++;
840             }
841             else
842             {
843                 SetLastError(CRYPT_E_ASN1_ERROR);
844                 return FALSE;
845             }
846         }
847         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
848     }
849     else
850         lenBytes = 1;
851     bytesNeeded += 1 + lenBytes;
852     if (pbEncoded)
853     {
854         if (*pcbEncoded < bytesNeeded)
855         {
856             SetLastError(ERROR_MORE_DATA);
857             ret = FALSE;
858         }
859         else
860         {
861             *pbEncoded++ = ASN_OBJECTIDENTIFIER;
862             CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
863             pbEncoded += lenBytes;
864             if (pszObjId)
865             {
866                 const char *ptr;
867                 int val, pos;
868
869                 *pbEncoded++ = firstByte;
870                 ptr = pszObjId + firstPos;
871                 while (ret && *ptr)
872                 {
873                     sscanf(ptr, "%d%n", &val, &pos);
874                     {
875                         unsigned char outBytes[5];
876                         int numBytes, i;
877
878                         if (val >= 0x10000000)
879                             numBytes = 5;
880                         else if (val >= 0x200000)
881                             numBytes = 4;
882                         else if (val >= 0x4000)
883                             numBytes = 3;
884                         else if (val >= 0x80)
885                             numBytes = 2;
886                         else
887                             numBytes = 1;
888                         for (i = numBytes; i > 0; i--)
889                         {
890                             outBytes[i - 1] = val & 0x7f;
891                             val >>= 7;
892                         }
893                         for (i = 0; i < numBytes - 1; i++)
894                             *pbEncoded++ = outBytes[i] | 0x80;
895                         *pbEncoded++ = outBytes[i];
896                         ptr += pos;
897                         if (*ptr == '.')
898                             ptr++;
899                     }
900                 }
901             }
902         }
903     }
904     *pcbEncoded = bytesNeeded;
905     return ret;
906 }
907
908 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
909  CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
910 {
911     BYTE tag;
912     DWORD bytesNeeded, lenBytes, encodedLen;
913     BOOL ret = TRUE;
914
915     switch (value->dwValueType)
916     {
917     case CERT_RDN_NUMERIC_STRING:
918         tag = ASN_NUMERICSTRING;
919         encodedLen = value->Value.cbData;
920         break;
921     case CERT_RDN_PRINTABLE_STRING:
922         tag = ASN_PRINTABLESTRING;
923         encodedLen = value->Value.cbData;
924         break;
925     case CERT_RDN_IA5_STRING:
926         tag = ASN_IA5STRING;
927         encodedLen = value->Value.cbData;
928         break;
929     case CERT_RDN_ANY_TYPE:
930         /* explicitly disallowed */
931         SetLastError(E_INVALIDARG);
932         return FALSE;
933     default:
934         FIXME("String type %ld unimplemented\n", value->dwValueType);
935         return FALSE;
936     }
937     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
938     bytesNeeded = 1 + lenBytes + encodedLen;
939     if (pbEncoded)
940     {
941         if (*pcbEncoded < bytesNeeded)
942         {
943             SetLastError(ERROR_MORE_DATA);
944             ret = FALSE;
945         }
946         else
947         {
948             *pbEncoded++ = tag;
949             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
950             pbEncoded += lenBytes;
951             switch (value->dwValueType)
952             {
953             case CERT_RDN_NUMERIC_STRING:
954             case CERT_RDN_PRINTABLE_STRING:
955             case CERT_RDN_IA5_STRING:
956                 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
957             }
958         }
959     }
960     *pcbEncoded = bytesNeeded;
961     return ret;
962 }
963
964 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
965  CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
966 {
967     DWORD bytesNeeded = 0, lenBytes, size;
968     BOOL ret;
969
970     ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
971      0, NULL, NULL, &size);
972     if (ret)
973     {
974         bytesNeeded += size;
975         /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
976          * with dwValueType, so "cast" it to get its encoded size
977          */
978         ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
979          (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
980         if (ret)
981         {
982             bytesNeeded += size;
983             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
984             bytesNeeded += 1 + lenBytes;
985             if (pbEncoded)
986             {
987                 if (*pcbEncoded < bytesNeeded)
988                 {
989                     SetLastError(ERROR_MORE_DATA);
990                     ret = FALSE;
991                 }
992                 else
993                 {
994                     *pbEncoded++ = ASN_SEQUENCE;
995                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
996                      &lenBytes);
997                     pbEncoded += lenBytes;
998                     size = bytesNeeded - 1 - lenBytes;
999                     ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1000                      attr->pszObjId, 0, NULL, pbEncoded, &size);
1001                     if (ret)
1002                     {
1003                         pbEncoded += size;
1004                         size = bytesNeeded - 1 - lenBytes - size;
1005                         ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1006                          (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
1007                          &size);
1008                     }
1009                 }
1010             }
1011             *pcbEncoded = bytesNeeded;
1012         }
1013     }
1014     return ret;
1015 }
1016
1017 static int BLOBComp(const void *l, const void *r)
1018 {
1019     CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
1020     int ret;
1021
1022     if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1023         ret = a->cbData - b->cbData;
1024     return ret;
1025 }
1026
1027 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1028  */
1029 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1030  BYTE *pbEncoded, DWORD *pcbEncoded)
1031 {
1032     BOOL ret;
1033     CRYPT_DER_BLOB *blobs = NULL;
1034
1035     __TRY
1036     {
1037         DWORD bytesNeeded = 0, lenBytes, i;
1038
1039         blobs = NULL;
1040         ret = TRUE;
1041         if (rdn->cRDNAttr)
1042         {
1043             blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1044             if (!blobs)
1045                 ret = FALSE;
1046             else
1047                 memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1048         }
1049         for (i = 0; ret && i < rdn->cRDNAttr; i++)
1050         {
1051             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1052              NULL, &blobs[i].cbData);
1053             if (ret)
1054                 bytesNeeded += blobs[i].cbData;
1055         }
1056         if (ret)
1057         {
1058             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1059             bytesNeeded += 1 + lenBytes;
1060             if (pbEncoded)
1061             {
1062                 if (*pcbEncoded < bytesNeeded)
1063                 {
1064                     SetLastError(ERROR_MORE_DATA);
1065                     ret = FALSE;
1066                 }
1067                 else
1068                 {
1069                     for (i = 0; ret && i < rdn->cRDNAttr; i++)
1070                     {
1071                         blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
1072                         if (!blobs[i].pbData)
1073                             ret = FALSE;
1074                         else
1075                             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1076                              &rdn->rgRDNAttr[i], blobs[i].pbData,
1077                              &blobs[i].cbData);
1078                     }
1079                     if (ret)
1080                     {
1081                         qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1082                          BLOBComp);
1083                         *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1084                         CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1085                          &lenBytes);
1086                         pbEncoded += lenBytes;
1087                         for (i = 0; ret && i < rdn->cRDNAttr; i++)
1088                         {
1089                             memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1090                             pbEncoded += blobs[i].cbData;
1091                         }
1092                     }
1093                 }
1094             }
1095             *pcbEncoded = bytesNeeded;
1096         }
1097         if (blobs)
1098         {
1099             for (i = 0; i < rdn->cRDNAttr; i++)
1100                 CryptMemFree(blobs[i].pbData);
1101         }
1102     }
1103     __EXCEPT_PAGE_FAULT
1104     {
1105         SetLastError(STATUS_ACCESS_VIOLATION);
1106         ret = FALSE;
1107     }
1108     __ENDTRY
1109     CryptMemFree(blobs);
1110     return ret;
1111 }
1112
1113 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1114  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1115  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1116 {
1117     BOOL ret;
1118
1119     __TRY
1120     {
1121         const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1122         DWORD bytesNeeded = 0, lenBytes, size, i;
1123
1124         TRACE("encoding name with %ld RDNs\n", info->cRDN);
1125         ret = TRUE;
1126         for (i = 0; ret && i < info->cRDN; i++)
1127         {
1128             ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1129              &size);
1130             if (ret)
1131                 bytesNeeded += size;
1132         }
1133         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1134         bytesNeeded += 1 + lenBytes;
1135         if (ret)
1136         {
1137             if (!pbEncoded)
1138                 *pcbEncoded = bytesNeeded;
1139             else
1140             {
1141                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1142                  pbEncoded, pcbEncoded, bytesNeeded)))
1143                 {
1144                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1145                         pbEncoded = *(BYTE **)pbEncoded;
1146                     *pbEncoded++ = ASN_SEQUENCEOF;
1147                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1148                      &lenBytes);
1149                     pbEncoded += lenBytes;
1150                     for (i = 0; ret && i < info->cRDN; i++)
1151                     {
1152                         size = bytesNeeded;
1153                         ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1154                          &info->rgRDN[i], pbEncoded, &size);
1155                         if (ret)
1156                         {
1157                             pbEncoded += size;
1158                             bytesNeeded -= size;
1159                         }
1160                     }
1161                 }
1162             }
1163         }
1164     }
1165     __EXCEPT_PAGE_FAULT
1166     {
1167         SetLastError(STATUS_ACCESS_VIOLATION);
1168         ret = FALSE;
1169     }
1170     __ENDTRY
1171     return ret;
1172 }
1173
1174 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1175  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1176  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1177 {
1178     BOOL val = *(const BOOL *)pvStructInfo, ret;
1179
1180     TRACE("%d\n", val);
1181
1182     if (!pbEncoded)
1183     {
1184         *pcbEncoded = 3;
1185         ret = TRUE;
1186     }
1187     else if (*pcbEncoded < 3)
1188     {
1189         *pcbEncoded = 3;
1190         SetLastError(ERROR_MORE_DATA);
1191         ret = FALSE;
1192     }
1193     else
1194     {
1195         *pcbEncoded = 3;
1196         *pbEncoded++ = ASN_BOOL;
1197         *pbEncoded++ = 1;
1198         *pbEncoded++ = val ? 0xff : 0;
1199         ret = TRUE;
1200     }
1201     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1202     return ret;
1203 }
1204
1205 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1206  BYTE *pbEncoded, DWORD *pcbEncoded)
1207 {
1208     BOOL ret;
1209     DWORD dataLen;
1210
1211     ret = TRUE;
1212     switch (entry->dwAltNameChoice)
1213     {
1214     case CERT_ALT_NAME_RFC822_NAME:
1215     case CERT_ALT_NAME_DNS_NAME:
1216     case CERT_ALT_NAME_URL:
1217         if (entry->u.pwszURL)
1218         {
1219             DWORD i;
1220
1221             /* Not + 1: don't encode the NULL-terminator */
1222             dataLen = lstrlenW(entry->u.pwszURL);
1223             for (i = 0; ret && i < dataLen; i++)
1224             {
1225                 if (entry->u.pwszURL[i] > 0x7f)
1226                 {
1227                     SetLastError(CRYPT_E_INVALID_IA5_STRING);
1228                     ret = FALSE;
1229                     *pcbEncoded = i;
1230                 }
1231             }
1232         }
1233         else
1234             dataLen = 0;
1235         break;
1236     case CERT_ALT_NAME_IP_ADDRESS:
1237         dataLen = entry->u.IPAddress.cbData;
1238         break;
1239     case CERT_ALT_NAME_REGISTERED_ID:
1240         /* FIXME: encode OID */
1241     case CERT_ALT_NAME_OTHER_NAME:
1242     case CERT_ALT_NAME_DIRECTORY_NAME:
1243         FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice);
1244         return FALSE;
1245     default:
1246         SetLastError(E_INVALIDARG);
1247         return FALSE;
1248     }
1249     if (ret)
1250     {
1251         DWORD bytesNeeded, lenBytes;
1252
1253         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1254         bytesNeeded = 1 + dataLen + lenBytes;
1255         if (!pbEncoded)
1256             *pcbEncoded = bytesNeeded;
1257         else if (*pcbEncoded < bytesNeeded)
1258         {
1259             SetLastError(ERROR_MORE_DATA);
1260             *pcbEncoded = bytesNeeded;
1261             ret = FALSE;
1262         }
1263         else
1264         {
1265             *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1266             CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1267             pbEncoded += lenBytes;
1268             switch (entry->dwAltNameChoice)
1269             {
1270             case CERT_ALT_NAME_RFC822_NAME:
1271             case CERT_ALT_NAME_DNS_NAME:
1272             case CERT_ALT_NAME_URL:
1273             {
1274                 DWORD i;
1275
1276                 for (i = 0; i < dataLen; i++)
1277                     *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1278                 break;
1279             }
1280             case CERT_ALT_NAME_IP_ADDRESS:
1281                 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1282                 break;
1283             }
1284             if (ret)
1285                 *pcbEncoded = bytesNeeded;
1286         }
1287     }
1288     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1289     return ret;
1290 }
1291
1292 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1293  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1294  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1295 {
1296     BOOL ret;
1297
1298     __TRY
1299     {
1300         const CERT_ALT_NAME_INFO *info =
1301          (const CERT_ALT_NAME_INFO *)pvStructInfo;
1302         DWORD bytesNeeded, dataLen, lenBytes, i;
1303
1304         ret = TRUE;
1305         /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1306          * can't encode an erroneous entry index if it's bigger than this.
1307          */
1308         for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1309         {
1310             DWORD len;
1311
1312             ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1313              &len);
1314             if (ret)
1315                 dataLen += len;
1316             else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1317             {
1318                 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1319                  * the bad character, now set the index of the bad
1320                  * entry
1321                  */
1322                 *pcbEncoded = (BYTE)i <<
1323                  CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1324             }
1325         }
1326         if (ret)
1327         {
1328             CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1329             bytesNeeded = 1 + lenBytes + dataLen;
1330             if (!pbEncoded)
1331             {
1332                 *pcbEncoded = bytesNeeded;
1333                 ret = TRUE;
1334             }
1335             else
1336             {
1337                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1338                  pbEncoded, pcbEncoded, bytesNeeded)))
1339                 {
1340                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1341                         pbEncoded = *(BYTE **)pbEncoded;
1342                     *pbEncoded++ = ASN_SEQUENCEOF;
1343                     CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1344                     pbEncoded += lenBytes;
1345                     for (i = 0; ret && i < info->cAltEntry; i++)
1346                     {
1347                         DWORD len = dataLen;
1348
1349                         ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1350                          pbEncoded, &len);
1351                         if (ret)
1352                         {
1353                             pbEncoded += len;
1354                             dataLen -= len;
1355                         }
1356                     }
1357                 }
1358             }
1359         }
1360     }
1361     __EXCEPT_PAGE_FAULT
1362     {
1363         SetLastError(STATUS_ACCESS_VIOLATION);
1364         ret = FALSE;
1365     }
1366     __ENDTRY
1367     return ret;
1368 }
1369
1370 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
1371  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1372  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1373 {
1374     BOOL ret;
1375
1376     __TRY
1377     {
1378         const CERT_BASIC_CONSTRAINTS_INFO *info =
1379          (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
1380         struct AsnEncodeSequenceItem items[3] = {
1381          { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
1382          { 0 }
1383         };
1384         DWORD cItem = 1;
1385
1386         if (info->fPathLenConstraint)
1387         {
1388             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1389             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1390             cItem++;
1391         }
1392         if (info->cSubtreesConstraint)
1393         {
1394             items[cItem].pvStructInfo = &info->cSubtreesConstraint;
1395             items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
1396             cItem++;
1397         }
1398         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1399          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1400     }
1401     __EXCEPT_PAGE_FAULT
1402     {
1403         SetLastError(STATUS_ACCESS_VIOLATION);
1404         ret = FALSE;
1405     }
1406     __ENDTRY
1407     return ret;
1408 }
1409
1410 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1411  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1412  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1413 {
1414     BOOL ret;
1415
1416     __TRY
1417     {
1418         const CERT_BASIC_CONSTRAINTS2_INFO *info =
1419          (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1420         struct AsnEncodeSequenceItem items[2] = { { 0 } };
1421         DWORD cItem = 0;
1422
1423         if (info->fCA)
1424         {
1425             items[cItem].pvStructInfo = &info->fCA;
1426             items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1427             cItem++;
1428         }
1429         if (info->fPathLenConstraint)
1430         {
1431             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1432             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1433             cItem++;
1434         }
1435         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1436          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1437     }
1438     __EXCEPT_PAGE_FAULT
1439     {
1440         SetLastError(STATUS_ACCESS_VIOLATION);
1441         ret = FALSE;
1442     }
1443     __ENDTRY
1444     return ret;
1445 }
1446
1447 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
1448  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1449  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1450 {
1451     BOOL ret;
1452
1453     __TRY
1454     {
1455         const BLOBHEADER *hdr =
1456          (const BLOBHEADER *)pvStructInfo;
1457
1458         if (hdr->bType != PUBLICKEYBLOB)
1459         {
1460             SetLastError(E_INVALIDARG);
1461             ret = FALSE;
1462         }
1463         else
1464         {
1465             const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
1466              ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
1467             CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
1468              (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
1469             struct AsnEncodeSequenceItem items[] = { 
1470              { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
1471              { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
1472             };
1473
1474             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1475              sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1476              pcbEncoded);
1477         }
1478     }
1479     __EXCEPT_PAGE_FAULT
1480     {
1481         SetLastError(STATUS_ACCESS_VIOLATION);
1482         ret = FALSE;
1483     }
1484     __ENDTRY
1485     return ret;
1486 }
1487
1488 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1489  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1490  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1491 {
1492     BOOL ret;
1493
1494     __TRY
1495     {
1496         const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1497         DWORD bytesNeeded, lenBytes;
1498
1499         TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1500          dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1501
1502         CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1503         bytesNeeded = 1 + lenBytes + blob->cbData;
1504         if (!pbEncoded)
1505         {
1506             *pcbEncoded = bytesNeeded;
1507             ret = TRUE;
1508         }
1509         else
1510         {
1511             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1512              pcbEncoded, bytesNeeded)))
1513             {
1514                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1515                     pbEncoded = *(BYTE **)pbEncoded;
1516                 *pbEncoded++ = ASN_OCTETSTRING;
1517                 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1518                 pbEncoded += lenBytes;
1519                 if (blob->cbData)
1520                     memcpy(pbEncoded, blob->pbData, blob->cbData);
1521             }
1522         }
1523     }
1524     __EXCEPT_PAGE_FAULT
1525     {
1526         SetLastError(STATUS_ACCESS_VIOLATION);
1527         ret = FALSE;
1528     }
1529     __ENDTRY
1530     TRACE("returning %d (%08lx)\n", ret, GetLastError());
1531     return ret;
1532 }
1533
1534 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1535  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1536  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1537 {
1538     BOOL ret;
1539
1540     __TRY
1541     {
1542         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1543         DWORD bytesNeeded, lenBytes, dataBytes;
1544         BYTE unusedBits;
1545
1546         /* yep, MS allows cUnusedBits to be >= 8 */
1547         if (!blob->cUnusedBits)
1548         {
1549             dataBytes = blob->cbData;
1550             unusedBits = 0;
1551         }
1552         else if (blob->cbData * 8 > blob->cUnusedBits)
1553         {
1554             dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1555             unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1556              blob->cUnusedBits;
1557         }
1558         else
1559         {
1560             dataBytes = 0;
1561             unusedBits = 0;
1562         }
1563         CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1564         bytesNeeded = 1 + lenBytes + dataBytes + 1;
1565         if (!pbEncoded)
1566         {
1567             *pcbEncoded = bytesNeeded;
1568             ret = TRUE;
1569         }
1570         else
1571         {
1572             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1573              pcbEncoded, bytesNeeded)))
1574             {
1575                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1576                     pbEncoded = *(BYTE **)pbEncoded;
1577                 *pbEncoded++ = ASN_BITSTRING;
1578                 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1579                 pbEncoded += lenBytes;
1580                 *pbEncoded++ = unusedBits;
1581                 if (dataBytes)
1582                 {
1583                     BYTE mask = 0xff << unusedBits;
1584
1585                     if (dataBytes > 1)
1586                     {
1587                         memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1588                         pbEncoded += dataBytes - 1;
1589                     }
1590                     *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1591                 }
1592             }
1593         }
1594     }
1595     __EXCEPT_PAGE_FAULT
1596     {
1597         SetLastError(STATUS_ACCESS_VIOLATION);
1598         ret = FALSE;
1599     }
1600     __ENDTRY
1601     return ret;
1602 }
1603
1604 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
1605  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1606  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1607 {
1608     BOOL ret;
1609
1610     __TRY
1611     {
1612         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1613         CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
1614
1615         ret = TRUE;
1616         if (newBlob.cbData)
1617         {
1618             newBlob.pbData = CryptMemAlloc(newBlob.cbData);
1619             if (newBlob.pbData)
1620             {
1621                 DWORD i;
1622
1623                 for (i = 0; i < newBlob.cbData; i++)
1624                     newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
1625             }
1626             else
1627                 ret = FALSE;
1628         }
1629         if (ret)
1630             ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
1631              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1632         CryptMemFree(newBlob.pbData);
1633     }
1634     __EXCEPT_PAGE_FAULT
1635     {
1636         SetLastError(STATUS_ACCESS_VIOLATION);
1637         ret = FALSE;
1638     }
1639     __ENDTRY
1640     return ret;
1641 }
1642
1643 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1644  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1645  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1646 {
1647     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1648
1649     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1650      &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1651 }
1652
1653 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1654  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1655  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1656 {
1657     BOOL ret;
1658
1659     __TRY
1660     {
1661         DWORD significantBytes, lenBytes;
1662         BYTE padByte = 0, bytesNeeded;
1663         BOOL pad = FALSE;
1664         const CRYPT_INTEGER_BLOB *blob =
1665          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1666
1667         significantBytes = blob->cbData;
1668         if (significantBytes)
1669         {
1670             if (blob->pbData[significantBytes - 1] & 0x80)
1671             {
1672                 /* negative, lop off leading (little-endian) 0xffs */
1673                 for (; significantBytes > 0 &&
1674                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1675                     ;
1676                 if (blob->pbData[significantBytes - 1] < 0x80)
1677                 {
1678                     padByte = 0xff;
1679                     pad = TRUE;
1680                 }
1681             }
1682             else
1683             {
1684                 /* positive, lop off leading (little-endian) zeroes */
1685                 for (; significantBytes > 0 &&
1686                  !blob->pbData[significantBytes - 1]; significantBytes--)
1687                     ;
1688                 if (significantBytes == 0)
1689                     significantBytes = 1;
1690                 if (blob->pbData[significantBytes - 1] > 0x7f)
1691                 {
1692                     padByte = 0;
1693                     pad = TRUE;
1694                 }
1695             }
1696         }
1697         if (pad)
1698             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1699         else
1700             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1701         bytesNeeded = 1 + lenBytes + significantBytes;
1702         if (pad)
1703             bytesNeeded++;
1704         if (!pbEncoded)
1705         {
1706             *pcbEncoded = bytesNeeded;
1707             ret = TRUE;
1708         }
1709         else
1710         {
1711             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1712              pcbEncoded, bytesNeeded)))
1713             {
1714                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1715                     pbEncoded = *(BYTE **)pbEncoded;
1716                 *pbEncoded++ = ASN_INTEGER;
1717                 if (pad)
1718                 {
1719                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1720                     pbEncoded += lenBytes;
1721                     *pbEncoded++ = padByte;
1722                 }
1723                 else
1724                 {
1725                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1726                     pbEncoded += lenBytes;
1727                 }
1728                 for (; significantBytes > 0; significantBytes--)
1729                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
1730             }
1731         }
1732     }
1733     __EXCEPT_PAGE_FAULT
1734     {
1735         SetLastError(STATUS_ACCESS_VIOLATION);
1736         ret = FALSE;
1737     }
1738     __ENDTRY
1739     return ret;
1740 }
1741
1742 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1743  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1744  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1745 {
1746     BOOL ret;
1747
1748     __TRY
1749     {
1750         DWORD significantBytes, lenBytes;
1751         BYTE bytesNeeded;
1752         BOOL pad = FALSE;
1753         const CRYPT_INTEGER_BLOB *blob =
1754          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1755
1756         significantBytes = blob->cbData;
1757         if (significantBytes)
1758         {
1759             /* positive, lop off leading (little-endian) zeroes */
1760             for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1761              significantBytes--)
1762                 ;
1763             if (significantBytes == 0)
1764                 significantBytes = 1;
1765             if (blob->pbData[significantBytes - 1] > 0x7f)
1766                 pad = TRUE;
1767         }
1768         if (pad)
1769             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1770         else
1771             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1772         bytesNeeded = 1 + lenBytes + significantBytes;
1773         if (pad)
1774             bytesNeeded++;
1775         if (!pbEncoded)
1776         {
1777             *pcbEncoded = bytesNeeded;
1778             ret = TRUE;
1779         }
1780         else
1781         {
1782             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1783              pcbEncoded, bytesNeeded)))
1784             {
1785                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1786                     pbEncoded = *(BYTE **)pbEncoded;
1787                 *pbEncoded++ = ASN_INTEGER;
1788                 if (pad)
1789                 {
1790                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1791                     pbEncoded += lenBytes;
1792                     *pbEncoded++ = 0;
1793                 }
1794                 else
1795                 {
1796                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1797                     pbEncoded += lenBytes;
1798                 }
1799                 for (; significantBytes > 0; significantBytes--)
1800                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
1801             }
1802         }
1803     }
1804     __EXCEPT_PAGE_FAULT
1805     {
1806         SetLastError(STATUS_ACCESS_VIOLATION);
1807         ret = FALSE;
1808     }
1809     __ENDTRY
1810     return ret;
1811 }
1812
1813 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
1814  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1815  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1816 {
1817     CRYPT_INTEGER_BLOB blob;
1818     BOOL ret;
1819
1820     /* Encode as an unsigned integer, then change the tag to enumerated */
1821     blob.cbData = sizeof(DWORD);
1822     blob.pbData = (BYTE *)pvStructInfo;
1823     ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
1824      X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1825     if (ret && pbEncoded)
1826     {
1827         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1828             pbEncoded = *(BYTE **)pbEncoded;
1829         pbEncoded[0] = ASN_ENUMERATED;
1830     }
1831     return ret;
1832 }
1833
1834 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
1835  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1836  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1837 {
1838     BOOL ret;
1839
1840     __TRY
1841     {
1842         SYSTEMTIME sysTime;
1843         /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
1844          * temporary buffer because the output buffer is not NULL-terminated.
1845          */
1846         char buf[16];
1847         static const DWORD bytesNeeded = sizeof(buf) - 1;
1848
1849         if (!pbEncoded)
1850         {
1851             *pcbEncoded = bytesNeeded;
1852             ret = TRUE;
1853         }
1854         else
1855         {
1856             /* Sanity check the year, this is a two-digit year format */
1857             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1858              &sysTime);
1859             if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
1860             {
1861                 SetLastError(CRYPT_E_BAD_ENCODE);
1862                 ret = FALSE;
1863             }
1864             if (ret)
1865             {
1866                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1867                  pbEncoded, pcbEncoded, bytesNeeded)))
1868                 {
1869                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1870                         pbEncoded = *(BYTE **)pbEncoded;
1871                     buf[0] = ASN_UTCTIME;
1872                     buf[1] = bytesNeeded - 2;
1873                     snprintf(buf + 2, sizeof(buf) - 2,
1874                      "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
1875                      sysTime.wYear - 2000 : sysTime.wYear - 1900,
1876                      sysTime.wMonth, sysTime.wDay, sysTime.wHour,
1877                      sysTime.wMinute, sysTime.wSecond);
1878                     memcpy(pbEncoded, buf, bytesNeeded);
1879                 }
1880             }
1881         }
1882     }
1883     __EXCEPT_PAGE_FAULT
1884     {
1885         SetLastError(STATUS_ACCESS_VIOLATION);
1886         ret = FALSE;
1887     }
1888     __ENDTRY
1889     return ret;
1890 }
1891
1892 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
1893  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1894  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1895 {
1896     BOOL ret;
1897
1898     __TRY
1899     {
1900         SYSTEMTIME sysTime;
1901         /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
1902          * temporary buffer because the output buffer is not NULL-terminated.
1903          */
1904         char buf[18];
1905         static const DWORD bytesNeeded = sizeof(buf) - 1;
1906
1907         if (!pbEncoded)
1908         {
1909             *pcbEncoded = bytesNeeded;
1910             ret = TRUE;
1911         }
1912         else
1913         {
1914             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1915              &sysTime);
1916             if (ret)
1917                 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1918                  pcbEncoded, bytesNeeded);
1919             if (ret)
1920             {
1921                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1922                     pbEncoded = *(BYTE **)pbEncoded;
1923                 buf[0] = ASN_GENERALTIME;
1924                 buf[1] = bytesNeeded - 2;
1925                 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
1926                  sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
1927                  sysTime.wMinute, sysTime.wSecond);
1928                 memcpy(pbEncoded, buf, bytesNeeded);
1929             }
1930         }
1931     }
1932     __EXCEPT_PAGE_FAULT
1933     {
1934         SetLastError(STATUS_ACCESS_VIOLATION);
1935         ret = FALSE;
1936     }
1937     __ENDTRY
1938     return ret;
1939 }
1940
1941 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
1942  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1943  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1944 {
1945     BOOL ret;
1946
1947     __TRY
1948     {
1949         SYSTEMTIME sysTime;
1950
1951         /* Check the year, if it's in the UTCTime range call that encode func */
1952         if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
1953             return FALSE;
1954         if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
1955             ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
1956              pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1957         else
1958             ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
1959              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
1960              pcbEncoded);
1961     }
1962     __EXCEPT_PAGE_FAULT
1963     {
1964         SetLastError(STATUS_ACCESS_VIOLATION);
1965         ret = FALSE;
1966     }
1967     __ENDTRY
1968     return ret;
1969 }
1970
1971 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
1972  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1973  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1974 {
1975     BOOL ret;
1976
1977     __TRY
1978     {
1979         DWORD bytesNeeded, dataLen, lenBytes, i;
1980         const CRYPT_SEQUENCE_OF_ANY *seq =
1981          (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
1982
1983         for (i = 0, dataLen = 0; i < seq->cValue; i++)
1984             dataLen += seq->rgValue[i].cbData;
1985         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1986         bytesNeeded = 1 + lenBytes + dataLen;
1987         if (!pbEncoded)
1988         {
1989             *pcbEncoded = bytesNeeded;
1990             ret = TRUE;
1991         }
1992         else
1993         {
1994             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1995              pcbEncoded, bytesNeeded)))
1996             {
1997                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1998                     pbEncoded = *(BYTE **)pbEncoded;
1999                 *pbEncoded++ = ASN_SEQUENCEOF;
2000                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2001                 pbEncoded += lenBytes;
2002                 for (i = 0; i < seq->cValue; i++)
2003                 {
2004                     memcpy(pbEncoded, seq->rgValue[i].pbData,
2005                      seq->rgValue[i].cbData);
2006                     pbEncoded += seq->rgValue[i].cbData;
2007                 }
2008             }
2009         }
2010     }
2011     __EXCEPT_PAGE_FAULT
2012     {
2013         SetLastError(STATUS_ACCESS_VIOLATION);
2014         ret = FALSE;
2015     }
2016     __ENDTRY
2017     return ret;
2018 }
2019
2020 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2021  BYTE *pbEncoded, DWORD *pcbEncoded)
2022 {
2023     BOOL ret = TRUE;
2024     struct AsnEncodeSequenceItem items[3] = { { 0 } };
2025     struct AsnConstructedItem constructed = { 0 };
2026     struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2027     DWORD cItem = 0, cSwapped = 0;
2028
2029     switch (distPoint->DistPointName.dwDistPointNameChoice)
2030     {
2031     case CRL_DIST_POINT_NO_NAME:
2032         /* do nothing */
2033         break;
2034     case CRL_DIST_POINT_FULL_NAME:
2035         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2036         swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2037         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2038         constructed.tag = 0;
2039         constructed.pvStructInfo = &swapped[cSwapped];
2040         constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2041         items[cItem].pvStructInfo = &constructed;
2042         items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2043         cSwapped++;
2044         cItem++;
2045         break;
2046     case CRL_DIST_POINT_ISSUER_RDN_NAME:
2047         FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2048         ret = FALSE;
2049         break;
2050     default:
2051         ret = FALSE;
2052     }
2053     if (ret && distPoint->ReasonFlags.cbData)
2054     {
2055         swapped[cSwapped].tag = ASN_CONTEXT | 1;
2056         swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2057         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2058         items[cItem].pvStructInfo = &swapped[cSwapped];
2059         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2060         cSwapped++;
2061         cItem++;
2062     }
2063     if (ret && distPoint->CRLIssuer.cAltEntry)
2064     {
2065         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2066         swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2067         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2068         items[cItem].pvStructInfo = &swapped[cSwapped];
2069         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2070         cSwapped++;
2071         cItem++;
2072     }
2073     if (ret)
2074         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2075          pbEncoded, pcbEncoded);
2076     return ret;
2077 }
2078
2079 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2080  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2081  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2082 {
2083     BOOL ret;
2084
2085     __TRY
2086     {
2087         const CRL_DIST_POINTS_INFO *info =
2088          (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2089
2090         if (!info->cDistPoint)
2091         {
2092             SetLastError(E_INVALIDARG);
2093             ret = FALSE;
2094         }
2095         else
2096         {
2097             DWORD bytesNeeded, dataLen, lenBytes, i;
2098
2099             ret = TRUE;
2100             for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2101             {
2102                 DWORD len;
2103
2104                 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2105                  &len);
2106                 if (ret)
2107                     dataLen += len;
2108                 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2109                 {
2110                     /* Have to propagate index of failing character */
2111                     *pcbEncoded = len;
2112                 }
2113             }
2114             if (ret)
2115             {
2116                 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2117                 bytesNeeded = 1 + lenBytes + dataLen;
2118                 if (!pbEncoded)
2119                 {
2120                     *pcbEncoded = bytesNeeded;
2121                     ret = TRUE;
2122                 }
2123                 else
2124                 {
2125                     if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2126                      pbEncoded, pcbEncoded, bytesNeeded)))
2127                     {
2128                         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2129                             pbEncoded = *(BYTE **)pbEncoded;
2130                         *pbEncoded++ = ASN_SEQUENCEOF;
2131                         CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2132                         pbEncoded += lenBytes;
2133                         for (i = 0; ret && i < info->cDistPoint; i++)
2134                         {
2135                             DWORD len = dataLen;
2136
2137                             ret = CRYPT_AsnEncodeDistPoint(
2138                              &info->rgDistPoint[i], pbEncoded, &len);
2139                             if (ret)
2140                             {
2141                                 pbEncoded += len;
2142                                 dataLen -= len;
2143                             }
2144                         }
2145                     }
2146                 }
2147             }
2148         }
2149     }
2150     __EXCEPT_PAGE_FAULT
2151     {
2152         SetLastError(STATUS_ACCESS_VIOLATION);
2153         ret = FALSE;
2154     }
2155     __ENDTRY
2156     return ret;
2157 }
2158
2159 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
2160  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2161  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2162 {
2163     BOOL ret;
2164
2165     __TRY
2166     {
2167         const CERT_ENHKEY_USAGE *usage =
2168          (const CERT_ENHKEY_USAGE *)pvStructInfo;
2169         DWORD bytesNeeded = 0, lenBytes, size, i;
2170
2171         ret = TRUE;
2172         for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2173         {
2174             ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2175              usage->rgpszUsageIdentifier[i],
2176              dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
2177             if (ret)
2178                 bytesNeeded += size;
2179         }
2180         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2181         bytesNeeded += 1 + lenBytes;
2182         if (ret)
2183         {
2184             if (!pbEncoded)
2185                 *pcbEncoded = bytesNeeded;
2186             else
2187             {
2188                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2189                  pbEncoded, pcbEncoded, bytesNeeded)))
2190                 {
2191                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2192                         pbEncoded = *(BYTE **)pbEncoded;
2193                     *pbEncoded++ = ASN_SEQUENCEOF;
2194                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2195                      &lenBytes);
2196                     pbEncoded += lenBytes;
2197                     for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2198                     {
2199                         size = bytesNeeded;
2200                         ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2201                          usage->rgpszUsageIdentifier[i],
2202                          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
2203                          &size);
2204                         if (ret)
2205                         {
2206                             pbEncoded += size;
2207                             bytesNeeded -= size;
2208                         }
2209                     }
2210                 }
2211             }
2212         }
2213     }
2214     __EXCEPT_PAGE_FAULT
2215     {
2216         SetLastError(STATUS_ACCESS_VIOLATION);
2217         ret = FALSE;
2218     }
2219     __ENDTRY
2220     return ret;
2221 }
2222
2223 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2224  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2225  void *pvEncoded, DWORD *pcbEncoded)
2226 {
2227     static HCRYPTOIDFUNCSET set = NULL;
2228     BOOL ret = FALSE;
2229     CryptEncodeObjectExFunc encodeFunc = NULL;
2230     HCRYPTOIDFUNCADDR hFunc = NULL;
2231
2232     TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2233      debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2234      pvEncoded, pcbEncoded);
2235
2236     if (!pvEncoded && !pcbEncoded)
2237     {
2238         SetLastError(ERROR_INVALID_PARAMETER);
2239         return FALSE;
2240     }
2241     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2242      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2243     {
2244         SetLastError(ERROR_FILE_NOT_FOUND);
2245         return FALSE;
2246     }
2247
2248     SetLastError(NOERROR);
2249     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2250         *(BYTE **)pvEncoded = NULL;
2251     if (!HIWORD(lpszStructType))
2252     {
2253         switch (LOWORD(lpszStructType))
2254         {
2255         case (WORD)X509_CERT:
2256             encodeFunc = CRYPT_AsnEncodeCert;
2257             break;
2258         case (WORD)X509_CERT_TO_BE_SIGNED:
2259             encodeFunc = CRYPT_AsnEncodeCertInfo;
2260             break;
2261         case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2262             encodeFunc = CRYPT_AsnEncodeCRLInfo;
2263             break;
2264         case (WORD)X509_EXTENSIONS:
2265             encodeFunc = CRYPT_AsnEncodeExtensions;
2266             break;
2267         case (WORD)X509_NAME:
2268             encodeFunc = CRYPT_AsnEncodeName;
2269             break;
2270         case (WORD)X509_PUBLIC_KEY_INFO:
2271             encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2272             break;
2273         case (WORD)X509_ALTERNATE_NAME:
2274             encodeFunc = CRYPT_AsnEncodeAltName;
2275             break;
2276         case (WORD)X509_BASIC_CONSTRAINTS:
2277             encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2278             break;
2279         case (WORD)X509_BASIC_CONSTRAINTS2:
2280             encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2281             break;
2282         case (WORD)RSA_CSP_PUBLICKEYBLOB:
2283             encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2284             break;
2285         case (WORD)X509_OCTET_STRING:
2286             encodeFunc = CRYPT_AsnEncodeOctets;
2287             break;
2288         case (WORD)X509_BITS:
2289         case (WORD)X509_KEY_USAGE:
2290             encodeFunc = CRYPT_AsnEncodeBits;
2291             break;
2292         case (WORD)X509_INTEGER:
2293             encodeFunc = CRYPT_AsnEncodeInt;
2294             break;
2295         case (WORD)X509_MULTI_BYTE_INTEGER:
2296             encodeFunc = CRYPT_AsnEncodeInteger;
2297             break;
2298         case (WORD)X509_MULTI_BYTE_UINT:
2299             encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2300             break;
2301         case (WORD)X509_ENUMERATED:
2302             encodeFunc = CRYPT_AsnEncodeEnumerated;
2303             break;
2304         case (WORD)X509_CHOICE_OF_TIME:
2305             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2306             break;
2307         case (WORD)X509_SEQUENCE_OF_ANY:
2308             encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2309             break;
2310         case (WORD)PKCS_UTC_TIME:
2311             encodeFunc = CRYPT_AsnEncodeUtcTime;
2312             break;
2313         case (WORD)X509_CRL_DIST_POINTS:
2314             encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2315             break;
2316         case (WORD)X509_ENHANCED_KEY_USAGE:
2317             encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2318             break;
2319         default:
2320             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2321         }
2322     }
2323     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2324         encodeFunc = CRYPT_AsnEncodeExtensions;
2325     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2326         encodeFunc = CRYPT_AsnEncodeUtcTime;
2327     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2328         encodeFunc = CRYPT_AsnEncodeEnumerated;
2329     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2330         encodeFunc = CRYPT_AsnEncodeBits;
2331     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2332         encodeFunc = CRYPT_AsnEncodeOctets;
2333     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
2334         encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2335     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2336         encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2337     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2338         encodeFunc = CRYPT_AsnEncodeAltName;
2339     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2340         encodeFunc = CRYPT_AsnEncodeAltName;
2341     else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2342         encodeFunc = CRYPT_AsnEncodeAltName;
2343     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2344         encodeFunc = CRYPT_AsnEncodeAltName;
2345     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2346         encodeFunc = CRYPT_AsnEncodeAltName;
2347     else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2348         encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2349     else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2350         encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2351     else
2352         TRACE("OID %s not found or unimplemented, looking for DLL\n",
2353          debugstr_a(lpszStructType));
2354     if (!encodeFunc)
2355     {
2356         if (!set)
2357             set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
2358         CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2359          (void **)&encodeFunc, &hFunc);
2360     }
2361     if (encodeFunc)
2362         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2363          dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2364     else
2365         SetLastError(ERROR_FILE_NOT_FOUND);
2366     if (hFunc)
2367         CryptFreeOIDFunctionAddress(hFunc, 0);
2368     return ret;
2369 }
2370
2371 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
2372  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
2373 {
2374     return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
2375      NULL, 0, NULL, pInfo, pcbInfo);
2376 }
2377
2378 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
2379  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
2380  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
2381 {
2382     BOOL ret;
2383     HCRYPTKEY key;
2384
2385     TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
2386      dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
2387      pInfo, pcbInfo);
2388
2389     if (!pszPublicKeyObjId)
2390         pszPublicKeyObjId = szOID_RSA_RSA;
2391     if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
2392     {
2393         DWORD keySize = 0;
2394
2395         ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
2396         if (ret)
2397         {
2398             LPBYTE pubKey = CryptMemAlloc(keySize);
2399
2400             if (pubKey)
2401             {
2402                 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
2403                  &keySize);
2404                 if (ret)
2405                 {
2406                     DWORD encodedLen = 0;
2407
2408                     ret = CryptEncodeObject(dwCertEncodingType,
2409                      RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
2410                     if (ret)
2411                     {
2412                         DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
2413                          strlen(pszPublicKeyObjId) + 1 + encodedLen;
2414
2415                         if (!pInfo)
2416                             *pcbInfo = sizeNeeded;
2417                         else if (*pcbInfo < sizeNeeded)
2418                         {
2419                             SetLastError(ERROR_MORE_DATA);
2420                             *pcbInfo = sizeNeeded;
2421                             ret = FALSE;
2422                         }
2423                         else
2424                         {
2425                             pInfo->Algorithm.pszObjId = (char *)pInfo +
2426                              sizeof(CERT_PUBLIC_KEY_INFO);
2427                             lstrcpyA(pInfo->Algorithm.pszObjId,
2428                              pszPublicKeyObjId);
2429                             pInfo->Algorithm.Parameters.cbData = 0;
2430                             pInfo->Algorithm.Parameters.pbData = NULL;
2431                             pInfo->PublicKey.pbData =
2432                              (BYTE *)pInfo->Algorithm.pszObjId
2433                              + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
2434                             pInfo->PublicKey.cbData = encodedLen;
2435                             pInfo->PublicKey.cUnusedBits = 0;
2436                             ret = CryptEncodeObject(dwCertEncodingType,
2437                              RSA_CSP_PUBLICKEYBLOB, pubKey,
2438                              pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
2439                         }
2440                     }
2441                 }
2442                 CryptMemFree(pubKey);
2443             }
2444             else
2445                 ret = FALSE;
2446         }
2447         CryptDestroyKey(key);
2448     }
2449     return ret;
2450 }
2451
2452 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
2453  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
2454  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
2455
2456 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
2457  DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
2458  void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
2459 {
2460     static HCRYPTOIDFUNCSET set = NULL;
2461     BOOL ret;
2462     ExportPublicKeyInfoExFunc exportFunc = NULL;
2463     HCRYPTOIDFUNCADDR hFunc = NULL;
2464
2465     TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
2466      dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
2467      pInfo, pcbInfo);
2468
2469     if (!hCryptProv)
2470     {
2471         SetLastError(ERROR_INVALID_PARAMETER);
2472         return FALSE;
2473     }
2474
2475     if (pszPublicKeyObjId)
2476     {
2477         if (!set)
2478             set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
2479              0);
2480         CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
2481          0, (void **)&exportFunc, &hFunc);
2482     }
2483     if (!exportFunc)
2484         exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
2485     ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
2486      pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
2487     if (hFunc)
2488         CryptFreeOIDFunctionAddress(hFunc, 0);
2489     return ret;
2490 }
2491
2492 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
2493  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
2494 {
2495     return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
2496      0, 0, NULL, phKey);
2497 }
2498
2499 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
2500  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
2501  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
2502 {
2503     BOOL ret;
2504     DWORD pubKeySize = 0;
2505
2506     TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
2507      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
2508
2509     ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
2510      pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
2511     if (ret)
2512     {
2513         LPBYTE pubKey = CryptMemAlloc(pubKeySize);
2514
2515         if (pubKey)
2516         {
2517             ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
2518              pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
2519              &pubKeySize);
2520             if (ret)
2521                 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
2522                  phKey);
2523             CryptMemFree(pubKey);
2524         }
2525         else
2526             ret = FALSE;
2527     }
2528     return ret;
2529 }
2530
2531 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
2532  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
2533  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
2534
2535 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
2536  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
2537  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
2538 {
2539     static HCRYPTOIDFUNCSET set = NULL;
2540     BOOL ret;
2541     ImportPublicKeyInfoExFunc importFunc = NULL;
2542     HCRYPTOIDFUNCADDR hFunc = NULL;
2543
2544     TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
2545      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
2546
2547     if (!set)
2548         set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
2549     CryptGetOIDFunctionAddress(set, dwCertEncodingType,
2550      pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
2551     if (!importFunc)
2552         importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
2553     ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
2554      pvAuxInfo, phKey);
2555     if (hFunc)
2556         CryptFreeOIDFunctionAddress(hFunc, 0);
2557     return ret;
2558 }