ntdll: Fix compilation on systems that don't support nameless unions.
[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 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1169  */
1170 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1171  CryptEncodeObjectExFunc nameValueEncodeFunc, BYTE *pbEncoded,
1172  DWORD *pcbEncoded)
1173 {
1174     BOOL ret;
1175     CRYPT_DER_BLOB *blobs = NULL;
1176
1177     __TRY
1178     {
1179         DWORD bytesNeeded = 0, lenBytes, i;
1180
1181         blobs = NULL;
1182         ret = TRUE;
1183         if (rdn->cRDNAttr)
1184         {
1185             blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1186             if (!blobs)
1187                 ret = FALSE;
1188             else
1189                 memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1190         }
1191         for (i = 0; ret && i < rdn->cRDNAttr; i++)
1192         {
1193             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1194              nameValueEncodeFunc, NULL, &blobs[i].cbData);
1195             if (ret)
1196                 bytesNeeded += blobs[i].cbData;
1197             else
1198             {
1199                 /* Have to propagate index of failing character */
1200                 *pcbEncoded = blobs[i].cbData;
1201             }
1202         }
1203         if (ret)
1204         {
1205             CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1206             bytesNeeded += 1 + lenBytes;
1207             if (pbEncoded)
1208             {
1209                 if (*pcbEncoded < bytesNeeded)
1210                 {
1211                     SetLastError(ERROR_MORE_DATA);
1212                     ret = FALSE;
1213                 }
1214                 else
1215                 {
1216                     for (i = 0; ret && i < rdn->cRDNAttr; i++)
1217                     {
1218                         blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
1219                         if (!blobs[i].pbData)
1220                             ret = FALSE;
1221                         else
1222                         {
1223                             ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1224                              &rdn->rgRDNAttr[i], nameValueEncodeFunc,
1225                              blobs[i].pbData, &blobs[i].cbData);
1226                             if (!ret)
1227                                 *pcbEncoded = blobs[i].cbData;
1228                         }
1229                     }
1230                     if (ret)
1231                     {
1232                         qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1233                          BLOBComp);
1234                         *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1235                         CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1236                          &lenBytes);
1237                         pbEncoded += lenBytes;
1238                         for (i = 0; ret && i < rdn->cRDNAttr; i++)
1239                         {
1240                             memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1241                             pbEncoded += blobs[i].cbData;
1242                         }
1243                     }
1244                 }
1245             }
1246             if (ret)
1247                 *pcbEncoded = bytesNeeded;
1248         }
1249         if (blobs)
1250         {
1251             for (i = 0; i < rdn->cRDNAttr; i++)
1252                 CryptMemFree(blobs[i].pbData);
1253         }
1254     }
1255     __EXCEPT_PAGE_FAULT
1256     {
1257         SetLastError(STATUS_ACCESS_VIOLATION);
1258         ret = FALSE;
1259     }
1260     __ENDTRY
1261     CryptMemFree(blobs);
1262     return ret;
1263 }
1264
1265 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1266  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1267  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
1268
1269 static BOOL WINAPI CRYPT_AsnEncodeOrCopyUnicodeNameValue(
1270  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
1271  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1272  DWORD *pcbEncoded)
1273 {
1274     const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1275     BOOL ret;
1276
1277     if (value->dwValueType == CERT_RDN_ENCODED_BLOB)
1278         ret = CRYPT_CopyEncodedBlob(dwCertEncodingType, NULL, &value->Value,
1279          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1280     else
1281         ret = CRYPT_AsnEncodeUnicodeNameValue(dwCertEncodingType, NULL, value,
1282          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1283     return ret;
1284 }
1285
1286 static BOOL WINAPI CRYPT_AsnEncodeUnicodeName(DWORD dwCertEncodingType,
1287  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1288  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1289 {
1290     BOOL ret = TRUE;
1291
1292     __TRY
1293     {
1294         const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1295         DWORD bytesNeeded = 0, lenBytes, size, i;
1296
1297         TRACE("encoding name with %d RDNs\n", info->cRDN);
1298         ret = TRUE;
1299         for (i = 0; ret && i < info->cRDN; i++)
1300         {
1301             ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1302              CRYPT_AsnEncodeOrCopyUnicodeNameValue, NULL, &size);
1303             if (ret)
1304                 bytesNeeded += size;
1305             else
1306                 *pcbEncoded = size;
1307         }
1308         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1309         bytesNeeded += 1 + lenBytes;
1310         if (ret)
1311         {
1312             if (!pbEncoded)
1313                 *pcbEncoded = bytesNeeded;
1314             else
1315             {
1316                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1317                  pbEncoded, pcbEncoded, bytesNeeded)))
1318                 {
1319                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1320                         pbEncoded = *(BYTE **)pbEncoded;
1321                     *pbEncoded++ = ASN_SEQUENCEOF;
1322                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1323                      &lenBytes);
1324                     pbEncoded += lenBytes;
1325                     for (i = 0; ret && i < info->cRDN; i++)
1326                     {
1327                         size = bytesNeeded;
1328                         ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1329                          &info->rgRDN[i], CRYPT_AsnEncodeOrCopyUnicodeNameValue,
1330                          pbEncoded, &size);
1331                         if (ret)
1332                         {
1333                             pbEncoded += size;
1334                             bytesNeeded -= size;
1335                         }
1336                         else
1337                             *pcbEncoded = size;
1338                     }
1339                 }
1340             }
1341         }
1342     }
1343     __EXCEPT_PAGE_FAULT
1344     {
1345         SetLastError(STATUS_ACCESS_VIOLATION);
1346         ret = FALSE;
1347     }
1348     __ENDTRY
1349     return ret;
1350 }
1351
1352 static BOOL CRYPT_AsnEncodeUnicodeStringCoerce(const CERT_NAME_VALUE *value,
1353  BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1354  DWORD *pcbEncoded)
1355 {
1356     BOOL ret = TRUE;
1357     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1358     DWORD bytesNeeded, lenBytes, encodedLen;
1359
1360     encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1361      lstrlenW(str);
1362     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1363     bytesNeeded = 1 + lenBytes + encodedLen;
1364     if (!pbEncoded)
1365         *pcbEncoded = bytesNeeded;
1366     else
1367     {
1368         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1369          pbEncoded, pcbEncoded, bytesNeeded)))
1370         {
1371             DWORD i;
1372
1373             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1374                 pbEncoded = *(BYTE **)pbEncoded;
1375             *pbEncoded++ = tag;
1376             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1377             pbEncoded += lenBytes;
1378             for (i = 0; i < encodedLen; i++)
1379                 *pbEncoded++ = (BYTE)str[i];
1380         }
1381     }
1382     return ret;
1383 }
1384
1385 static BOOL CRYPT_AsnEncodeNumericString(const CERT_NAME_VALUE *value,
1386  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1387  DWORD *pcbEncoded)
1388 {
1389     BOOL ret = TRUE;
1390     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1391     DWORD bytesNeeded, lenBytes, encodedLen;
1392
1393     encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1394      lstrlenW(str);
1395     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1396     bytesNeeded = 1 + lenBytes + encodedLen;
1397     if (!pbEncoded)
1398         *pcbEncoded = bytesNeeded;
1399     else
1400     {
1401         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1402          pbEncoded, pcbEncoded, bytesNeeded)))
1403         {
1404             DWORD i;
1405
1406             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1407                 pbEncoded = *(BYTE **)pbEncoded;
1408             *pbEncoded++ = ASN_NUMERICSTRING;
1409             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1410             pbEncoded += lenBytes;
1411             for (i = 0; ret && i < encodedLen; i++)
1412             {
1413                 if (isdigitW(str[i]))
1414                     *pbEncoded++ = (BYTE)str[i];
1415                 else
1416                 {
1417                     *pcbEncoded = i;
1418                     SetLastError(CRYPT_E_INVALID_NUMERIC_STRING);
1419                     ret = FALSE;
1420                 }
1421             }
1422         }
1423     }
1424     return ret;
1425 }
1426
1427 static inline int isprintableW(WCHAR wc)
1428 {
1429     return isalnumW(wc) || isspaceW(wc) || wc == '\'' || wc == '(' ||
1430      wc == ')' || wc == '+' || wc == ',' || wc == '-' || wc == '.' ||
1431      wc == '/' || wc == ':' || wc == '=' || wc == '?';
1432 }
1433
1434 static BOOL CRYPT_AsnEncodePrintableString(const CERT_NAME_VALUE *value,
1435  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1436  DWORD *pcbEncoded)
1437 {
1438     BOOL ret = TRUE;
1439     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1440     DWORD bytesNeeded, lenBytes, encodedLen;
1441
1442     encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1443      lstrlenW(str);
1444     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1445     bytesNeeded = 1 + lenBytes + encodedLen;
1446     if (!pbEncoded)
1447         *pcbEncoded = bytesNeeded;
1448     else
1449     {
1450         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1451          pbEncoded, pcbEncoded, bytesNeeded)))
1452         {
1453             DWORD i;
1454
1455             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1456                 pbEncoded = *(BYTE **)pbEncoded;
1457             *pbEncoded++ = ASN_PRINTABLESTRING;
1458             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1459             pbEncoded += lenBytes;
1460             for (i = 0; ret && i < encodedLen; i++)
1461             {
1462                 if (isprintableW(str[i]))
1463                     *pbEncoded++ = (BYTE)str[i];
1464                 else
1465                 {
1466                     *pcbEncoded = i;
1467                     SetLastError(CRYPT_E_INVALID_PRINTABLE_STRING);
1468                     ret = FALSE;
1469                 }
1470             }
1471         }
1472     }
1473     return ret;
1474 }
1475
1476 static BOOL CRYPT_AsnEncodeIA5String(const CERT_NAME_VALUE *value,
1477  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1478  DWORD *pcbEncoded)
1479 {
1480     BOOL ret = TRUE;
1481     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1482     DWORD bytesNeeded, lenBytes, encodedLen;
1483
1484     encodedLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1485      lstrlenW(str);
1486     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1487     bytesNeeded = 1 + lenBytes + encodedLen;
1488     if (!pbEncoded)
1489         *pcbEncoded = bytesNeeded;
1490     else
1491     {
1492         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1493          pbEncoded, pcbEncoded, bytesNeeded)))
1494         {
1495             DWORD i;
1496
1497             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1498                 pbEncoded = *(BYTE **)pbEncoded;
1499             *pbEncoded++ = ASN_IA5STRING;
1500             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1501             pbEncoded += lenBytes;
1502             for (i = 0; ret && i < encodedLen; i++)
1503             {
1504                 if (str[i] <= 0x7f)
1505                     *pbEncoded++ = (BYTE)str[i];
1506                 else
1507                 {
1508                     *pcbEncoded = i;
1509                     SetLastError(CRYPT_E_INVALID_IA5_STRING);
1510                     ret = FALSE;
1511                 }
1512             }
1513         }
1514     }
1515     return ret;
1516 }
1517
1518 static BOOL CRYPT_AsnEncodeUniversalString(const CERT_NAME_VALUE *value,
1519  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
1520  DWORD *pcbEncoded)
1521 {
1522     BOOL ret = TRUE;
1523     LPCWSTR str = (LPCWSTR)value->Value.pbData;
1524     DWORD bytesNeeded, lenBytes, strLen;
1525
1526     /* FIXME: doesn't handle composite characters */
1527     strLen = value->Value.cbData ? value->Value.cbData / sizeof(WCHAR) :
1528      lstrlenW(str);
1529     CRYPT_EncodeLen(strLen * 4, NULL, &lenBytes);
1530     bytesNeeded = 1 + lenBytes + strLen * 4;
1531     if (!pbEncoded)
1532         *pcbEncoded = bytesNeeded;
1533     else
1534     {
1535         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1536          pbEncoded, pcbEncoded, bytesNeeded)))
1537         {
1538             DWORD i;
1539
1540             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1541                 pbEncoded = *(BYTE **)pbEncoded;
1542             *pbEncoded++ = ASN_UNIVERSALSTRING;
1543             CRYPT_EncodeLen(strLen * 4, pbEncoded, &lenBytes);
1544             pbEncoded += lenBytes;
1545             for (i = 0; i < strLen; i++)
1546             {
1547                 *pbEncoded++ = 0;
1548                 *pbEncoded++ = 0;
1549                 *pbEncoded++ = (BYTE)((str[i] & 0xff00) >> 8);
1550                 *pbEncoded++ = (BYTE)(str[i] & 0x00ff);
1551             }
1552         }
1553     }
1554     return ret;
1555 }
1556
1557 static BOOL WINAPI CRYPT_AsnEncodeUnicodeNameValue(DWORD dwCertEncodingType,
1558  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1559  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1560 {
1561     BOOL ret = FALSE;
1562
1563     __TRY
1564     {
1565         const CERT_NAME_VALUE *value = (const CERT_NAME_VALUE *)pvStructInfo;
1566
1567         switch (value->dwValueType)
1568         {
1569         case CERT_RDN_ANY_TYPE:
1570         case CERT_RDN_ENCODED_BLOB:
1571         case CERT_RDN_OCTET_STRING:
1572             SetLastError(CRYPT_E_NOT_CHAR_STRING);
1573             break;
1574         case CERT_RDN_NUMERIC_STRING:
1575             ret = CRYPT_AsnEncodeNumericString(value, dwFlags, pEncodePara,
1576              pbEncoded, pcbEncoded);
1577             break;
1578         case CERT_RDN_PRINTABLE_STRING:
1579             ret = CRYPT_AsnEncodePrintableString(value, dwFlags, pEncodePara,
1580              pbEncoded, pcbEncoded);
1581             break;
1582         case CERT_RDN_TELETEX_STRING:
1583             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_T61STRING,
1584              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1585             break;
1586         case CERT_RDN_VIDEOTEX_STRING:
1587             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value,
1588              ASN_VIDEOTEXSTRING, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1589             break;
1590         case CERT_RDN_IA5_STRING:
1591             ret = CRYPT_AsnEncodeIA5String(value, dwFlags, pEncodePara,
1592              pbEncoded, pcbEncoded);
1593             break;
1594         case CERT_RDN_GRAPHIC_STRING:
1595             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GRAPHICSTRING,
1596              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1597             break;
1598         case CERT_RDN_VISIBLE_STRING:
1599             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_VISIBLESTRING,
1600              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1601             break;
1602         case CERT_RDN_GENERAL_STRING:
1603             ret = CRYPT_AsnEncodeUnicodeStringCoerce(value, ASN_GENERALSTRING,
1604              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1605             break;
1606         case CERT_RDN_UNIVERSAL_STRING:
1607             ret = CRYPT_AsnEncodeUniversalString(value, dwFlags, pEncodePara,
1608              pbEncoded, pcbEncoded);
1609             break;
1610         case CERT_RDN_BMP_STRING:
1611             ret = CRYPT_AsnEncodeBMPString(value, dwFlags, pEncodePara,
1612              pbEncoded, pcbEncoded);
1613             break;
1614         case CERT_RDN_UTF8_STRING:
1615             ret = CRYPT_AsnEncodeUTF8String(value, dwFlags, pEncodePara,
1616              pbEncoded, pcbEncoded);
1617             break;
1618         default:
1619             SetLastError(CRYPT_E_ASN1_CHOICE);
1620         }
1621     }
1622     __EXCEPT_PAGE_FAULT
1623     {
1624         SetLastError(STATUS_ACCESS_VIOLATION);
1625     }
1626     __ENDTRY
1627     return ret;
1628 }
1629
1630 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1631  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1632  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1633 {
1634     BOOL ret;
1635
1636     __TRY
1637     {
1638         const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1639         DWORD bytesNeeded = 0, lenBytes, size, i;
1640
1641         TRACE("encoding name with %d RDNs\n", info->cRDN);
1642         ret = TRUE;
1643         for (i = 0; ret && i < info->cRDN; i++)
1644         {
1645             ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i],
1646              CRYPT_AsnEncodeNameValue, NULL, &size);
1647             if (ret)
1648                 bytesNeeded += size;
1649         }
1650         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1651         bytesNeeded += 1 + lenBytes;
1652         if (ret)
1653         {
1654             if (!pbEncoded)
1655                 *pcbEncoded = bytesNeeded;
1656             else
1657             {
1658                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1659                  pbEncoded, pcbEncoded, bytesNeeded)))
1660                 {
1661                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1662                         pbEncoded = *(BYTE **)pbEncoded;
1663                     *pbEncoded++ = ASN_SEQUENCEOF;
1664                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1665                      &lenBytes);
1666                     pbEncoded += lenBytes;
1667                     for (i = 0; ret && i < info->cRDN; i++)
1668                     {
1669                         size = bytesNeeded;
1670                         ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1671                          &info->rgRDN[i], CRYPT_AsnEncodeNameValue, pbEncoded,
1672                          &size);
1673                         if (ret)
1674                         {
1675                             pbEncoded += size;
1676                             bytesNeeded -= size;
1677                         }
1678                     }
1679                 }
1680             }
1681         }
1682     }
1683     __EXCEPT_PAGE_FAULT
1684     {
1685         SetLastError(STATUS_ACCESS_VIOLATION);
1686         ret = FALSE;
1687     }
1688     __ENDTRY
1689     return ret;
1690 }
1691
1692 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1693  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1694  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1695 {
1696     BOOL val = *(const BOOL *)pvStructInfo, ret;
1697
1698     TRACE("%d\n", val);
1699
1700     if (!pbEncoded)
1701     {
1702         *pcbEncoded = 3;
1703         ret = TRUE;
1704     }
1705     else if (*pcbEncoded < 3)
1706     {
1707         *pcbEncoded = 3;
1708         SetLastError(ERROR_MORE_DATA);
1709         ret = FALSE;
1710     }
1711     else
1712     {
1713         *pcbEncoded = 3;
1714         *pbEncoded++ = ASN_BOOL;
1715         *pbEncoded++ = 1;
1716         *pbEncoded++ = val ? 0xff : 0;
1717         ret = TRUE;
1718     }
1719     TRACE("returning %d (%08x)\n", ret, GetLastError());
1720     return ret;
1721 }
1722
1723 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1724  BYTE *pbEncoded, DWORD *pcbEncoded)
1725 {
1726     BOOL ret;
1727     DWORD dataLen;
1728
1729     ret = TRUE;
1730     switch (entry->dwAltNameChoice)
1731     {
1732     case CERT_ALT_NAME_RFC822_NAME:
1733     case CERT_ALT_NAME_DNS_NAME:
1734     case CERT_ALT_NAME_URL:
1735         if (entry->u.pwszURL)
1736         {
1737             DWORD i;
1738
1739             /* Not + 1: don't encode the NULL-terminator */
1740             dataLen = lstrlenW(entry->u.pwszURL);
1741             for (i = 0; ret && i < dataLen; i++)
1742             {
1743                 if (entry->u.pwszURL[i] > 0x7f)
1744                 {
1745                     SetLastError(CRYPT_E_INVALID_IA5_STRING);
1746                     ret = FALSE;
1747                     *pcbEncoded = i;
1748                 }
1749             }
1750         }
1751         else
1752             dataLen = 0;
1753         break;
1754     case CERT_ALT_NAME_IP_ADDRESS:
1755         dataLen = entry->u.IPAddress.cbData;
1756         break;
1757     case CERT_ALT_NAME_REGISTERED_ID:
1758         /* FIXME: encode OID */
1759     case CERT_ALT_NAME_OTHER_NAME:
1760     case CERT_ALT_NAME_DIRECTORY_NAME:
1761         FIXME("name type %d unimplemented\n", entry->dwAltNameChoice);
1762         return FALSE;
1763     default:
1764         SetLastError(E_INVALIDARG);
1765         return FALSE;
1766     }
1767     if (ret)
1768     {
1769         DWORD bytesNeeded, lenBytes;
1770
1771         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1772         bytesNeeded = 1 + dataLen + lenBytes;
1773         if (!pbEncoded)
1774             *pcbEncoded = bytesNeeded;
1775         else if (*pcbEncoded < bytesNeeded)
1776         {
1777             SetLastError(ERROR_MORE_DATA);
1778             *pcbEncoded = bytesNeeded;
1779             ret = FALSE;
1780         }
1781         else
1782         {
1783             *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1784             CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1785             pbEncoded += lenBytes;
1786             switch (entry->dwAltNameChoice)
1787             {
1788             case CERT_ALT_NAME_RFC822_NAME:
1789             case CERT_ALT_NAME_DNS_NAME:
1790             case CERT_ALT_NAME_URL:
1791             {
1792                 DWORD i;
1793
1794                 for (i = 0; i < dataLen; i++)
1795                     *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1796                 break;
1797             }
1798             case CERT_ALT_NAME_IP_ADDRESS:
1799                 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1800                 break;
1801             }
1802             if (ret)
1803                 *pcbEncoded = bytesNeeded;
1804         }
1805     }
1806     TRACE("returning %d (%08x)\n", ret, GetLastError());
1807     return ret;
1808 }
1809
1810 static BOOL WINAPI CRYPT_AsnEncodeAuthorityKeyId(DWORD dwCertEncodingType,
1811  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1812  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1813 {
1814     BOOL ret;
1815
1816     __TRY
1817     {
1818         const CERT_AUTHORITY_KEY_ID_INFO *info =
1819          (const CERT_AUTHORITY_KEY_ID_INFO *)pvStructInfo;
1820         struct AsnEncodeSequenceItem items[3] = { { 0 } };
1821         struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
1822         struct AsnConstructedItem constructed = { 0 };
1823         DWORD cItem = 0, cSwapped = 0;
1824
1825         if (info->KeyId.cbData)
1826         {
1827             swapped[cSwapped].tag = ASN_CONTEXT | 0;
1828             swapped[cSwapped].pvStructInfo = &info->KeyId;
1829             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
1830             items[cItem].pvStructInfo = &swapped[cSwapped];
1831             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
1832             cSwapped++;
1833             cItem++;
1834         }
1835         if (info->CertIssuer.cbData)
1836         {
1837             constructed.tag = 1;
1838             constructed.pvStructInfo = &info->CertIssuer;
1839             constructed.encodeFunc = CRYPT_CopyEncodedBlob;
1840             items[cItem].pvStructInfo = &constructed;
1841             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
1842             cItem++;
1843         }
1844         if (info->CertSerialNumber.cbData)
1845         {
1846             swapped[cSwapped].tag = ASN_CONTEXT | 2;
1847             swapped[cSwapped].pvStructInfo = &info->CertSerialNumber;
1848             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeInteger;
1849             items[cItem].pvStructInfo = &swapped[cSwapped];
1850             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
1851             cSwapped++;
1852             cItem++;
1853         }
1854         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, dwFlags,
1855          pEncodePara, pbEncoded, pcbEncoded);
1856     }
1857     __EXCEPT_PAGE_FAULT
1858     {
1859         SetLastError(STATUS_ACCESS_VIOLATION);
1860         ret = FALSE;
1861     }
1862     __ENDTRY
1863     return ret;
1864 }
1865
1866 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1867  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1868  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1869 {
1870     BOOL ret;
1871
1872     __TRY
1873     {
1874         const CERT_ALT_NAME_INFO *info =
1875          (const CERT_ALT_NAME_INFO *)pvStructInfo;
1876         DWORD bytesNeeded, dataLen, lenBytes, i;
1877
1878         ret = TRUE;
1879         /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1880          * can't encode an erroneous entry index if it's bigger than this.
1881          */
1882         for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1883         {
1884             DWORD len;
1885
1886             ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1887              &len);
1888             if (ret)
1889                 dataLen += len;
1890             else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1891             {
1892                 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1893                  * the bad character, now set the index of the bad
1894                  * entry
1895                  */
1896                 *pcbEncoded = (BYTE)i <<
1897                  CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1898             }
1899         }
1900         if (ret)
1901         {
1902             CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1903             bytesNeeded = 1 + lenBytes + dataLen;
1904             if (!pbEncoded)
1905             {
1906                 *pcbEncoded = bytesNeeded;
1907                 ret = TRUE;
1908             }
1909             else
1910             {
1911                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1912                  pbEncoded, pcbEncoded, bytesNeeded)))
1913                 {
1914                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1915                         pbEncoded = *(BYTE **)pbEncoded;
1916                     *pbEncoded++ = ASN_SEQUENCEOF;
1917                     CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1918                     pbEncoded += lenBytes;
1919                     for (i = 0; ret && i < info->cAltEntry; i++)
1920                     {
1921                         DWORD len = dataLen;
1922
1923                         ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1924                          pbEncoded, &len);
1925                         if (ret)
1926                         {
1927                             pbEncoded += len;
1928                             dataLen -= len;
1929                         }
1930                     }
1931                 }
1932             }
1933         }
1934     }
1935     __EXCEPT_PAGE_FAULT
1936     {
1937         SetLastError(STATUS_ACCESS_VIOLATION);
1938         ret = FALSE;
1939     }
1940     __ENDTRY
1941     return ret;
1942 }
1943
1944 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
1945  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1946  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1947 {
1948     BOOL ret;
1949
1950     __TRY
1951     {
1952         const CERT_BASIC_CONSTRAINTS_INFO *info =
1953          (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
1954         struct AsnEncodeSequenceItem items[3] = {
1955          { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
1956          { 0 }
1957         };
1958         DWORD cItem = 1;
1959
1960         if (info->fPathLenConstraint)
1961         {
1962             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1963             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1964             cItem++;
1965         }
1966         if (info->cSubtreesConstraint)
1967         {
1968             items[cItem].pvStructInfo = &info->cSubtreesConstraint;
1969             items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
1970             cItem++;
1971         }
1972         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1973          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1974     }
1975     __EXCEPT_PAGE_FAULT
1976     {
1977         SetLastError(STATUS_ACCESS_VIOLATION);
1978         ret = FALSE;
1979     }
1980     __ENDTRY
1981     return ret;
1982 }
1983
1984 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1985  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1986  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1987 {
1988     BOOL ret;
1989
1990     __TRY
1991     {
1992         const CERT_BASIC_CONSTRAINTS2_INFO *info =
1993          (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1994         struct AsnEncodeSequenceItem items[2] = { { 0 } };
1995         DWORD cItem = 0;
1996
1997         if (info->fCA)
1998         {
1999             items[cItem].pvStructInfo = &info->fCA;
2000             items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
2001             cItem++;
2002         }
2003         if (info->fPathLenConstraint)
2004         {
2005             items[cItem].pvStructInfo = &info->dwPathLenConstraint;
2006             items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
2007             cItem++;
2008         }
2009         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2010          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2011     }
2012     __EXCEPT_PAGE_FAULT
2013     {
2014         SetLastError(STATUS_ACCESS_VIOLATION);
2015         ret = FALSE;
2016     }
2017     __ENDTRY
2018     return ret;
2019 }
2020
2021 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
2022  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2023  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2024 {
2025     BOOL ret;
2026
2027     __TRY
2028     {
2029         const BLOBHEADER *hdr =
2030          (const BLOBHEADER *)pvStructInfo;
2031
2032         if (hdr->bType != PUBLICKEYBLOB)
2033         {
2034             SetLastError(E_INVALIDARG);
2035             ret = FALSE;
2036         }
2037         else
2038         {
2039             const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
2040              ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
2041             CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
2042              (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
2043             struct AsnEncodeSequenceItem items[] = { 
2044              { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
2045              { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
2046             };
2047
2048             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
2049              sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
2050              pcbEncoded);
2051         }
2052     }
2053     __EXCEPT_PAGE_FAULT
2054     {
2055         SetLastError(STATUS_ACCESS_VIOLATION);
2056         ret = FALSE;
2057     }
2058     __ENDTRY
2059     return ret;
2060 }
2061
2062 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
2063  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2064  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2065 {
2066     BOOL ret;
2067
2068     __TRY
2069     {
2070         const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
2071         DWORD bytesNeeded, lenBytes;
2072
2073         TRACE("(%d, %p), %08x, %p, %p, %d\n", blob->cbData, blob->pbData,
2074          dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
2075
2076         CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
2077         bytesNeeded = 1 + lenBytes + blob->cbData;
2078         if (!pbEncoded)
2079         {
2080             *pcbEncoded = bytesNeeded;
2081             ret = TRUE;
2082         }
2083         else
2084         {
2085             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2086              pcbEncoded, bytesNeeded)))
2087             {
2088                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2089                     pbEncoded = *(BYTE **)pbEncoded;
2090                 *pbEncoded++ = ASN_OCTETSTRING;
2091                 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
2092                 pbEncoded += lenBytes;
2093                 if (blob->cbData)
2094                     memcpy(pbEncoded, blob->pbData, blob->cbData);
2095             }
2096         }
2097     }
2098     __EXCEPT_PAGE_FAULT
2099     {
2100         SetLastError(STATUS_ACCESS_VIOLATION);
2101         ret = FALSE;
2102     }
2103     __ENDTRY
2104     TRACE("returning %d (%08x)\n", ret, GetLastError());
2105     return ret;
2106 }
2107
2108 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
2109  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2110  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2111 {
2112     BOOL ret;
2113
2114     __TRY
2115     {
2116         const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2117         DWORD bytesNeeded, lenBytes, dataBytes;
2118         BYTE unusedBits;
2119
2120         /* yep, MS allows cUnusedBits to be >= 8 */
2121         if (!blob->cUnusedBits)
2122         {
2123             dataBytes = blob->cbData;
2124             unusedBits = 0;
2125         }
2126         else if (blob->cbData * 8 > blob->cUnusedBits)
2127         {
2128             dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
2129             unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
2130              blob->cUnusedBits;
2131         }
2132         else
2133         {
2134             dataBytes = 0;
2135             unusedBits = 0;
2136         }
2137         CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
2138         bytesNeeded = 1 + lenBytes + dataBytes + 1;
2139         if (!pbEncoded)
2140         {
2141             *pcbEncoded = bytesNeeded;
2142             ret = TRUE;
2143         }
2144         else
2145         {
2146             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2147              pcbEncoded, bytesNeeded)))
2148             {
2149                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2150                     pbEncoded = *(BYTE **)pbEncoded;
2151                 *pbEncoded++ = ASN_BITSTRING;
2152                 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
2153                 pbEncoded += lenBytes;
2154                 *pbEncoded++ = unusedBits;
2155                 if (dataBytes)
2156                 {
2157                     BYTE mask = 0xff << unusedBits;
2158
2159                     if (dataBytes > 1)
2160                     {
2161                         memcpy(pbEncoded, blob->pbData, dataBytes - 1);
2162                         pbEncoded += dataBytes - 1;
2163                     }
2164                     *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
2165                 }
2166             }
2167         }
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_AsnEncodeBitsSwapBytes(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 CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
2187         CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
2188
2189         ret = TRUE;
2190         if (newBlob.cbData)
2191         {
2192             newBlob.pbData = CryptMemAlloc(newBlob.cbData);
2193             if (newBlob.pbData)
2194             {
2195                 DWORD i;
2196
2197                 for (i = 0; i < newBlob.cbData; i++)
2198                     newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
2199             }
2200             else
2201                 ret = FALSE;
2202         }
2203         if (ret)
2204             ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
2205              &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2206         CryptMemFree(newBlob.pbData);
2207     }
2208     __EXCEPT_PAGE_FAULT
2209     {
2210         SetLastError(STATUS_ACCESS_VIOLATION);
2211         ret = FALSE;
2212     }
2213     __ENDTRY
2214     return ret;
2215 }
2216
2217 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
2218  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2219  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2220 {
2221     CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
2222
2223     return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
2224      &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2225 }
2226
2227 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
2228  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2229  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2230 {
2231     BOOL ret;
2232
2233     __TRY
2234     {
2235         DWORD significantBytes, lenBytes;
2236         BYTE padByte = 0, bytesNeeded;
2237         BOOL pad = FALSE;
2238         const CRYPT_INTEGER_BLOB *blob =
2239          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2240
2241         significantBytes = blob->cbData;
2242         if (significantBytes)
2243         {
2244             if (blob->pbData[significantBytes - 1] & 0x80)
2245             {
2246                 /* negative, lop off leading (little-endian) 0xffs */
2247                 for (; significantBytes > 0 &&
2248                  blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
2249                     ;
2250                 if (blob->pbData[significantBytes - 1] < 0x80)
2251                 {
2252                     padByte = 0xff;
2253                     pad = TRUE;
2254                 }
2255             }
2256             else
2257             {
2258                 /* positive, lop off leading (little-endian) zeroes */
2259                 for (; significantBytes > 0 &&
2260                  !blob->pbData[significantBytes - 1]; significantBytes--)
2261                     ;
2262                 if (significantBytes == 0)
2263                     significantBytes = 1;
2264                 if (blob->pbData[significantBytes - 1] > 0x7f)
2265                 {
2266                     padByte = 0;
2267                     pad = TRUE;
2268                 }
2269             }
2270         }
2271         if (pad)
2272             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2273         else
2274             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2275         bytesNeeded = 1 + lenBytes + significantBytes;
2276         if (pad)
2277             bytesNeeded++;
2278         if (!pbEncoded)
2279         {
2280             *pcbEncoded = bytesNeeded;
2281             ret = TRUE;
2282         }
2283         else
2284         {
2285             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2286              pcbEncoded, bytesNeeded)))
2287             {
2288                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2289                     pbEncoded = *(BYTE **)pbEncoded;
2290                 *pbEncoded++ = ASN_INTEGER;
2291                 if (pad)
2292                 {
2293                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2294                     pbEncoded += lenBytes;
2295                     *pbEncoded++ = padByte;
2296                 }
2297                 else
2298                 {
2299                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2300                     pbEncoded += lenBytes;
2301                 }
2302                 for (; significantBytes > 0; significantBytes--)
2303                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
2304             }
2305         }
2306     }
2307     __EXCEPT_PAGE_FAULT
2308     {
2309         SetLastError(STATUS_ACCESS_VIOLATION);
2310         ret = FALSE;
2311     }
2312     __ENDTRY
2313     return ret;
2314 }
2315
2316 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
2317  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2318  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2319 {
2320     BOOL ret;
2321
2322     __TRY
2323     {
2324         DWORD significantBytes, lenBytes;
2325         BYTE bytesNeeded;
2326         BOOL pad = FALSE;
2327         const CRYPT_INTEGER_BLOB *blob =
2328          (const CRYPT_INTEGER_BLOB *)pvStructInfo;
2329
2330         significantBytes = blob->cbData;
2331         if (significantBytes)
2332         {
2333             /* positive, lop off leading (little-endian) zeroes */
2334             for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
2335              significantBytes--)
2336                 ;
2337             if (significantBytes == 0)
2338                 significantBytes = 1;
2339             if (blob->pbData[significantBytes - 1] > 0x7f)
2340                 pad = TRUE;
2341         }
2342         if (pad)
2343             CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
2344         else
2345             CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
2346         bytesNeeded = 1 + lenBytes + significantBytes;
2347         if (pad)
2348             bytesNeeded++;
2349         if (!pbEncoded)
2350         {
2351             *pcbEncoded = bytesNeeded;
2352             ret = TRUE;
2353         }
2354         else
2355         {
2356             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2357              pcbEncoded, bytesNeeded)))
2358             {
2359                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2360                     pbEncoded = *(BYTE **)pbEncoded;
2361                 *pbEncoded++ = ASN_INTEGER;
2362                 if (pad)
2363                 {
2364                     CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
2365                     pbEncoded += lenBytes;
2366                     *pbEncoded++ = 0;
2367                 }
2368                 else
2369                 {
2370                     CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
2371                     pbEncoded += lenBytes;
2372                 }
2373                 for (; significantBytes > 0; significantBytes--)
2374                     *(pbEncoded++) = blob->pbData[significantBytes - 1];
2375             }
2376         }
2377     }
2378     __EXCEPT_PAGE_FAULT
2379     {
2380         SetLastError(STATUS_ACCESS_VIOLATION);
2381         ret = FALSE;
2382     }
2383     __ENDTRY
2384     return ret;
2385 }
2386
2387 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
2388  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2389  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2390 {
2391     CRYPT_INTEGER_BLOB blob;
2392     BOOL ret;
2393
2394     /* Encode as an unsigned integer, then change the tag to enumerated */
2395     blob.cbData = sizeof(DWORD);
2396     blob.pbData = (BYTE *)pvStructInfo;
2397     ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
2398      X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2399     if (ret && pbEncoded)
2400     {
2401         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2402             pbEncoded = *(BYTE **)pbEncoded;
2403         pbEncoded[0] = ASN_ENUMERATED;
2404     }
2405     return ret;
2406 }
2407
2408 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
2409  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2410  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2411 {
2412     BOOL ret;
2413
2414     __TRY
2415     {
2416         SYSTEMTIME sysTime;
2417         /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0.  I use a
2418          * temporary buffer because the output buffer is not NULL-terminated.
2419          */
2420         char buf[16];
2421         static const DWORD bytesNeeded = sizeof(buf) - 1;
2422
2423         if (!pbEncoded)
2424         {
2425             *pcbEncoded = bytesNeeded;
2426             ret = TRUE;
2427         }
2428         else
2429         {
2430             /* Sanity check the year, this is a two-digit year format */
2431             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2432              &sysTime);
2433             if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
2434             {
2435                 SetLastError(CRYPT_E_BAD_ENCODE);
2436                 ret = FALSE;
2437             }
2438             if (ret)
2439             {
2440                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2441                  pbEncoded, pcbEncoded, bytesNeeded)))
2442                 {
2443                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2444                         pbEncoded = *(BYTE **)pbEncoded;
2445                     buf[0] = ASN_UTCTIME;
2446                     buf[1] = bytesNeeded - 2;
2447                     snprintf(buf + 2, sizeof(buf) - 2,
2448                      "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
2449                      sysTime.wYear - 2000 : sysTime.wYear - 1900,
2450                      sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2451                      sysTime.wMinute, sysTime.wSecond);
2452                     memcpy(pbEncoded, buf, bytesNeeded);
2453                 }
2454             }
2455         }
2456     }
2457     __EXCEPT_PAGE_FAULT
2458     {
2459         SetLastError(STATUS_ACCESS_VIOLATION);
2460         ret = FALSE;
2461     }
2462     __ENDTRY
2463     return ret;
2464 }
2465
2466 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
2467  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2468  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2469 {
2470     BOOL ret;
2471
2472     __TRY
2473     {
2474         SYSTEMTIME sysTime;
2475         /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0.  I use a
2476          * temporary buffer because the output buffer is not NULL-terminated.
2477          */
2478         char buf[18];
2479         static const DWORD bytesNeeded = sizeof(buf) - 1;
2480
2481         if (!pbEncoded)
2482         {
2483             *pcbEncoded = bytesNeeded;
2484             ret = TRUE;
2485         }
2486         else
2487         {
2488             ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
2489              &sysTime);
2490             if (ret)
2491                 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2492                  pcbEncoded, bytesNeeded);
2493             if (ret)
2494             {
2495                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2496                     pbEncoded = *(BYTE **)pbEncoded;
2497                 buf[0] = ASN_GENERALTIME;
2498                 buf[1] = bytesNeeded - 2;
2499                 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2500                  sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2501                  sysTime.wMinute, sysTime.wSecond);
2502                 memcpy(pbEncoded, buf, bytesNeeded);
2503             }
2504         }
2505     }
2506     __EXCEPT_PAGE_FAULT
2507     {
2508         SetLastError(STATUS_ACCESS_VIOLATION);
2509         ret = FALSE;
2510     }
2511     __ENDTRY
2512     return ret;
2513 }
2514
2515 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2516  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2517  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2518 {
2519     BOOL ret;
2520
2521     __TRY
2522     {
2523         SYSTEMTIME sysTime;
2524
2525         /* Check the year, if it's in the UTCTime range call that encode func */
2526         if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2527             return FALSE;
2528         if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2529             ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2530              pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2531         else
2532             ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2533              lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2534              pcbEncoded);
2535     }
2536     __EXCEPT_PAGE_FAULT
2537     {
2538         SetLastError(STATUS_ACCESS_VIOLATION);
2539         ret = FALSE;
2540     }
2541     __ENDTRY
2542     return ret;
2543 }
2544
2545 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2546  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2547  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2548 {
2549     BOOL ret;
2550
2551     __TRY
2552     {
2553         DWORD bytesNeeded, dataLen, lenBytes, i;
2554         const CRYPT_SEQUENCE_OF_ANY *seq =
2555          (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2556
2557         for (i = 0, dataLen = 0; i < seq->cValue; i++)
2558             dataLen += seq->rgValue[i].cbData;
2559         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2560         bytesNeeded = 1 + lenBytes + dataLen;
2561         if (!pbEncoded)
2562         {
2563             *pcbEncoded = bytesNeeded;
2564             ret = TRUE;
2565         }
2566         else
2567         {
2568             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2569              pcbEncoded, bytesNeeded)))
2570             {
2571                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2572                     pbEncoded = *(BYTE **)pbEncoded;
2573                 *pbEncoded++ = ASN_SEQUENCEOF;
2574                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2575                 pbEncoded += lenBytes;
2576                 for (i = 0; i < seq->cValue; i++)
2577                 {
2578                     memcpy(pbEncoded, seq->rgValue[i].pbData,
2579                      seq->rgValue[i].cbData);
2580                     pbEncoded += seq->rgValue[i].cbData;
2581                 }
2582             }
2583         }
2584     }
2585     __EXCEPT_PAGE_FAULT
2586     {
2587         SetLastError(STATUS_ACCESS_VIOLATION);
2588         ret = FALSE;
2589     }
2590     __ENDTRY
2591     return ret;
2592 }
2593
2594 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2595  BYTE *pbEncoded, DWORD *pcbEncoded)
2596 {
2597     BOOL ret = TRUE;
2598     struct AsnEncodeSequenceItem items[3] = { { 0 } };
2599     struct AsnConstructedItem constructed = { 0 };
2600     struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2601     DWORD cItem = 0, cSwapped = 0;
2602
2603     switch (distPoint->DistPointName.dwDistPointNameChoice)
2604     {
2605     case CRL_DIST_POINT_NO_NAME:
2606         /* do nothing */
2607         break;
2608     case CRL_DIST_POINT_FULL_NAME:
2609         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2610         swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2611         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2612         constructed.tag = 0;
2613         constructed.pvStructInfo = &swapped[cSwapped];
2614         constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2615         items[cItem].pvStructInfo = &constructed;
2616         items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2617         cSwapped++;
2618         cItem++;
2619         break;
2620     case CRL_DIST_POINT_ISSUER_RDN_NAME:
2621         FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2622         ret = FALSE;
2623         break;
2624     default:
2625         ret = FALSE;
2626     }
2627     if (ret && distPoint->ReasonFlags.cbData)
2628     {
2629         swapped[cSwapped].tag = ASN_CONTEXT | 1;
2630         swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2631         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2632         items[cItem].pvStructInfo = &swapped[cSwapped];
2633         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2634         cSwapped++;
2635         cItem++;
2636     }
2637     if (ret && distPoint->CRLIssuer.cAltEntry)
2638     {
2639         swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2640         swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2641         swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2642         items[cItem].pvStructInfo = &swapped[cSwapped];
2643         items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2644         cSwapped++;
2645         cItem++;
2646     }
2647     if (ret)
2648         ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2649          pbEncoded, pcbEncoded);
2650     return ret;
2651 }
2652
2653 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2654  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2655  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2656 {
2657     BOOL ret;
2658
2659     __TRY
2660     {
2661         const CRL_DIST_POINTS_INFO *info =
2662          (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2663
2664         if (!info->cDistPoint)
2665         {
2666             SetLastError(E_INVALIDARG);
2667             ret = FALSE;
2668         }
2669         else
2670         {
2671             DWORD bytesNeeded, dataLen, lenBytes, i;
2672
2673             ret = TRUE;
2674             for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2675             {
2676                 DWORD len;
2677
2678                 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2679                  &len);
2680                 if (ret)
2681                     dataLen += len;
2682                 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2683                 {
2684                     /* Have to propagate index of failing character */
2685                     *pcbEncoded = len;
2686                 }
2687             }
2688             if (ret)
2689             {
2690                 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2691                 bytesNeeded = 1 + lenBytes + dataLen;
2692                 if (!pbEncoded)
2693                 {
2694                     *pcbEncoded = bytesNeeded;
2695                     ret = TRUE;
2696                 }
2697                 else
2698                 {
2699                     if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2700                      pbEncoded, pcbEncoded, bytesNeeded)))
2701                     {
2702                         if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2703                             pbEncoded = *(BYTE **)pbEncoded;
2704                         *pbEncoded++ = ASN_SEQUENCEOF;
2705                         CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2706                         pbEncoded += lenBytes;
2707                         for (i = 0; ret && i < info->cDistPoint; i++)
2708                         {
2709                             DWORD len = dataLen;
2710
2711                             ret = CRYPT_AsnEncodeDistPoint(
2712                              &info->rgDistPoint[i], pbEncoded, &len);
2713                             if (ret)
2714                             {
2715                                 pbEncoded += len;
2716                                 dataLen -= len;
2717                             }
2718                         }
2719                     }
2720                 }
2721             }
2722         }
2723     }
2724     __EXCEPT_PAGE_FAULT
2725     {
2726         SetLastError(STATUS_ACCESS_VIOLATION);
2727         ret = FALSE;
2728     }
2729     __ENDTRY
2730     return ret;
2731 }
2732
2733 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
2734  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2735  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2736 {
2737     BOOL ret;
2738
2739     __TRY
2740     {
2741         const CERT_ENHKEY_USAGE *usage =
2742          (const CERT_ENHKEY_USAGE *)pvStructInfo;
2743         DWORD bytesNeeded = 0, lenBytes, size, i;
2744
2745         ret = TRUE;
2746         for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2747         {
2748             ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2749              usage->rgpszUsageIdentifier[i],
2750              dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
2751             if (ret)
2752                 bytesNeeded += size;
2753         }
2754         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2755         bytesNeeded += 1 + lenBytes;
2756         if (ret)
2757         {
2758             if (!pbEncoded)
2759                 *pcbEncoded = bytesNeeded;
2760             else
2761             {
2762                 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2763                  pbEncoded, pcbEncoded, bytesNeeded)))
2764                 {
2765                     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2766                         pbEncoded = *(BYTE **)pbEncoded;
2767                     *pbEncoded++ = ASN_SEQUENCEOF;
2768                     CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2769                      &lenBytes);
2770                     pbEncoded += lenBytes;
2771                     for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2772                     {
2773                         size = bytesNeeded;
2774                         ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2775                          usage->rgpszUsageIdentifier[i],
2776                          dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
2777                          &size);
2778                         if (ret)
2779                         {
2780                             pbEncoded += size;
2781                             bytesNeeded -= size;
2782                         }
2783                     }
2784                 }
2785             }
2786         }
2787     }
2788     __EXCEPT_PAGE_FAULT
2789     {
2790         SetLastError(STATUS_ACCESS_VIOLATION);
2791         ret = FALSE;
2792     }
2793     __ENDTRY
2794     return ret;
2795 }
2796
2797 static BOOL WINAPI CRYPT_AsnEncodeIssuingDistPoint(DWORD dwCertEncodingType,
2798  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2799  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2800 {
2801     BOOL ret;
2802
2803     __TRY
2804     {
2805         const CRL_ISSUING_DIST_POINT *point =
2806          (const CRL_ISSUING_DIST_POINT *)pvStructInfo;
2807         struct AsnEncodeSequenceItem items[6] = { { 0 } };
2808         struct AsnConstructedItem constructed = { 0 };
2809         struct AsnEncodeTagSwappedItem swapped[5] = { { 0 } };
2810         DWORD cItem = 0, cSwapped = 0;
2811
2812         ret = TRUE;
2813         switch (point->DistPointName.dwDistPointNameChoice)
2814         {
2815         case CRL_DIST_POINT_NO_NAME:
2816             /* do nothing */
2817             break;
2818         case CRL_DIST_POINT_FULL_NAME:
2819             swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2820             swapped[cSwapped].pvStructInfo = &point->DistPointName.u.FullName;
2821             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2822             constructed.tag = 0;
2823             constructed.pvStructInfo = &swapped[cSwapped];
2824             constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2825             items[cItem].pvStructInfo = &constructed;
2826             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2827             cSwapped++;
2828             cItem++;
2829             break;
2830         default:
2831             SetLastError(E_INVALIDARG);
2832             ret = FALSE;
2833         }
2834         if (ret && point->fOnlyContainsUserCerts)
2835         {
2836             swapped[cSwapped].tag = ASN_CONTEXT | 1;
2837             swapped[cSwapped].pvStructInfo = &point->fOnlyContainsUserCerts;
2838             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2839             items[cItem].pvStructInfo = &swapped[cSwapped];
2840             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2841             cSwapped++;
2842             cItem++;
2843         }
2844         if (ret && point->fOnlyContainsCACerts)
2845         {
2846             swapped[cSwapped].tag = ASN_CONTEXT | 2;
2847             swapped[cSwapped].pvStructInfo = &point->fOnlyContainsCACerts;
2848             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2849             items[cItem].pvStructInfo = &swapped[cSwapped];
2850             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2851             cSwapped++;
2852             cItem++;
2853         }
2854         if (ret && point->OnlySomeReasonFlags.cbData)
2855         {
2856             swapped[cSwapped].tag = ASN_CONTEXT | 3;
2857             swapped[cSwapped].pvStructInfo = &point->OnlySomeReasonFlags;
2858             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2859             items[cItem].pvStructInfo = &swapped[cSwapped];
2860             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2861             cSwapped++;
2862             cItem++;
2863         }
2864         if (ret && point->fIndirectCRL)
2865         {
2866             swapped[cSwapped].tag = ASN_CONTEXT | 4;
2867             swapped[cSwapped].pvStructInfo = &point->fIndirectCRL;
2868             swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBool;
2869             items[cItem].pvStructInfo = &swapped[cSwapped];
2870             items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2871             cSwapped++;
2872             cItem++;
2873         }
2874         if (ret)
2875             ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
2876              dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2877     }
2878     __EXCEPT_PAGE_FAULT
2879     {
2880         SetLastError(STATUS_ACCESS_VIOLATION);
2881         ret = FALSE;
2882     }
2883     __ENDTRY
2884     return ret;
2885 }
2886
2887 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2888  const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2889  void *pvEncoded, DWORD *pcbEncoded)
2890 {
2891     static HCRYPTOIDFUNCSET set = NULL;
2892     BOOL ret = FALSE;
2893     CryptEncodeObjectExFunc encodeFunc = NULL;
2894     HCRYPTOIDFUNCADDR hFunc = NULL;
2895
2896     TRACE("(0x%08x, %s, %p, 0x%08x, %p, %p, %p)\n", dwCertEncodingType,
2897      debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2898      pvEncoded, pcbEncoded);
2899
2900     if (!pvEncoded && !pcbEncoded)
2901     {
2902         SetLastError(ERROR_INVALID_PARAMETER);
2903         return FALSE;
2904     }
2905     if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2906      && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2907     {
2908         SetLastError(ERROR_FILE_NOT_FOUND);
2909         return FALSE;
2910     }
2911
2912     SetLastError(NOERROR);
2913     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2914         *(BYTE **)pvEncoded = NULL;
2915     if (!HIWORD(lpszStructType))
2916     {
2917         switch (LOWORD(lpszStructType))
2918         {
2919         case (WORD)X509_CERT:
2920             encodeFunc = CRYPT_AsnEncodeCert;
2921             break;
2922         case (WORD)X509_CERT_TO_BE_SIGNED:
2923             encodeFunc = CRYPT_AsnEncodeCertInfo;
2924             break;
2925         case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2926             encodeFunc = CRYPT_AsnEncodeCRLInfo;
2927             break;
2928         case (WORD)X509_EXTENSIONS:
2929             encodeFunc = CRYPT_AsnEncodeExtensions;
2930             break;
2931         case (WORD)X509_NAME_VALUE:
2932             encodeFunc = CRYPT_AsnEncodeNameValue;
2933             break;
2934         case (WORD)X509_NAME:
2935             encodeFunc = CRYPT_AsnEncodeName;
2936             break;
2937         case (WORD)X509_PUBLIC_KEY_INFO:
2938             encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2939             break;
2940         case (WORD)X509_AUTHORITY_KEY_ID:
2941             encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
2942             break;
2943         case (WORD)X509_ALTERNATE_NAME:
2944             encodeFunc = CRYPT_AsnEncodeAltName;
2945             break;
2946         case (WORD)X509_BASIC_CONSTRAINTS:
2947             encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2948             break;
2949         case (WORD)X509_BASIC_CONSTRAINTS2:
2950             encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2951             break;
2952         case (WORD)RSA_CSP_PUBLICKEYBLOB:
2953             encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2954             break;
2955         case (WORD)X509_UNICODE_NAME:
2956             encodeFunc = CRYPT_AsnEncodeUnicodeName;
2957             break;
2958         case (WORD)X509_UNICODE_NAME_VALUE:
2959             encodeFunc = CRYPT_AsnEncodeUnicodeNameValue;
2960             break;
2961         case (WORD)X509_OCTET_STRING:
2962             encodeFunc = CRYPT_AsnEncodeOctets;
2963             break;
2964         case (WORD)X509_BITS:
2965         case (WORD)X509_KEY_USAGE:
2966             encodeFunc = CRYPT_AsnEncodeBits;
2967             break;
2968         case (WORD)X509_INTEGER:
2969             encodeFunc = CRYPT_AsnEncodeInt;
2970             break;
2971         case (WORD)X509_MULTI_BYTE_INTEGER:
2972             encodeFunc = CRYPT_AsnEncodeInteger;
2973             break;
2974         case (WORD)X509_MULTI_BYTE_UINT:
2975             encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2976             break;
2977         case (WORD)X509_ENUMERATED:
2978             encodeFunc = CRYPT_AsnEncodeEnumerated;
2979             break;
2980         case (WORD)X509_CHOICE_OF_TIME:
2981             encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2982             break;
2983         case (WORD)X509_SEQUENCE_OF_ANY:
2984             encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2985             break;
2986         case (WORD)PKCS_UTC_TIME:
2987             encodeFunc = CRYPT_AsnEncodeUtcTime;
2988             break;
2989         case (WORD)X509_CRL_DIST_POINTS:
2990             encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2991             break;
2992         case (WORD)X509_ENHANCED_KEY_USAGE:
2993             encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2994             break;
2995         case (WORD)X509_ISSUING_DIST_POINT:
2996             encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
2997             break;
2998         default:
2999             FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
3000         }
3001     }
3002     else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
3003         encodeFunc = CRYPT_AsnEncodeExtensions;
3004     else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
3005         encodeFunc = CRYPT_AsnEncodeUtcTime;
3006     else if (!strcmp(lpszStructType, szOID_AUTHORITY_KEY_IDENTIFIER))
3007         encodeFunc = CRYPT_AsnEncodeAuthorityKeyId;
3008     else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
3009         encodeFunc = CRYPT_AsnEncodeEnumerated;
3010     else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
3011         encodeFunc = CRYPT_AsnEncodeBits;
3012     else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
3013         encodeFunc = CRYPT_AsnEncodeOctets;
3014     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
3015         encodeFunc = CRYPT_AsnEncodeBasicConstraints;
3016     else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
3017         encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
3018     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
3019         encodeFunc = CRYPT_AsnEncodeAltName;
3020     else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
3021         encodeFunc = CRYPT_AsnEncodeAltName;
3022     else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
3023         encodeFunc = CRYPT_AsnEncodeAltName;
3024     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
3025         encodeFunc = CRYPT_AsnEncodeAltName;
3026     else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
3027         encodeFunc = CRYPT_AsnEncodeAltName;
3028     else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
3029         encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
3030     else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
3031         encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
3032     else if (!strcmp(lpszStructType, szOID_ISSUING_DIST_POINT))
3033         encodeFunc = CRYPT_AsnEncodeIssuingDistPoint;
3034     else
3035         TRACE("OID %s not found or unimplemented, looking for DLL\n",
3036          debugstr_a(lpszStructType));
3037     if (!encodeFunc)
3038     {
3039         if (!set)
3040             set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
3041         CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
3042          (void **)&encodeFunc, &hFunc);
3043     }
3044     if (encodeFunc)
3045         ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
3046          dwFlags, pEncodePara, pvEncoded, pcbEncoded);
3047     else
3048         SetLastError(ERROR_FILE_NOT_FOUND);
3049     if (hFunc)
3050         CryptFreeOIDFunctionAddress(hFunc, 0);
3051     return ret;
3052 }
3053
3054 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3055  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3056 {
3057     return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
3058      NULL, 0, NULL, pInfo, pcbInfo);
3059 }
3060
3061 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3062  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3063  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3064 {
3065     BOOL ret;
3066     HCRYPTKEY key;
3067     static CHAR oid[] = szOID_RSA_RSA;
3068
3069     TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3070      dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3071      pInfo, pcbInfo);
3072
3073     if (!pszPublicKeyObjId)
3074         pszPublicKeyObjId = oid;
3075     if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
3076     {
3077         DWORD keySize = 0;
3078
3079         ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
3080         if (ret)
3081         {
3082             LPBYTE pubKey = CryptMemAlloc(keySize);
3083
3084             if (pubKey)
3085             {
3086                 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
3087                  &keySize);
3088                 if (ret)
3089                 {
3090                     DWORD encodedLen = 0;
3091
3092                     ret = CryptEncodeObject(dwCertEncodingType,
3093                      RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
3094                     if (ret)
3095                     {
3096                         DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
3097                          strlen(pszPublicKeyObjId) + 1 + encodedLen;
3098
3099                         if (!pInfo)
3100                             *pcbInfo = sizeNeeded;
3101                         else if (*pcbInfo < sizeNeeded)
3102                         {
3103                             SetLastError(ERROR_MORE_DATA);
3104                             *pcbInfo = sizeNeeded;
3105                             ret = FALSE;
3106                         }
3107                         else
3108                         {
3109                             pInfo->Algorithm.pszObjId = (char *)pInfo +
3110                              sizeof(CERT_PUBLIC_KEY_INFO);
3111                             lstrcpyA(pInfo->Algorithm.pszObjId,
3112                              pszPublicKeyObjId);
3113                             pInfo->Algorithm.Parameters.cbData = 0;
3114                             pInfo->Algorithm.Parameters.pbData = NULL;
3115                             pInfo->PublicKey.pbData =
3116                              (BYTE *)pInfo->Algorithm.pszObjId
3117                              + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
3118                             pInfo->PublicKey.cbData = encodedLen;
3119                             pInfo->PublicKey.cUnusedBits = 0;
3120                             ret = CryptEncodeObject(dwCertEncodingType,
3121                              RSA_CSP_PUBLICKEYBLOB, pubKey,
3122                              pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
3123                         }
3124                     }
3125                 }
3126                 CryptMemFree(pubKey);
3127             }
3128             else
3129                 ret = FALSE;
3130         }
3131         CryptDestroyKey(key);
3132     }
3133     return ret;
3134 }
3135
3136 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3137  DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
3138  DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
3139
3140 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
3141  DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
3142  void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
3143 {
3144     static HCRYPTOIDFUNCSET set = NULL;
3145     BOOL ret;
3146     ExportPublicKeyInfoExFunc exportFunc = NULL;
3147     HCRYPTOIDFUNCADDR hFunc = NULL;
3148
3149     TRACE("(%08lx, %d, %08x, %s, %08x, %p, %p, %p)\n", hCryptProv, dwKeySpec,
3150      dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
3151      pInfo, pcbInfo);
3152
3153     if (!hCryptProv)
3154     {
3155         SetLastError(ERROR_INVALID_PARAMETER);
3156         return FALSE;
3157     }
3158
3159     if (pszPublicKeyObjId)
3160     {
3161         if (!set)
3162             set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
3163              0);
3164         CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
3165          0, (void **)&exportFunc, &hFunc);
3166     }
3167     if (!exportFunc)
3168         exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
3169     ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
3170      pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
3171     if (hFunc)
3172         CryptFreeOIDFunctionAddress(hFunc, 0);
3173     return ret;
3174 }
3175
3176 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
3177  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
3178 {
3179     return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
3180      0, 0, NULL, phKey);
3181 }
3182
3183 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3184  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3185  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3186 {
3187     BOOL ret;
3188     DWORD pubKeySize = 0;
3189
3190     TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv,
3191      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3192
3193     ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3194      pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
3195     if (ret)
3196     {
3197         LPBYTE pubKey = CryptMemAlloc(pubKeySize);
3198
3199         if (pubKey)
3200         {
3201             ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
3202              pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
3203              &pubKeySize);
3204             if (ret)
3205                 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
3206                  phKey);
3207             CryptMemFree(pubKey);
3208         }
3209         else
3210             ret = FALSE;
3211     }
3212     return ret;
3213 }
3214
3215 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
3216  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3217  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
3218
3219 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
3220  DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
3221  DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
3222 {
3223     static HCRYPTOIDFUNCSET set = NULL;
3224     BOOL ret;
3225     ImportPublicKeyInfoExFunc importFunc = NULL;
3226     HCRYPTOIDFUNCADDR hFunc = NULL;
3227
3228     TRACE("(%08lx, %d, %p, %d, %08x, %p, %p)\n", hCryptProv,
3229      dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
3230
3231     if (!set)
3232         set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
3233     CryptGetOIDFunctionAddress(set, dwCertEncodingType,
3234      pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
3235     if (!importFunc)
3236         importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
3237     ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
3238      pvAuxInfo, phKey);
3239     if (hFunc)
3240         CryptFreeOIDFunctionAddress(hFunc, 0);
3241     return ret;
3242 }