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