~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/crypt32/encode.c

Version: ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~ [ wine-1.0-rc5 ] ~ [ wine-1.0-rc4 ] ~ [ wine-1.0-rc3 ] ~ [ wine-1.0-rc2 ] ~ [ wine-1.0-rc1 ] ~ [ wine-0.9.61 ] ~ [ wine-0.9.60 ] ~ [ wine-0.9.59 ] ~ [ wine-0.9.58 ] ~ [ wine-0.9.57 ] ~ [ wine-0.9.56 ] ~ [ wine-0.9.55 ] ~ [ wine-0.9.54 ] ~ [ wine-0.9.53 ] ~ [ wine-0.9.52 ] ~ [ wine-0.9.51 ] ~ [ wine-0.9.50 ] ~ [ wine-0.9.49 ] ~ [ wine-0.9.48 ] ~ [ wine-0.9.47 ] ~ [ wine-0.9.46 ] ~ [ wine-0.9.45 ] ~ [ wine-0.9.44 ] ~ [ wine-0.9.43 ] ~ [ wine-0.9.42 ] ~ [ wine-0.9.41 ] ~ [ wine-0.9.40 ] ~ [ wine-0.9.39 ] ~ [ wine-0.9.38 ] ~ [ wine-0.9.37 ] ~ [ wine-0.9.36 ] ~ [ wine-0.9.35 ] ~ [ wine-0.9.34 ] ~ [ wine-0.9.33 ] ~ [ wine-0.9.32 ] ~ [ wine-0.9.31 ] ~ [ wine-0.9.30 ] ~ [ wine-0.9.29 ] ~ [ wine-0.9.28 ] ~ [ wine-0.9.27 ] ~ [ wine-0.9.26 ] ~ [ wine-0.9.25 ] ~ [ wine-0.9.24 ] ~ [ wine-0.9.23 ] ~ [ wine-0.9.22 ] ~ [ wine-0.9.21 ] ~ [ wine-0.9.20 ] ~ [ wine-0.9.19 ] ~ [ wine-0.9.18 ] ~ [ wine-0.9.17 ] ~ [ wine-0.9.16 ] ~ [ wine-0.9.15 ] ~ [ wine-0.9.14 ] ~ [ wine-0.9.13 ] ~ [ wine-0.9.12 ] ~ [ wine-0.9.11 ] ~ [ wine-0.9.10 ] ~ [ wine-0.9.9 ] ~ [ wine-0.9.8 ] ~ [ wine-0.9.7 ] ~ [ wine-0.9.6 ] ~ [ wine-0.9.5 ] ~ [ wine-0.9.4 ] ~ [ wine-0.9.3 ] ~ [ wine-0.9.2 ] ~ [ wine-0.9.1 ] ~ [ wine-0.9 ] ~ [ wine20050930 ] ~ [ wine20050830 ] ~ [ wine20050725 ] ~ [ wine20050628 ] ~ [ wine20050524 ] ~ [ wine20050419 ] ~ [ wine20050310 ] ~ [ wine20050211 ] ~ [ wine20050111 ] ~ [ wine20041201 ] ~ [ wine20041019 ] ~ [ wine20040914 ] ~ [ wine20040813 ] ~ [ wine20040716 ] ~ [ wine20040615 ] ~ [ wine20040505 ] ~ [ wine20040408 ] ~ [ wine20040309 ] ~ [ wine20040213 ] ~ [ wine20040121 ] ~ [ wine20031212 ] ~ [ wine20031118 ] ~ [ wine20031016 ] ~ [ wine20030911 ] ~ [ wine20030813 ] ~ [ wine20030709 ] ~ [ wine20030618 ] ~ [ wine20030508 ] ~ [ wine20030408 ] ~ [ wine20030318 ] ~ [ wine20030219 ] ~ [ wine20030115 ] ~ [ wine20021219 ] ~ [ wine20021125 ] ~ [ wine20021031 ] ~ [ wine20021007 ] ~ [ wine20020904 ] ~ [ wine20020804 ] ~ [ wine20020710 ] ~ [ wine20020605 ] ~ [ wine20020509 ] ~ [ wine20020411 ] ~ [ wine20020310 ] ~ [ wine20020228 ] ~ [ wine20011226 ] ~ [ wine20011108 ] ~ [ wine20011004 ] ~ [ wine20010824 ] ~ [ wine20010731 ] ~ [ wine20010629 ] ~ [ wine20010510 ] ~ [ wine20010418 ] ~ [ wine20010326 ] ~ [ wine20010305 ] ~ [ wine20010216 ] ~ [ wine20010112 ] ~ [ wine20001222 ] ~ [ wine20001202 ] ~ [ wine20001026 ] ~ [ wine20001002 ] ~ [ wine20000909 ] ~ [ wine20000821 ] ~ [ wine20000801 ] ~ [ wine20000716 ] ~ [ wine20000326 ] ~ [ wine20000227 ] ~ [ wine20000130 ] ~ [ wine20000109 ] ~

  1 /*
  2  * Copyright 2005-2007 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 isn't
 21  * implemented, 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 "Constants for CryptEncodeObject and CryptDecodeObject"
 31  */
 32 
 33 #include "config.h"
 34 #include "wine/port.h"
 35 
 36 #include <assert.h>
 37 #include <stdarg.h>
 38 #include <stdio.h>
 39 #include <stdlib.h>
 40 
 41 #define NONAMELESSUNION
 42 
 43 #include "windef.h"
 44 #include "winbase.h"
 45 #include "wincrypt.h"
 46 #include "snmp.h"
 47 #include "wine/debug.h"
 48 #include "wine/exception.h"
 49 #include "wine/unicode.h"
 50 #include "crypt32_private.h"
 51 
 52 WINE_DEFAULT_DEBUG_CHANNEL(cryptasn);
 53 WINE_DECLARE_DEBUG_CHANNEL(crypt);
 54 
 55 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
 56  BYTE *, DWORD *);
 57 
 58 /* Prototypes for built-in encoders.  They follow the Ex style prototypes.
 59  * The dwCertEncodingType and lpszStructType are ignored by the built-in
 60  * functions, but the parameters are retained to simplify CryptEncodeObjectEx,
 61  * since it must call functions in external DLLs that follow these signatures.
 62  */
 63 BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
 64  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
 65  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
 66 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
 67  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
 68  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
 69 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
 70  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
 71  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
 72 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
 73  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
 74  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
 75 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
 76  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
 77  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
 78 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
 79  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
 80  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
 81 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
 82  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
 83  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
 84 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
 85  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
 86  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
 87 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
 88  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
 89  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
 90 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
 91  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
 92  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
 93 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
 94  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
 95  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
 96 
 97 BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
 98  BYTE *pbEncoded, DWORD *pcbEncoded, DWORD bytesNeeded)
 99 {
100     BOOL ret = TRUE;
101 
102     if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
103     {
104         if (pEncodePara && pEncodePara->pfnAlloc)
105             *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
106         else
107             *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
108         if (!*(BYTE **)pbEncoded)
109             ret = FALSE;
110         else
111             *pcbEncoded = bytesNeeded;
112     }
113     else if (bytesNeeded > *pcbEncoded)
114     {
115         *pcbEncoded = bytesNeeded;
116         SetLastError(ERROR_MORE_DATA);
117         ret = FALSE;
118     }
119     else
120         *pcbEncoded = bytesNeeded;
121     return ret;
122 }
123 
124 BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
125 {
126     DWORD bytesNeeded, significantBytes = 0;
127 
128     if (len <= 0x7f)
129         bytesNeeded = 1;
130     else
131     {
132         DWORD temp;
133 
134         for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
135          temp <<= 8, significantBytes--)
136             ;
137         bytesNeeded = significantBytes + 1;
138     }
139     if (!pbEncoded)
140     {
141         *pcbEncoded = bytesNeeded;
142         return TRUE;
143     }
144     if (*pcbEncoded < bytesNeeded)
145     {
146         SetLastError(ERROR_MORE_DATA);
147         return FALSE;
148     }
149     if (len <= 0x7f)
150         *pbEncoded = (BYTE)len;
151     else
152     {
153         DWORD i;
154 
155         *pbEncoded++ = significantBytes | 0x80;
156         for (i = 0; i < significantBytes; i++)
157         {
158             *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
159             len >>= 8;
160         }
161     }
162     *pcbEncoded = bytesNeeded;
163     return TRUE;
164 }
165 
166 BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
167  struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
168  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
169 {
170     BOOL ret;
171     DWORD i, dataLen = 0;
172 
173     TRACE("%p, %d, %08x, %p, %p, %d\n", items, cItem, dwFlags, pEncodePara,
174      pbEncoded, *pcbEncoded);
175     for (i = 0, ret = TRUE; ret && i < cItem; i++)
176     {
177         ret = items[i].encodeFunc(dwCertEncodingType, NULL,
178          items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
179          NULL, &items[i].size);
180         /* Some functions propagate their errors through the size */
181         if (!ret)
182             *pcbEncoded = items[i].size;
183         dataLen += items[i].size;
184     }
185     if (ret)
186     {
187         DWORD lenBytes, bytesNeeded;
188 
189         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
190         bytesNeeded = 1 + lenBytes + dataLen;
191         if (!pbEncoded)
192             *pcbEncoded = bytesNeeded;
193         else
194         {
195             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
196              pcbEncoded, bytesNeeded)))
197             {
198                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
199                     pbEncoded = *(BYTE **)pbEncoded;
200                 *pbEncoded++ = ASN_SEQUENCE;
201                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
202                 pbEncoded += lenBytes;
203                 for (i = 0; ret && i < cItem; i++)
204                 {
205                     ret = items[i].encodeFunc(dwCertEncodingType, NULL,
206                      items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
207                      NULL, pbEncoded, &items[i].size);
208                     /* Some functions propagate their errors through the size */
209                     if (!ret)
210                         *pcbEncoded = items[i].size;
211                     pbEncoded += items[i].size;
212                 }
213             }
214         }
215     }
216     TRACE("returning %d (%08x)\n", ret, GetLastError());
217     return ret;
218 }
219 
220 BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
221  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
222  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
223 {
224     BOOL ret;
225     const struct AsnConstructedItem *item =
226      (const struct AsnConstructedItem *)pvStructInfo;
227     DWORD len;
228 
229     if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
230      item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
231     {
232         DWORD dataLen, bytesNeeded;
233 
234         CRYPT_EncodeLen(len, NULL, &dataLen);
235         bytesNeeded = 1 + dataLen + len;
236         if (!pbEncoded)
237             *pcbEncoded = bytesNeeded;
238         else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
239          pbEncoded, pcbEncoded, bytesNeeded)))
240         {
241             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
242                 pbEncoded = *(BYTE **)pbEncoded;
243             *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
244             CRYPT_EncodeLen(len, pbEncoded, &dataLen);
245             pbEncoded += dataLen;
246             ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
247              item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
248              pbEncoded, &len);
249             if (!ret)
250             {
251                 /* Some functions propagate their errors through the size */
252                 *pcbEncoded = len;
253             }
254         }
255     }
256     else
257     {
258         /* Some functions propagate their errors through the size */
259         *pcbEncoded = len;
260     }
261     return ret;
262 }
263 
264 struct AsnEncodeTagSwappedItem
265 {
266     BYTE                    tag;
267     const void             *pvStructInfo;
268     CryptEncodeObjectExFunc encodeFunc;
269 };
270 
271 /* Sort of a wacky hack, it encodes something using the struct
272  * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag
273  * given in the struct AsnEncodeTagSwappedItem.
274  */
275 static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
276  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
277  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
278 {
279     BOOL ret;
280     const struct AsnEncodeTagSwappedItem *item =
281      (const struct AsnEncodeTagSwappedItem *)pvStructInfo;
282 
283     ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
284      item->pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
285     if (ret && pbEncoded)
286         *pbEncoded = item->tag;
287     return ret;
288 }
289 
290 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
291  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
292  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
293 {
294     const DWORD *ver = (const DWORD *)pvStructInfo;
295     BOOL ret;
296 
297     /* CERT_V1 is not encoded */
298     if (*ver == CERT_V1)
299     {
300         *pcbEncoded = 0;
301         ret = TRUE;
302     }
303     else
304     {
305         struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
306 
307         ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
308          &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
309     }
310     return ret;
311 }
312 
313 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
314  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
315  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
316 {
317     const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
318     BOOL ret;
319 
320     if (!pbEncoded)
321     {
322         *pcbEncoded = blob->cbData;
323         ret = TRUE;
324     }
325     else
326     {
327         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
328          pcbEncoded, blob->cbData)))
329         {
330             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
331                 pbEncoded = *(BYTE **)pbEncoded;
332             if (blob->cbData)
333                 memcpy(pbEncoded, blob->pbData, blob->cbData);
334             *pcbEncoded = blob->cbData;
335             ret = TRUE;
336         }
337     }
338     return ret;
339 }
340 
341 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
342  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
343  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
344 {
345     BOOL ret;
346     /* This has two filetimes in a row, a NotBefore and a NotAfter */
347     const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
348     struct AsnEncodeSequenceItem items[] = {
349      { timePtr,     CRYPT_AsnEncodeChoiceOfTime, 0 },
350      { timePtr + 1, CRYPT_AsnEncodeChoiceOfTime, 0 },
351     };
352 
353     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, 
354      sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
355      pcbEncoded);
356     return ret;
357 }
358 
359 /* Like CRYPT_AsnEncodeAlgorithmId, but encodes parameters as an asn.1 NULL
360  * if they are empty.
361  */
362 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmIdWithNullParams(
363  DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
364  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
365  DWORD *pcbEncoded)
366 {
367     const CRYPT_ALGORITHM_IDENTIFIER *algo =
368      (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
369     static const BYTE asn1Null[] = { ASN_NULL, 0 };
370     static const CRYPT_DATA_BLOB nullBlob = { sizeof(asn1Null),
371      (LPBYTE)asn1Null };
372     BOOL ret;
373     struct AsnEncodeSequenceItem items[2] = {
374      { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
375      { NULL,           CRYPT_CopyEncodedBlob, 0 },
376     };
377 
378     if (algo->Parameters.cbData)
379         items[1].pvStructInfo = &algo->Parameters;
380     else
381         items[1].pvStructInfo = &nullBlob;
382     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
383      sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
384      pcbEncoded);
385     return ret;
386 }
387 
388 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(DWORD dwCertEncodingType,
389  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
390  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
391 {
392     const CRYPT_ALGORITHM_IDENTIFIER *algo =
393      (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
394     BOOL ret;
395     struct AsnEncodeSequenceItem items[] = {
396      { algo->pszObjId,    CRYPT_AsnEncodeOid, 0 },
397      { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
398     };
399 
400     ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
401      sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
402      pcbEncoded);
403     return ret;
404 }
405 
406 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
407  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
408  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
409 {
410     BOOL ret;
411 
412     __TRY
413     {
414         const CERT_PUBLIC_KEY_INFO *info =
415          (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
416         struct AsnEncodeSequenceItem items[] = {
417          { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
418          { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
419         };
420 
421         TRACE("Encoding public key with OID %s\n",
422          debugstr_a(info->Algorithm.pszObjId));
423         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
424          sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
425          pcbEncoded);
426     }
427     __EXCEPT_PAGE_FAULT
428     {
429         SetLastError(STATUS_ACCESS_VIOLATION);
430         ret = FALSE;
431     }
432     __ENDTRY
433     return ret;
434 }
435 
436 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
437  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
438  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
439 {
440     BOOL ret;
441 
442     __TRY
443     {
444         const CERT_SIGNED_CONTENT_INFO *info =
445          (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
446         struct AsnEncodeSequenceItem items[] = {
447          { &info->ToBeSigned,         CRYPT_CopyEncodedBlob, 0 },
448          { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
449          { &info->Signature,          CRYPT_AsnEncodeBitsSwapBytes, 0 },
450         };
451 
452         if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
453             items[2].encodeFunc = CRYPT_AsnEncodeBits;
454         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, 
455          sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
456          pcbEncoded);
457     }
458     __EXCEPT_PAGE_FAULT
459     {
460         SetLastError(STATUS_ACCESS_VIOLATION);
461         ret = FALSE;
462     }
463     __ENDTRY
464     return ret;
465 }
466 
467 /* Like in Windows, this blithely ignores the validity of the passed-in
468  * CERT_INFO, and just encodes it as-is.  The resulting encoded data may not
469  * decode properly, see CRYPT_AsnDecodeCertInfo.
470  */
471 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
472  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
473  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
474 {
475     BOOL ret;
476 
477     __TRY
478     {
479         const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
480         struct AsnEncodeSequenceItem items[10] = {
481          { &info->dwVersion,            CRYPT_AsnEncodeCertVersion, 0 },
482          { &info->SerialNumber,         CRYPT_AsnEncodeInteger, 0 },
483          { &info->SignatureAlgorithm,   CRYPT_AsnEncodeAlgorithmId, 0 },
484          { &info->Issuer,               CRYPT_CopyEncodedBlob, 0 },
485          { &info->NotBefore,            CRYPT_AsnEncodeValidity, 0 },
486          { &info->Subject,              CRYPT_CopyEncodedBlob, 0 },
487          { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
488          { 0 }
489         };
490         struct AsnConstructedItem constructed[3] = { { 0 } };
491         DWORD cItem = 7, cConstructed = 0;
492 
493         if (info->IssuerUniqueId.cbData)
494         {
495             constructed[cConstructed].tag = 1;
496             constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
497             constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
498             items[cItem].pvStructInfo = &constructed[cConstructed];
499             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
500             cConstructed++;
501             cItem++;
502         }
503         if (info->SubjectUniqueId.cbData)
504         {
505             constructed[cConstructed].tag = 2;
506             constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
507             constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
508             items[cItem].pvStructInfo = &constructed[cConstructed];
509             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
510             cConstructed++;
511             cItem++;
512         }
513         if (info->cExtension)
514         {
515             constructed[cConstructed].tag = 3;
516             constructed[cConstructed].pvStructInfo = &info->cExtension;
517             constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
518             items[cItem].pvStructInfo = &constructed[cConstructed];
519             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
520             cConstructed++;
521             cItem++;
522         }
523 
524         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
525          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
526     }
527     __EXCEPT_PAGE_FAULT
528     {
529         SetLastError(STATUS_ACCESS_VIOLATION);
530         ret = FALSE;
531     }
532     __ENDTRY
533     return ret;
534 }
535 
536 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
537  BYTE *pbEncoded, DWORD *pcbEncoded)
538 {
539     struct AsnEncodeSequenceItem items[3] = {
540      { &entry->SerialNumber,   CRYPT_AsnEncodeInteger, 0 },
541      { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
542      { 0 }
543     };
544     DWORD cItem = 2;
545     BOOL ret;
546 
547     TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
548 
549     if (entry->cExtension)
550     {
551         items[cItem].pvStructInfo = &entry->cExtension;
552         items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
553         cItem++;
554     }
555 
556     ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
557      pbEncoded, pcbEncoded);
558 
559     TRACE("returning %d (%08x)\n", ret, GetLastError());
560     return ret;
561 }
562 
563 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
564  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
565  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
566 {
567     DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
568     DWORD bytesNeeded, dataLen, lenBytes, i;
569     const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY *const *)
570      ((const BYTE *)pvStructInfo + sizeof(DWORD));
571     BOOL ret = TRUE;
572 
573     for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
574     {
575         DWORD size;
576 
577         ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
578         if (ret)
579             dataLen += size;
580     }
581     CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
582     bytesNeeded = 1 + lenBytes + dataLen;
583     if (!pbEncoded)
584         *pcbEncoded = bytesNeeded;
585     else
586     {
587         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
588          pcbEncoded, bytesNeeded)))
589         {
590             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
591                 pbEncoded = *(BYTE **)pbEncoded;
592             *pbEncoded++ = ASN_SEQUENCEOF;
593             CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
594             pbEncoded += lenBytes;
595             for (i = 0; i < cCRLEntry; i++)
596             {
597                 DWORD size = dataLen;
598 
599                 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
600                 pbEncoded += size;
601                 dataLen -= size;
602             }
603         }
604     }
605     return ret;
606 }
607 
608 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
609  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
610  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
611 {
612     const DWORD *ver = (const DWORD *)pvStructInfo;
613     BOOL ret;
614 
615     /* CRL_V1 is not encoded */
616     if (*ver == CRL_V1)
617     {
618         *pcbEncoded = 0;
619         ret = TRUE;
620     }
621     else
622         ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
623          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
624     return ret;
625 }
626 
627 /* Like in Windows, this blithely ignores the validity of the passed-in
628  * CRL_INFO, and just encodes it as-is.  The resulting encoded data may not
629  * decode properly, see CRYPT_AsnDecodeCRLInfo.
630  */
631 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
632  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
633  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
634 {
635     BOOL ret;
636 
637     __TRY
638     {
639         const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
640         struct AsnEncodeSequenceItem items[7] = {
641          { &info->dwVersion,          CRYPT_AsnEncodeCRLVersion, 0 },
642          { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
643          { &info->Issuer,             CRYPT_CopyEncodedBlob, 0 },
644          { &info->ThisUpdate,         CRYPT_AsnEncodeChoiceOfTime, 0 },
645          { 0 }
646         };
647         struct AsnConstructedItem constructed[1] = { { 0 } };
648         DWORD cItem = 4, cConstructed = 0;
649 
650         if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
651         {
652             items[cItem].pvStructInfo = &info->NextUpdate;
653             items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
654             cItem++;
655         }
656         if (info->cCRLEntry)
657         {
658             items[cItem].pvStructInfo = &info->cCRLEntry;
659             items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
660             cItem++;
661         }
662         if (info->cExtension)
663         {
664             constructed[cConstructed].tag = 0;
665             constructed[cConstructed].pvStructInfo = &info->cExtension;
666             constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
667             items[cItem].pvStructInfo = &constructed[cConstructed];
668             items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
669             cConstructed++;
670             cItem++;
671         }
672 
673         ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
674          dwFlags, pEncodePara, pbEncoded, pcbEncoded);
675     }
676     __EXCEPT_PAGE_FAULT
677     {
678         SetLastError(STATUS_ACCESS_VIOLATION);
679         ret = FALSE;
680     }
681     __ENDTRY
682     return ret;
683 }
684 
685 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
686  DWORD *pcbEncoded)
687 {
688     BOOL ret;
689     struct AsnEncodeSequenceItem items[3] = {
690      { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
691      { NULL, NULL, 0 },
692      { NULL, NULL, 0 },
693     };
694     DWORD cItem = 1;
695 
696     TRACE("%p, %p, %d\n", ext, pbEncoded, *pcbEncoded);
697 
698     if (ext->fCritical)
699     {
700         items[cItem].pvStructInfo = &ext->fCritical;
701         items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
702         cItem++;
703     }
704     items[cItem].pvStructInfo = &ext->Value;
705     items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
706     cItem++;
707 
708     ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
709      pbEncoded, pcbEncoded);
710     TRACE("returning %d (%08x)\n", ret, GetLastError());
711     return ret;
712 }
713 
714 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
715  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
716  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
717 {
718     BOOL ret;
719 
720     __TRY
721     {
722         DWORD bytesNeeded, dataLen, lenBytes, i;
723         const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
724 
725         ret = TRUE;
726         for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
727         {
728             DWORD size;
729 
730             ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
731             if (ret)
732                 dataLen += size;
733         }
734         CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
735         bytesNeeded = 1 + lenBytes + dataLen;
736         if (!pbEncoded)
737             *pcbEncoded = bytesNeeded;
738         else
739         {
740             if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
741              pcbEncoded, bytesNeeded)))
742             {
743                 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
744                     pbEncoded = *(BYTE **)pbEncoded;
745                 *pbEncoded++ = ASN_SEQUENCEOF;
746                 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
747                 pbEncoded += lenBytes;
748                 for (i = 0; i < exts->cExtension; i++)
749                 {
750                     DWORD size = dataLen;
751 
752                     ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
753                      pbEncoded, &size);
754                     pbEncoded += size;
755                     dataLen -= size;
756                 }
757             }
758         }
759     }
760     __EXCEPT_PAGE_FAULT
761     {
762         SetLastError(STATUS_ACCESS_VIOLATION);
763         ret = FALSE;
764     }
765     __ENDTRY
766     return ret;
767 }
768 
769 BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
770  LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
771  PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
772 {
773     LPCSTR pszObjId = (LPCSTR)pvStructInfo;
774     DWORD bytesNeeded = 0, lenBytes;
775     BOOL ret = TRUE;
776     int firstPos = 0;
777     BYTE firstByte = 0;
778 
779     TRACE("%s\n", debugstr_a(pszObjId));
780 
781     if (pszObjId)
782     {
783         const char *ptr;
784         int val1, val2;
785 
786         if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
787         {
788             SetLastError(CRYPT_E_ASN1_ERROR);
789             return FALSE;
790         }
791         bytesNeeded++;
792         firstByte = val1 * 40 + val2;
793         ptr = pszObjId + firstPos;
794         while (ret && *ptr)
795         {
796             int pos;
797 
798             /* note I assume each component is at most 32-bits long in base 2 */
799             if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
800             {
801                 if (val1 >= 0x10000000)
802                     bytesNeeded += 5;
803                 else if (val1 >= 0x200000)
804                     bytesNeeded += 4;
805                 else if (val1 >= 0x4000)
806                     bytesNeeded += 3;
807                 else if (val1 >= 0x80)
808                     bytesNeeded += 2;
809                 else
810                     bytesNeeded += 1;
811                 ptr += pos;
812                 if (*ptr == '.')
813                     ptr++;
814             }
815             else
816             {
817                 SetLastError(CRYPT_E_ASN1_ERROR);
818                 return FALSE;
819             }
820         }
821         CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
822     }
823     else
824         lenBytes = 1;
825     bytesNeeded += 1 + lenBytes;
826     if (pbEncoded)
827     {
828         if (*pcbEncoded < bytesNeeded)
829         {
830             SetLastError(ERROR_MORE_DATA);
831             ret = FALSE;
832         }
833         else
834         {
835             *pbEncoded++ = ASN_OBJECTIDENTIFIER;
836             CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
837             pbEncoded += lenBytes;
838             if (pszObjId)
839             {
840                 const char *ptr;
841                 int val, pos;
842 
843                 *pbEncoded++ = firstByte;
844                 ptr = pszObjId + firstPos;
845                 while (ret && *ptr)
846                 {
847                     sscanf(ptr, "%d%n", &val, &pos);
848                     {
849                         unsigned char outBytes[5];
850                         int numBytes, i;
851 
852                         if (val >= 0x10000000)
853                             numBytes = 5;
854                         else if (val >= 0x200000)
855                             numBytes = 4;
856                         else if (val >= 0x4000)
857                             numBytes = 3;
858                         else if (val >= 0x80)
859                             numBytes = 2;
860                         else
861                             numBytes = 1;
862                         for (i = numBytes; i > 0; i--)
863                         {
864                             outBytes[i - 1] = val & 0x7f;
865                             val >>= 7;
866                         }
867                         for (i = 0; i < numBytes - 1; i++)
868                             *pbEncoded++ = outBytes[i] | 0x80;
869                         *pbEncoded++ = outBytes[i];
870                         ptr += pos;
871                         if (*ptr == '.')
872                             ptr++;
873                     }
874                 }
875             }
876         }
877     }
878     *pcbEncoded = bytesNeeded;
879     return ret;
880 }
881 
882 static BOOL CRYPT_AsnEncodeStringCoerce(const CERT_NAME_VALUE *value,
883  BYTE tag, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
884  DWORD *pcbEncoded)
885 {
886     BOOL ret = TRUE;
887     LPCSTR str = (LPCSTR)value->Value.pbData;
888     DWORD bytesNeeded, lenBytes, encodedLen;
889 
890     encodedLen = value->Value.cbData ? value->Value.cbData : lstrlenA(str);
891     CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
892     bytesNeeded = 1 + lenBytes + encodedLen;
893     if (!pbEncoded)
894         *pcbEncoded = bytesNeeded;
895     else
896     {
897         if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
898          pbEncoded, pcbEncoded, bytesNeeded)))
899         {
900             if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
901                 pbEncoded = *(BYTE **)pbEncoded;
902             *pbEncoded++ = tag;
903             CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
904             pbEncoded += lenBytes;
905             memcpy(pbEncoded, str, encodedLen);
906         }
907     }
908     return ret;
909 }
910 
911 static BOOL CRYPT_AsnEncodeBMPString(const CERT_NAME_VALUE *value,
912  DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
913  DWORD *pcbEncoded)
914 {
915     BOOL ret = TRUE;
916     LPCWSTR str = (LPCWSTR)value->Value.pbData;
917     DWORD bytesNeeded, lenBytes, strLen;
918 
919     if (value->Value.cbData)
920         strLen = value->Value.cbData / sizeof(WCHAR);
921     else if (value->Value.pbData)
922         strLen = lstrlenW(str);
923     else
924         strLen = 0;
925     CRYPT_EncodeLen(strLen * 2, NULL, &lenBytes);
926     bytesNeeded = 1 + lenBytes + strLen * 2;