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