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