user32: Implement SystemParametersInfo(SPI_[GS]ETCOMBOBOXANIMATION).
[wine/testsucceed.git] / dlls / crypt32 / encode.c
blobd04f747fa2f5b48ec007911786162927a5e8ce48
1 /*
2 * Copyright 2005 Juan Lang
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.
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.
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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 * This file implements ASN.1 DER encoding and decoding of a limited set of
19 * types. 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.
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.)
28 * RFC3280, http://www.faqs.org/rfcs/rfc3280.html
30 * MSDN, especially:
31 * http://msdn.microsoft.com/library/en-us/seccrypto/security/constants_for_cryptencodeobject_and_cryptdecodeobject.asp
34 #include "config.h"
35 #include "wine/port.h"
37 #include <assert.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <stdlib.h>
42 #define NONAMELESSUNION
44 #include "windef.h"
45 #include "winbase.h"
46 #include "excpt.h"
47 #include "wincrypt.h"
48 #include "winreg.h"
49 #include "snmp.h"
50 #include "wine/debug.h"
51 #include "wine/exception.h"
52 #include "crypt32_private.h"
54 /* This is a bit arbitrary, but to set some limit: */
55 #define MAX_ENCODED_LEN 0x02000000
57 /* a few asn.1 tags we need */
58 #define ASN_BOOL (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x01)
59 #define ASN_BITSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x03)
60 #define ASN_ENUMERATED (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x0a)
61 #define ASN_SETOF (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x11)
62 #define ASN_NUMERICSTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x12)
63 #define ASN_PRINTABLESTRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x13)
64 #define ASN_IA5STRING (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x16)
65 #define ASN_UTCTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x17)
66 #define ASN_GENERALTIME (ASN_UNIVERSAL | ASN_PRIMITIVE | 0x18)
68 #define ASN_FLAGS_MASK 0xe0
69 #define ASN_TYPE_MASK 0x1f
71 WINE_DEFAULT_DEBUG_CHANNEL(crypt);
73 struct GenericArray
75 DWORD cItems;
76 BYTE *rgItems;
79 typedef BOOL (WINAPI *CryptEncodeObjectFunc)(DWORD, LPCSTR, const void *,
80 BYTE *, DWORD *);
81 typedef BOOL (WINAPI *CryptEncodeObjectExFunc)(DWORD, LPCSTR, const void *,
82 DWORD, PCRYPT_ENCODE_PARA, BYTE *, DWORD *);
83 typedef BOOL (WINAPI *CryptDecodeObjectFunc)(DWORD, LPCSTR, const BYTE *,
84 DWORD, DWORD, void *, DWORD *);
85 typedef BOOL (WINAPI *CryptDecodeObjectExFunc)(DWORD, LPCSTR, const BYTE *,
86 DWORD, DWORD, PCRYPT_DECODE_PARA, void *, DWORD *);
88 /* Prototypes for built-in encoders/decoders. They follow the Ex style
89 * prototypes. The dwCertEncodingType and lpszStructType are ignored by the
90 * built-in functions, but the parameters are retained to simplify
91 * CryptEncodeObjectEx/CryptDecodeObjectEx, since they must call functions in
92 * external DLLs that follow these signatures.
94 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
95 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
96 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
97 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
98 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
99 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
100 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
101 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
102 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
103 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
104 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
105 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
106 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
107 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
108 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
109 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
110 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
111 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
112 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
113 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
114 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
115 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
116 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
117 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
118 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
119 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
120 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
121 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
122 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
123 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
124 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
125 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
126 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
127 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
128 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
129 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded);
131 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
132 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
133 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
134 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType,
135 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
136 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
137 /* Like CRYPT_AsnDecodeExtensions, except assumes rgExtension is set ahead of
138 * time, doesn't do memory allocation, and doesn't do exception handling.
139 * (This isn't intended to be the externally-called one.)
141 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
142 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
143 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
144 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
145 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId);
146 /* Assumes algo->Parameters.pbData is set ahead of time. Internal func. */
147 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
148 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
149 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
150 /* Internal function */
151 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
152 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
153 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
154 /* Assumes the CRYPT_DATA_BLOB's pbData member has been initialized */
155 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
156 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
157 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
158 /* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
159 * member has been initialized, doesn't do exception handling, and doesn't do
160 * memory allocation.
162 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
163 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
164 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
165 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
166 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
167 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
168 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
169 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
170 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
171 /* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
172 * member has been initialized, doesn't do exception handling, and doesn't do
173 * memory allocation.
175 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
176 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
177 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
178 /* Like CRYPT_AsnDecodeInteger, but unsigned. */
179 static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
180 DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
181 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
182 void *pvStructInfo, DWORD *pcbStructInfo);
184 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
185 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
187 static HCRYPTOIDFUNCSET set = NULL;
188 BOOL ret = FALSE;
189 HCRYPTOIDFUNCADDR hFunc;
190 CryptEncodeObjectFunc pCryptEncodeObject;
192 TRACE("(0x%08lx, %s, %p, %p, %p)\n", dwCertEncodingType,
193 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
194 pcbEncoded);
196 if (!pbEncoded && !pcbEncoded)
198 SetLastError(ERROR_INVALID_PARAMETER);
199 return FALSE;
202 /* Try registered DLL first.. */
203 if (!set)
204 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_FUNC, 0);
205 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
206 (void **)&pCryptEncodeObject, &hFunc);
207 if (pCryptEncodeObject)
209 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
210 pvStructInfo, pbEncoded, pcbEncoded);
211 CryptFreeOIDFunctionAddress(hFunc, 0);
213 else
215 /* If not, use CryptEncodeObjectEx */
216 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
217 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
219 return ret;
222 /* Helper function to check *pcbEncoded, set it to the required size, and
223 * optionally to allocate memory. Assumes pbEncoded is not NULL.
224 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
225 * pointer to the newly allocated memory.
227 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
228 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
229 DWORD bytesNeeded)
231 BOOL ret = TRUE;
233 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
235 if (pEncodePara && pEncodePara->pfnAlloc)
236 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
237 else
238 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
239 if (!*(BYTE **)pbEncoded)
240 ret = FALSE;
241 else
242 *pcbEncoded = bytesNeeded;
244 else if (bytesNeeded > *pcbEncoded)
246 *pcbEncoded = bytesNeeded;
247 SetLastError(ERROR_MORE_DATA);
248 ret = FALSE;
250 return ret;
253 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
255 DWORD bytesNeeded, significantBytes = 0;
257 if (len <= 0x7f)
258 bytesNeeded = 1;
259 else
261 DWORD temp;
263 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
264 temp <<= 8, significantBytes--)
266 bytesNeeded = significantBytes + 1;
268 if (!pbEncoded)
270 *pcbEncoded = bytesNeeded;
271 return TRUE;
273 if (*pcbEncoded < bytesNeeded)
275 SetLastError(ERROR_MORE_DATA);
276 return FALSE;
278 if (len <= 0x7f)
279 *pbEncoded = (BYTE)len;
280 else
282 DWORD i;
284 *pbEncoded++ = significantBytes | 0x80;
285 for (i = 0; i < significantBytes; i++)
287 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
288 len >>= 8;
291 *pcbEncoded = bytesNeeded;
292 return TRUE;
295 struct AsnEncodeSequenceItem
297 const void *pvStructInfo;
298 CryptEncodeObjectExFunc encodeFunc;
299 DWORD size; /* used during encoding, not for your use */
302 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
303 struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
304 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
306 BOOL ret;
307 DWORD i, dataLen = 0;
309 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", items, cItem, dwFlags, pEncodePara,
310 pbEncoded, *pcbEncoded);
311 for (i = 0, ret = TRUE; ret && i < cItem; i++)
313 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
314 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
315 NULL, &items[i].size);
316 /* Some functions propagate their errors through the size */
317 if (!ret)
318 *pcbEncoded = items[i].size;
319 dataLen += items[i].size;
321 if (ret)
323 DWORD lenBytes, bytesNeeded;
325 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
326 bytesNeeded = 1 + lenBytes + dataLen;
327 if (!pbEncoded)
328 *pcbEncoded = bytesNeeded;
329 else
331 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
332 pcbEncoded, bytesNeeded)))
334 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
335 pbEncoded = *(BYTE **)pbEncoded;
336 *pbEncoded++ = ASN_SEQUENCE;
337 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
338 pbEncoded += lenBytes;
339 for (i = 0; ret && i < cItem; i++)
341 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
342 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
343 NULL, pbEncoded, &items[i].size);
344 /* Some functions propagate their errors through the size */
345 if (!ret)
346 *pcbEncoded = items[i].size;
347 pbEncoded += items[i].size;
352 TRACE("returning %d (%08lx)\n", ret, GetLastError());
353 return ret;
356 struct AsnConstructedItem
358 BYTE tag;
359 const void *pvStructInfo;
360 CryptEncodeObjectExFunc encodeFunc;
363 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
364 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
365 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
367 BOOL ret;
368 const struct AsnConstructedItem *item =
369 (const struct AsnConstructedItem *)pvStructInfo;
370 DWORD len;
372 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
373 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
375 DWORD dataLen, bytesNeeded;
377 CRYPT_EncodeLen(len, NULL, &dataLen);
378 bytesNeeded = 1 + dataLen + len;
379 if (!pbEncoded)
380 *pcbEncoded = bytesNeeded;
381 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
382 pbEncoded, pcbEncoded, bytesNeeded)))
384 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
385 pbEncoded = *(BYTE **)pbEncoded;
386 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
387 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
388 pbEncoded += dataLen;
389 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
390 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
391 pbEncoded, &len);
392 if (!ret)
394 /* Some functions propagate their errors through the size */
395 *pcbEncoded = len;
399 else
401 /* Some functions propagate their errors through the size */
402 *pcbEncoded = len;
404 return ret;
407 struct AsnEncodeTagSwappedItem
409 BYTE tag;
410 const void *pvStructInfo;
411 CryptEncodeObjectExFunc encodeFunc;
414 /* Sort of a wacky hack, it encodes something using the struct
415 * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag
416 * given in the struct AsnEncodeTagSwappedItem.
418 static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
419 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
420 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
422 BOOL ret;
423 const struct AsnEncodeTagSwappedItem *item =
424 (const struct AsnEncodeTagSwappedItem *)pvStructInfo;
426 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
427 item->pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
428 if (ret && pbEncoded)
429 *pbEncoded = item->tag;
430 return ret;
433 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
434 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
435 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
437 const DWORD *ver = (const DWORD *)pvStructInfo;
438 BOOL ret;
440 /* CERT_V1 is not encoded */
441 if (*ver == CERT_V1)
443 *pcbEncoded = 0;
444 ret = TRUE;
446 else
448 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
450 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
451 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
453 return ret;
456 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
457 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
458 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
460 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
461 BOOL ret;
463 if (!pbEncoded)
465 *pcbEncoded = blob->cbData;
466 ret = TRUE;
468 else if (*pcbEncoded < blob->cbData)
470 *pcbEncoded = blob->cbData;
471 SetLastError(ERROR_MORE_DATA);
472 ret = FALSE;
474 else
476 if (blob->cbData)
477 memcpy(pbEncoded, blob->pbData, blob->cbData);
478 *pcbEncoded = blob->cbData;
479 ret = TRUE;
481 return ret;
484 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
485 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
486 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
488 BOOL ret;
489 /* This has two filetimes in a row, a NotBefore and a NotAfter */
490 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
491 struct AsnEncodeSequenceItem items[] = {
492 { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
493 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
496 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
497 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
498 pcbEncoded);
499 return ret;
502 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
503 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
504 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
505 DWORD *pcbEncoded)
507 const CRYPT_ALGORITHM_IDENTIFIER *algo =
508 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
509 BOOL ret;
510 struct AsnEncodeSequenceItem items[] = {
511 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
512 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
515 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
516 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
517 pcbEncoded);
518 return ret;
521 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
522 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
523 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
525 BOOL ret;
527 __TRY
529 const CERT_PUBLIC_KEY_INFO *info =
530 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
531 struct AsnEncodeSequenceItem items[] = {
532 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
533 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
536 TRACE("Encoding public key with OID %s\n",
537 debugstr_a(info->Algorithm.pszObjId));
538 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
539 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
540 pcbEncoded);
542 __EXCEPT_PAGE_FAULT
544 SetLastError(STATUS_ACCESS_VIOLATION);
545 ret = FALSE;
547 __ENDTRY
548 return ret;
551 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
552 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
553 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
555 BOOL ret;
557 __TRY
559 const CERT_SIGNED_CONTENT_INFO *info =
560 (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
561 struct AsnEncodeSequenceItem items[] = {
562 { &info->ToBeSigned, CRYPT_CopyEncodedBlob, 0 },
563 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
564 { &info->Signature, CRYPT_AsnEncodeBitsSwapBytes, 0 },
567 if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
568 items[2].encodeFunc = CRYPT_AsnEncodeBits;
569 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
570 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
571 pcbEncoded);
573 __EXCEPT_PAGE_FAULT
575 SetLastError(STATUS_ACCESS_VIOLATION);
576 ret = FALSE;
578 __ENDTRY
579 return ret;
582 /* Like in Windows, this blithely ignores the validity of the passed-in
583 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
584 * decode properly, see CRYPT_AsnDecodeCertInfo.
586 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
587 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
588 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
590 BOOL ret;
592 __TRY
594 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
595 struct AsnEncodeSequenceItem items[10] = {
596 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
597 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
598 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
599 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
600 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
601 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
602 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
603 { 0 }
605 struct AsnConstructedItem constructed[3] = { { 0 } };
606 DWORD cItem = 7, cConstructed = 0;
608 if (info->IssuerUniqueId.cbData)
610 constructed[cConstructed].tag = 1;
611 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
612 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
613 items[cItem].pvStructInfo = &constructed[cConstructed];
614 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
615 cConstructed++;
616 cItem++;
618 if (info->SubjectUniqueId.cbData)
620 constructed[cConstructed].tag = 2;
621 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
622 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
623 items[cItem].pvStructInfo = &constructed[cConstructed];
624 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
625 cConstructed++;
626 cItem++;
628 if (info->cExtension)
630 constructed[cConstructed].tag = 3;
631 constructed[cConstructed].pvStructInfo = &info->cExtension;
632 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
633 items[cItem].pvStructInfo = &constructed[cConstructed];
634 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
635 cConstructed++;
636 cItem++;
639 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
640 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
642 __EXCEPT_PAGE_FAULT
644 SetLastError(STATUS_ACCESS_VIOLATION);
645 ret = FALSE;
647 __ENDTRY
648 return ret;
651 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
652 BYTE *pbEncoded, DWORD *pcbEncoded)
654 struct AsnEncodeSequenceItem items[3] = {
655 { &entry->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
656 { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
657 { 0 }
659 DWORD cItem = 2;
660 BOOL ret;
662 TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
664 if (entry->cExtension)
666 items[cItem].pvStructInfo = &entry->cExtension;
667 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
668 cItem++;
671 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
672 pbEncoded, pcbEncoded);
674 TRACE("returning %d (%08lx)\n", ret, GetLastError());
675 return ret;
678 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
679 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
680 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
682 DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
683 DWORD bytesNeeded, dataLen, lenBytes, i;
684 const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY **)
685 ((const BYTE *)pvStructInfo + sizeof(DWORD));
686 BOOL ret = TRUE;
688 for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
690 DWORD size;
692 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
693 if (ret)
694 dataLen += size;
696 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
697 bytesNeeded = 1 + lenBytes + dataLen;
698 if (!pbEncoded)
699 *pcbEncoded = bytesNeeded;
700 else
702 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
703 pcbEncoded, bytesNeeded)))
705 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
706 pbEncoded = *(BYTE **)pbEncoded;
707 *pbEncoded++ = ASN_SEQUENCEOF;
708 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
709 pbEncoded += lenBytes;
710 for (i = 0; i < cCRLEntry; i++)
712 DWORD size = dataLen;
714 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
715 pbEncoded += size;
716 dataLen -= size;
720 return ret;
723 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
724 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
725 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
727 const DWORD *ver = (const DWORD *)pvStructInfo;
728 BOOL ret;
730 /* CRL_V1 is not encoded */
731 if (*ver == CRL_V1)
733 *pcbEncoded = 0;
734 ret = TRUE;
736 else
737 ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
738 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
739 return ret;
742 /* Like in Windows, this blithely ignores the validity of the passed-in
743 * CRL_INFO, and just encodes it as-is. The resulting encoded data may not
744 * decode properly, see CRYPT_AsnDecodeCRLInfo.
746 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
747 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
748 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
750 BOOL ret;
752 __TRY
754 const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
755 struct AsnEncodeSequenceItem items[7] = {
756 { &info->dwVersion, CRYPT_AsnEncodeCRLVersion, 0 },
757 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
758 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
759 { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 },
760 { 0 }
762 DWORD cItem = 4;
764 if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
766 items[cItem].pvStructInfo = &info->NextUpdate;
767 items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
768 cItem++;
770 if (info->cCRLEntry)
772 items[cItem].pvStructInfo = &info->cCRLEntry;
773 items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
774 cItem++;
776 if (info->cExtension)
778 items[cItem].pvStructInfo = &info->cExtension;
779 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
780 cItem++;
783 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
784 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
786 __EXCEPT_PAGE_FAULT
788 SetLastError(STATUS_ACCESS_VIOLATION);
789 ret = FALSE;
791 __ENDTRY
792 return ret;
795 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
796 DWORD *pcbEncoded)
798 BOOL ret;
799 struct AsnEncodeSequenceItem items[3] = {
800 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
801 { NULL, NULL, 0 },
802 { NULL, NULL, 0 },
804 DWORD cItem = 1;
806 TRACE("%p, %p, %ld\n", ext, pbEncoded, *pcbEncoded);
808 if (ext->fCritical)
810 items[cItem].pvStructInfo = &ext->fCritical;
811 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
812 cItem++;
814 items[cItem].pvStructInfo = &ext->Value;
815 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
816 cItem++;
818 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
819 pbEncoded, pcbEncoded);
820 TRACE("returning %d (%08lx)\n", ret, GetLastError());
821 return ret;
824 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
825 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
826 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
828 BOOL ret;
830 __TRY
832 DWORD bytesNeeded, dataLen, lenBytes, i;
833 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
835 ret = TRUE;
836 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
838 DWORD size;
840 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
841 if (ret)
842 dataLen += size;
844 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
845 bytesNeeded = 1 + lenBytes + dataLen;
846 if (!pbEncoded)
847 *pcbEncoded = bytesNeeded;
848 else
850 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
851 pcbEncoded, bytesNeeded)))
853 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
854 pbEncoded = *(BYTE **)pbEncoded;
855 *pbEncoded++ = ASN_SEQUENCEOF;
856 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
857 pbEncoded += lenBytes;
858 for (i = 0; i < exts->cExtension; i++)
860 DWORD size = dataLen;
862 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
863 pbEncoded, &size);
864 pbEncoded += size;
865 dataLen -= size;
870 __EXCEPT_PAGE_FAULT
872 SetLastError(STATUS_ACCESS_VIOLATION);
873 ret = FALSE;
875 __ENDTRY
876 return ret;
879 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
880 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
881 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
883 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
884 DWORD bytesNeeded = 0, lenBytes;
885 BOOL ret = TRUE;
886 int firstPos = 0;
887 BYTE firstByte = 0;
889 TRACE("%s\n", debugstr_a(pszObjId));
891 if (pszObjId)
893 const char *ptr;
894 int val1, val2;
896 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
898 SetLastError(CRYPT_E_ASN1_ERROR);
899 return FALSE;
901 bytesNeeded++;
902 firstByte = val1 * 40 + val2;
903 ptr = pszObjId + firstPos;
904 while (ret && *ptr)
906 int pos;
908 /* note I assume each component is at most 32-bits long in base 2 */
909 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
911 if (val1 >= 0x10000000)
912 bytesNeeded += 5;
913 else if (val1 >= 0x200000)
914 bytesNeeded += 4;
915 else if (val1 >= 0x4000)
916 bytesNeeded += 3;
917 else if (val1 >= 0x80)
918 bytesNeeded += 2;
919 else
920 bytesNeeded += 1;
921 ptr += pos;
922 if (*ptr == '.')
923 ptr++;
925 else
927 SetLastError(CRYPT_E_ASN1_ERROR);
928 return FALSE;
931 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
933 else
934 lenBytes = 1;
935 bytesNeeded += 1 + lenBytes;
936 if (pbEncoded)
938 if (*pcbEncoded < bytesNeeded)
940 SetLastError(ERROR_MORE_DATA);
941 ret = FALSE;
943 else
945 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
946 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
947 pbEncoded += lenBytes;
948 if (pszObjId)
950 const char *ptr;
951 int val, pos;
953 *pbEncoded++ = firstByte;
954 ptr = pszObjId + firstPos;
955 while (ret && *ptr)
957 sscanf(ptr, "%d%n", &val, &pos);
959 unsigned char outBytes[5];
960 int numBytes, i;
962 if (val >= 0x10000000)
963 numBytes = 5;
964 else if (val >= 0x200000)
965 numBytes = 4;
966 else if (val >= 0x4000)
967 numBytes = 3;
968 else if (val >= 0x80)
969 numBytes = 2;
970 else
971 numBytes = 1;
972 for (i = numBytes; i > 0; i--)
974 outBytes[i - 1] = val & 0x7f;
975 val >>= 7;
977 for (i = 0; i < numBytes - 1; i++)
978 *pbEncoded++ = outBytes[i] | 0x80;
979 *pbEncoded++ = outBytes[i];
980 ptr += pos;
981 if (*ptr == '.')
982 ptr++;
988 *pcbEncoded = bytesNeeded;
989 return ret;
992 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
993 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
995 BYTE tag;
996 DWORD bytesNeeded, lenBytes, encodedLen;
997 BOOL ret = TRUE;
999 switch (value->dwValueType)
1001 case CERT_RDN_NUMERIC_STRING:
1002 tag = ASN_NUMERICSTRING;
1003 encodedLen = value->Value.cbData;
1004 break;
1005 case CERT_RDN_PRINTABLE_STRING:
1006 tag = ASN_PRINTABLESTRING;
1007 encodedLen = value->Value.cbData;
1008 break;
1009 case CERT_RDN_IA5_STRING:
1010 tag = ASN_IA5STRING;
1011 encodedLen = value->Value.cbData;
1012 break;
1013 case CERT_RDN_ANY_TYPE:
1014 /* explicitly disallowed */
1015 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1016 return FALSE;
1017 default:
1018 FIXME("String type %ld unimplemented\n", value->dwValueType);
1019 return FALSE;
1021 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1022 bytesNeeded = 1 + lenBytes + encodedLen;
1023 if (pbEncoded)
1025 if (*pcbEncoded < bytesNeeded)
1027 SetLastError(ERROR_MORE_DATA);
1028 ret = FALSE;
1030 else
1032 *pbEncoded++ = tag;
1033 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1034 pbEncoded += lenBytes;
1035 switch (value->dwValueType)
1037 case CERT_RDN_NUMERIC_STRING:
1038 case CERT_RDN_PRINTABLE_STRING:
1039 case CERT_RDN_IA5_STRING:
1040 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
1044 *pcbEncoded = bytesNeeded;
1045 return ret;
1048 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1049 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
1051 DWORD bytesNeeded = 0, lenBytes, size;
1052 BOOL ret;
1054 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1055 0, NULL, NULL, &size);
1056 if (ret)
1058 bytesNeeded += size;
1059 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1060 * with dwValueType, so "cast" it to get its encoded size
1062 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1063 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
1064 if (ret)
1066 bytesNeeded += size;
1067 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1068 bytesNeeded += 1 + lenBytes;
1069 if (pbEncoded)
1071 if (*pcbEncoded < bytesNeeded)
1073 SetLastError(ERROR_MORE_DATA);
1074 ret = FALSE;
1076 else
1078 *pbEncoded++ = ASN_SEQUENCE;
1079 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1080 &lenBytes);
1081 pbEncoded += lenBytes;
1082 size = bytesNeeded - 1 - lenBytes;
1083 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1084 attr->pszObjId, 0, NULL, pbEncoded, &size);
1085 if (ret)
1087 pbEncoded += size;
1088 size = bytesNeeded - 1 - lenBytes - size;
1089 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1090 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
1091 &size);
1095 *pcbEncoded = bytesNeeded;
1098 return ret;
1101 static int BLOBComp(const void *l, const void *r)
1103 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
1104 int ret;
1106 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1107 ret = a->cbData - b->cbData;
1108 return ret;
1111 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1113 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1114 BYTE *pbEncoded, DWORD *pcbEncoded)
1116 BOOL ret;
1117 CRYPT_DER_BLOB *blobs = NULL;
1119 __TRY
1121 DWORD bytesNeeded = 0, lenBytes, i;
1123 blobs = NULL;
1124 ret = TRUE;
1125 if (rdn->cRDNAttr)
1127 blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1128 if (!blobs)
1129 ret = FALSE;
1130 else
1131 memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1133 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1135 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1136 NULL, &blobs[i].cbData);
1137 if (ret)
1138 bytesNeeded += blobs[i].cbData;
1140 if (ret)
1142 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1143 bytesNeeded += 1 + lenBytes;
1144 if (pbEncoded)
1146 if (*pcbEncoded < bytesNeeded)
1148 SetLastError(ERROR_MORE_DATA);
1149 ret = FALSE;
1151 else
1153 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1155 blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
1156 if (!blobs[i].pbData)
1157 ret = FALSE;
1158 else
1159 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1160 &rdn->rgRDNAttr[i], blobs[i].pbData,
1161 &blobs[i].cbData);
1163 if (ret)
1165 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1166 BLOBComp);
1167 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1168 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1169 &lenBytes);
1170 pbEncoded += lenBytes;
1171 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1173 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1174 pbEncoded += blobs[i].cbData;
1179 *pcbEncoded = bytesNeeded;
1181 if (blobs)
1183 for (i = 0; i < rdn->cRDNAttr; i++)
1184 CryptMemFree(blobs[i].pbData);
1187 __EXCEPT_PAGE_FAULT
1189 SetLastError(STATUS_ACCESS_VIOLATION);
1190 ret = FALSE;
1192 __ENDTRY
1193 CryptMemFree(blobs);
1194 return ret;
1197 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1198 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1199 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1201 BOOL ret;
1203 __TRY
1205 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1206 DWORD bytesNeeded = 0, lenBytes, size, i;
1208 TRACE("encoding name with %ld RDNs\n", info->cRDN);
1209 ret = TRUE;
1210 for (i = 0; ret && i < info->cRDN; i++)
1212 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1213 &size);
1214 if (ret)
1215 bytesNeeded += size;
1217 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1218 bytesNeeded += 1 + lenBytes;
1219 if (ret)
1221 if (!pbEncoded)
1222 *pcbEncoded = bytesNeeded;
1223 else
1225 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1226 pbEncoded, pcbEncoded, bytesNeeded)))
1228 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1229 pbEncoded = *(BYTE **)pbEncoded;
1230 *pbEncoded++ = ASN_SEQUENCEOF;
1231 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1232 &lenBytes);
1233 pbEncoded += lenBytes;
1234 for (i = 0; ret && i < info->cRDN; i++)
1236 size = bytesNeeded;
1237 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1238 &info->rgRDN[i], pbEncoded, &size);
1239 if (ret)
1241 pbEncoded += size;
1242 bytesNeeded -= size;
1249 __EXCEPT_PAGE_FAULT
1251 SetLastError(STATUS_ACCESS_VIOLATION);
1252 ret = FALSE;
1254 __ENDTRY
1255 return ret;
1258 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1259 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1260 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1262 BOOL val = *(const BOOL *)pvStructInfo, ret;
1264 TRACE("%d\n", val);
1266 if (!pbEncoded)
1268 *pcbEncoded = 3;
1269 ret = TRUE;
1271 else if (*pcbEncoded < 3)
1273 *pcbEncoded = 3;
1274 SetLastError(ERROR_MORE_DATA);
1275 ret = FALSE;
1277 else
1279 *pcbEncoded = 3;
1280 *pbEncoded++ = ASN_BOOL;
1281 *pbEncoded++ = 1;
1282 *pbEncoded++ = val ? 0xff : 0;
1283 ret = TRUE;
1285 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1286 return ret;
1289 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1290 BYTE *pbEncoded, DWORD *pcbEncoded)
1292 BOOL ret;
1293 DWORD dataLen;
1295 ret = TRUE;
1296 switch (entry->dwAltNameChoice)
1298 case CERT_ALT_NAME_RFC822_NAME:
1299 case CERT_ALT_NAME_DNS_NAME:
1300 case CERT_ALT_NAME_URL:
1301 if (entry->u.pwszURL)
1303 DWORD i;
1305 /* Not + 1: don't encode the NULL-terminator */
1306 dataLen = lstrlenW(entry->u.pwszURL);
1307 for (i = 0; ret && i < dataLen; i++)
1309 if (entry->u.pwszURL[i] > 0x7f)
1311 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1312 ret = FALSE;
1313 *pcbEncoded = i;
1317 else
1318 dataLen = 0;
1319 break;
1320 case CERT_ALT_NAME_IP_ADDRESS:
1321 dataLen = entry->u.IPAddress.cbData;
1322 break;
1323 case CERT_ALT_NAME_REGISTERED_ID:
1324 /* FIXME: encode OID */
1325 case CERT_ALT_NAME_OTHER_NAME:
1326 case CERT_ALT_NAME_DIRECTORY_NAME:
1327 FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice);
1328 return FALSE;
1329 default:
1330 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1331 return FALSE;
1333 if (ret)
1335 DWORD bytesNeeded, lenBytes;
1337 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1338 bytesNeeded = 1 + dataLen + lenBytes;
1339 if (!pbEncoded)
1340 *pcbEncoded = bytesNeeded;
1341 else if (*pcbEncoded < bytesNeeded)
1343 SetLastError(ERROR_MORE_DATA);
1344 *pcbEncoded = bytesNeeded;
1345 ret = FALSE;
1347 else
1349 *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1350 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1351 pbEncoded += lenBytes;
1352 switch (entry->dwAltNameChoice)
1354 case CERT_ALT_NAME_RFC822_NAME:
1355 case CERT_ALT_NAME_DNS_NAME:
1356 case CERT_ALT_NAME_URL:
1358 DWORD i;
1360 for (i = 0; i < dataLen; i++)
1361 *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1362 break;
1364 case CERT_ALT_NAME_IP_ADDRESS:
1365 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1366 break;
1368 if (ret)
1369 *pcbEncoded = bytesNeeded;
1372 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1373 return ret;
1376 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1377 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1378 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1380 BOOL ret;
1382 __TRY
1384 const CERT_ALT_NAME_INFO *info =
1385 (const CERT_ALT_NAME_INFO *)pvStructInfo;
1386 DWORD bytesNeeded, dataLen, lenBytes, i;
1388 ret = TRUE;
1389 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1390 * can't encode an erroneous entry index if it's bigger than this.
1392 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1394 DWORD len;
1396 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1397 &len);
1398 if (ret)
1399 dataLen += len;
1400 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1402 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1403 * the bad character, now set the index of the bad
1404 * entry
1406 *pcbEncoded = (BYTE)i <<
1407 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1410 if (ret)
1412 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1413 bytesNeeded = 1 + lenBytes + dataLen;
1414 if (!pbEncoded)
1416 *pcbEncoded = bytesNeeded;
1417 ret = TRUE;
1419 else
1421 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1422 pbEncoded, pcbEncoded, bytesNeeded)))
1424 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1425 pbEncoded = *(BYTE **)pbEncoded;
1426 *pbEncoded++ = ASN_SEQUENCEOF;
1427 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1428 pbEncoded += lenBytes;
1429 for (i = 0; ret && i < info->cAltEntry; i++)
1431 DWORD len = dataLen;
1433 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1434 pbEncoded, &len);
1435 if (ret)
1437 pbEncoded += len;
1438 dataLen -= len;
1445 __EXCEPT_PAGE_FAULT
1447 SetLastError(STATUS_ACCESS_VIOLATION);
1448 ret = FALSE;
1450 __ENDTRY
1451 return ret;
1454 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
1455 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1456 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1458 BOOL ret;
1460 __TRY
1462 const CERT_BASIC_CONSTRAINTS_INFO *info =
1463 (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
1464 struct AsnEncodeSequenceItem items[3] = {
1465 { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
1466 { 0 }
1468 DWORD cItem = 1;
1470 if (info->fPathLenConstraint)
1472 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1473 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1474 cItem++;
1476 if (info->cSubtreesConstraint)
1478 items[cItem].pvStructInfo = &info->cSubtreesConstraint;
1479 items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
1480 cItem++;
1482 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1483 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1485 __EXCEPT_PAGE_FAULT
1487 SetLastError(STATUS_ACCESS_VIOLATION);
1488 ret = FALSE;
1490 __ENDTRY
1491 return ret;
1494 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1495 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1496 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1498 BOOL ret;
1500 __TRY
1502 const CERT_BASIC_CONSTRAINTS2_INFO *info =
1503 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1504 struct AsnEncodeSequenceItem items[2] = { { 0 } };
1505 DWORD cItem = 0;
1507 if (info->fCA)
1509 items[cItem].pvStructInfo = &info->fCA;
1510 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1511 cItem++;
1513 if (info->fPathLenConstraint)
1515 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1516 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1517 cItem++;
1519 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1520 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1522 __EXCEPT_PAGE_FAULT
1524 SetLastError(STATUS_ACCESS_VIOLATION);
1525 ret = FALSE;
1527 __ENDTRY
1528 return ret;
1531 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
1532 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1533 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1535 BOOL ret;
1537 __TRY
1539 const BLOBHEADER *hdr =
1540 (const BLOBHEADER *)pvStructInfo;
1542 if (hdr->bType != PUBLICKEYBLOB)
1544 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
1545 ret = FALSE;
1547 else
1549 const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
1550 ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
1551 CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
1552 (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
1553 struct AsnEncodeSequenceItem items[] = {
1554 { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
1555 { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
1558 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1559 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1560 pcbEncoded);
1563 __EXCEPT_PAGE_FAULT
1565 SetLastError(STATUS_ACCESS_VIOLATION);
1566 ret = FALSE;
1568 __ENDTRY
1569 return ret;
1572 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1573 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1574 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1576 BOOL ret;
1578 __TRY
1580 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1581 DWORD bytesNeeded, lenBytes;
1583 TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1584 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1586 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1587 bytesNeeded = 1 + lenBytes + blob->cbData;
1588 if (!pbEncoded)
1590 *pcbEncoded = bytesNeeded;
1591 ret = TRUE;
1593 else
1595 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1596 pcbEncoded, bytesNeeded)))
1598 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1599 pbEncoded = *(BYTE **)pbEncoded;
1600 *pbEncoded++ = ASN_OCTETSTRING;
1601 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1602 pbEncoded += lenBytes;
1603 if (blob->cbData)
1604 memcpy(pbEncoded, blob->pbData, blob->cbData);
1608 __EXCEPT_PAGE_FAULT
1610 SetLastError(STATUS_ACCESS_VIOLATION);
1611 ret = FALSE;
1613 __ENDTRY
1614 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1615 return ret;
1618 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1619 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1620 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1622 BOOL ret;
1624 __TRY
1626 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1627 DWORD bytesNeeded, lenBytes, dataBytes;
1628 BYTE unusedBits;
1630 /* yep, MS allows cUnusedBits to be >= 8 */
1631 if (!blob->cUnusedBits)
1633 dataBytes = blob->cbData;
1634 unusedBits = 0;
1636 else if (blob->cbData * 8 > blob->cUnusedBits)
1638 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1639 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1640 blob->cUnusedBits;
1642 else
1644 dataBytes = 0;
1645 unusedBits = 0;
1647 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1648 bytesNeeded = 1 + lenBytes + dataBytes + 1;
1649 if (!pbEncoded)
1651 *pcbEncoded = bytesNeeded;
1652 ret = TRUE;
1654 else
1656 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1657 pcbEncoded, bytesNeeded)))
1659 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1660 pbEncoded = *(BYTE **)pbEncoded;
1661 *pbEncoded++ = ASN_BITSTRING;
1662 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1663 pbEncoded += lenBytes;
1664 *pbEncoded++ = unusedBits;
1665 if (dataBytes)
1667 BYTE mask = 0xff << unusedBits;
1669 if (dataBytes > 1)
1671 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1672 pbEncoded += dataBytes - 1;
1674 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1679 __EXCEPT_PAGE_FAULT
1681 SetLastError(STATUS_ACCESS_VIOLATION);
1682 ret = FALSE;
1684 __ENDTRY
1685 return ret;
1688 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
1689 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1690 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1692 BOOL ret;
1694 __TRY
1696 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1697 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
1699 ret = TRUE;
1700 if (newBlob.cbData)
1702 newBlob.pbData = CryptMemAlloc(newBlob.cbData);
1703 if (newBlob.pbData)
1705 DWORD i;
1707 for (i = 0; i < newBlob.cbData; i++)
1708 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
1710 else
1711 ret = FALSE;
1713 if (ret)
1714 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
1715 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1716 CryptMemFree(newBlob.pbData);
1718 __EXCEPT_PAGE_FAULT
1720 SetLastError(STATUS_ACCESS_VIOLATION);
1721 ret = FALSE;
1723 __ENDTRY
1724 return ret;
1727 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1728 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1729 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1731 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1733 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1734 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1737 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1738 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1739 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1741 BOOL ret;
1743 __TRY
1745 DWORD significantBytes, lenBytes;
1746 BYTE padByte = 0, bytesNeeded;
1747 BOOL pad = FALSE;
1748 const CRYPT_INTEGER_BLOB *blob =
1749 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1751 significantBytes = blob->cbData;
1752 if (significantBytes)
1754 if (blob->pbData[significantBytes - 1] & 0x80)
1756 /* negative, lop off leading (little-endian) 0xffs */
1757 for (; significantBytes > 0 &&
1758 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1760 if (blob->pbData[significantBytes - 1] < 0x80)
1762 padByte = 0xff;
1763 pad = TRUE;
1766 else
1768 /* positive, lop off leading (little-endian) zeroes */
1769 for (; significantBytes > 0 &&
1770 !blob->pbData[significantBytes - 1]; significantBytes--)
1772 if (significantBytes == 0)
1773 significantBytes = 1;
1774 if (blob->pbData[significantBytes - 1] > 0x7f)
1776 padByte = 0;
1777 pad = TRUE;
1781 if (pad)
1782 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1783 else
1784 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1785 bytesNeeded = 1 + lenBytes + significantBytes;
1786 if (pad)
1787 bytesNeeded++;
1788 if (!pbEncoded)
1790 *pcbEncoded = bytesNeeded;
1791 ret = TRUE;
1793 else
1795 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1796 pcbEncoded, bytesNeeded)))
1798 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1799 pbEncoded = *(BYTE **)pbEncoded;
1800 *pbEncoded++ = ASN_INTEGER;
1801 if (pad)
1803 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1804 pbEncoded += lenBytes;
1805 *pbEncoded++ = padByte;
1807 else
1809 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1810 pbEncoded += lenBytes;
1812 for (; significantBytes > 0; significantBytes--)
1813 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1817 __EXCEPT_PAGE_FAULT
1819 SetLastError(STATUS_ACCESS_VIOLATION);
1820 ret = FALSE;
1822 __ENDTRY
1823 return ret;
1826 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1827 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1828 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1830 BOOL ret;
1832 __TRY
1834 DWORD significantBytes, lenBytes;
1835 BYTE bytesNeeded;
1836 BOOL pad = FALSE;
1837 const CRYPT_INTEGER_BLOB *blob =
1838 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1840 significantBytes = blob->cbData;
1841 if (significantBytes)
1843 /* positive, lop off leading (little-endian) zeroes */
1844 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1845 significantBytes--)
1847 if (significantBytes == 0)
1848 significantBytes = 1;
1849 if (blob->pbData[significantBytes - 1] > 0x7f)
1850 pad = TRUE;
1852 if (pad)
1853 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1854 else
1855 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1856 bytesNeeded = 1 + lenBytes + significantBytes;
1857 if (pad)
1858 bytesNeeded++;
1859 if (!pbEncoded)
1861 *pcbEncoded = bytesNeeded;
1862 ret = TRUE;
1864 else
1866 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1867 pcbEncoded, bytesNeeded)))
1869 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1870 pbEncoded = *(BYTE **)pbEncoded;
1871 *pbEncoded++ = ASN_INTEGER;
1872 if (pad)
1874 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1875 pbEncoded += lenBytes;
1876 *pbEncoded++ = 0;
1878 else
1880 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1881 pbEncoded += lenBytes;
1883 for (; significantBytes > 0; significantBytes--)
1884 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1888 __EXCEPT_PAGE_FAULT
1890 SetLastError(STATUS_ACCESS_VIOLATION);
1891 ret = FALSE;
1893 __ENDTRY
1894 return ret;
1897 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
1898 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1899 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1901 CRYPT_INTEGER_BLOB blob;
1902 BOOL ret;
1904 /* Encode as an unsigned integer, then change the tag to enumerated */
1905 blob.cbData = sizeof(DWORD);
1906 blob.pbData = (BYTE *)pvStructInfo;
1907 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
1908 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1909 if (ret && pbEncoded)
1911 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1912 pbEncoded = *(BYTE **)pbEncoded;
1913 pbEncoded[0] = ASN_ENUMERATED;
1915 return ret;
1918 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
1919 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1920 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1922 BOOL ret;
1924 __TRY
1926 SYSTEMTIME sysTime;
1927 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
1928 * temporary buffer because the output buffer is not NULL-terminated.
1930 char buf[16];
1931 static const DWORD bytesNeeded = sizeof(buf) - 1;
1933 if (!pbEncoded)
1935 *pcbEncoded = bytesNeeded;
1936 ret = TRUE;
1938 else
1940 /* Sanity check the year, this is a two-digit year format */
1941 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1942 &sysTime);
1943 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
1945 SetLastError(CRYPT_E_BAD_ENCODE);
1946 ret = FALSE;
1948 if (ret)
1950 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1951 pbEncoded, pcbEncoded, bytesNeeded)))
1953 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1954 pbEncoded = *(BYTE **)pbEncoded;
1955 buf[0] = ASN_UTCTIME;
1956 buf[1] = bytesNeeded - 2;
1957 snprintf(buf + 2, sizeof(buf) - 2,
1958 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
1959 sysTime.wYear - 2000 : sysTime.wYear - 1900,
1960 sysTime.wDay, sysTime.wMonth, sysTime.wHour,
1961 sysTime.wMinute, sysTime.wSecond);
1962 memcpy(pbEncoded, buf, bytesNeeded);
1967 __EXCEPT_PAGE_FAULT
1969 SetLastError(STATUS_ACCESS_VIOLATION);
1970 ret = FALSE;
1972 __ENDTRY
1973 return ret;
1976 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
1977 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1978 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1980 BOOL ret;
1982 __TRY
1984 SYSTEMTIME sysTime;
1985 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
1986 * temporary buffer because the output buffer is not NULL-terminated.
1988 char buf[18];
1989 static const DWORD bytesNeeded = sizeof(buf) - 1;
1991 if (!pbEncoded)
1993 *pcbEncoded = bytesNeeded;
1994 ret = TRUE;
1996 else
1998 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1999 &sysTime);
2000 if (ret)
2001 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2002 pcbEncoded, bytesNeeded);
2003 if (ret)
2005 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2006 pbEncoded = *(BYTE **)pbEncoded;
2007 buf[0] = ASN_GENERALTIME;
2008 buf[1] = bytesNeeded - 2;
2009 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2010 sysTime.wYear, sysTime.wDay, sysTime.wMonth, sysTime.wHour,
2011 sysTime.wMinute, sysTime.wSecond);
2012 memcpy(pbEncoded, buf, bytesNeeded);
2016 __EXCEPT_PAGE_FAULT
2018 SetLastError(STATUS_ACCESS_VIOLATION);
2019 ret = FALSE;
2021 __ENDTRY
2022 return ret;
2025 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2026 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2027 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2029 BOOL ret;
2031 __TRY
2033 SYSTEMTIME sysTime;
2035 /* Check the year, if it's in the UTCTime range call that encode func */
2036 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2037 return FALSE;
2038 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2039 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2040 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2041 else
2042 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2043 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2044 pcbEncoded);
2046 __EXCEPT_PAGE_FAULT
2048 SetLastError(STATUS_ACCESS_VIOLATION);
2049 ret = FALSE;
2051 __ENDTRY
2052 return ret;
2055 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2056 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2057 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2059 BOOL ret;
2061 __TRY
2063 DWORD bytesNeeded, dataLen, lenBytes, i;
2064 const CRYPT_SEQUENCE_OF_ANY *seq =
2065 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2067 for (i = 0, dataLen = 0; i < seq->cValue; i++)
2068 dataLen += seq->rgValue[i].cbData;
2069 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2070 bytesNeeded = 1 + lenBytes + dataLen;
2071 if (!pbEncoded)
2073 *pcbEncoded = bytesNeeded;
2074 ret = TRUE;
2076 else
2078 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2079 pcbEncoded, bytesNeeded)))
2081 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2082 pbEncoded = *(BYTE **)pbEncoded;
2083 *pbEncoded++ = ASN_SEQUENCEOF;
2084 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2085 pbEncoded += lenBytes;
2086 for (i = 0; i < seq->cValue; i++)
2088 memcpy(pbEncoded, seq->rgValue[i].pbData,
2089 seq->rgValue[i].cbData);
2090 pbEncoded += seq->rgValue[i].cbData;
2095 __EXCEPT_PAGE_FAULT
2097 SetLastError(STATUS_ACCESS_VIOLATION);
2098 ret = FALSE;
2100 __ENDTRY
2101 return ret;
2104 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2105 BYTE *pbEncoded, DWORD *pcbEncoded)
2107 BOOL ret = TRUE;
2108 struct AsnEncodeSequenceItem items[3] = { { 0 } };
2109 struct AsnConstructedItem constructed = { 0 };
2110 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2111 DWORD cItem = 0, cSwapped = 0;
2113 switch (distPoint->DistPointName.dwDistPointNameChoice)
2115 case CRL_DIST_POINT_NO_NAME:
2116 /* do nothing */
2117 break;
2118 case CRL_DIST_POINT_FULL_NAME:
2119 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2120 swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2121 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2122 constructed.tag = 0;
2123 constructed.pvStructInfo = &swapped[cSwapped];
2124 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2125 items[cItem].pvStructInfo = &constructed;
2126 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2127 cSwapped++;
2128 cItem++;
2129 break;
2130 case CRL_DIST_POINT_ISSUER_RDN_NAME:
2131 FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2132 ret = FALSE;
2133 break;
2134 default:
2135 ret = FALSE;
2137 if (ret && distPoint->ReasonFlags.cbData)
2139 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2140 swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2141 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2142 items[cItem].pvStructInfo = &swapped[cSwapped];
2143 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2144 cSwapped++;
2145 cItem++;
2147 if (ret && distPoint->CRLIssuer.cAltEntry)
2149 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2150 swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2151 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2152 items[cItem].pvStructInfo = &swapped[cSwapped];
2153 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2154 cSwapped++;
2155 cItem++;
2157 if (ret)
2158 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2159 pbEncoded, pcbEncoded);
2160 return ret;
2163 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2164 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2165 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2167 BOOL ret;
2169 __TRY
2171 const CRL_DIST_POINTS_INFO *info =
2172 (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2174 if (!info->cDistPoint)
2176 SetLastError(HRESULT_FROM_WIN32(ERROR_INVALID_PARAMETER));
2177 ret = FALSE;
2179 else
2181 DWORD bytesNeeded, dataLen, lenBytes, i;
2183 ret = TRUE;
2184 for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2186 DWORD len;
2188 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2189 &len);
2190 if (ret)
2191 dataLen += len;
2192 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2194 /* Have to propagate index of failing character */
2195 *pcbEncoded = len;
2198 if (ret)
2200 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2201 bytesNeeded = 1 + lenBytes + dataLen;
2202 if (!pbEncoded)
2204 *pcbEncoded = bytesNeeded;
2205 ret = TRUE;
2207 else
2209 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2210 pbEncoded, pcbEncoded, bytesNeeded)))
2212 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2213 pbEncoded = *(BYTE **)pbEncoded;
2214 *pbEncoded++ = ASN_SEQUENCEOF;
2215 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2216 pbEncoded += lenBytes;
2217 for (i = 0; ret && i < info->cDistPoint; i++)
2219 DWORD len = dataLen;
2221 ret = CRYPT_AsnEncodeDistPoint(
2222 &info->rgDistPoint[i], pbEncoded, &len);
2223 if (ret)
2225 pbEncoded += len;
2226 dataLen -= len;
2234 __EXCEPT_PAGE_FAULT
2236 SetLastError(STATUS_ACCESS_VIOLATION);
2237 ret = FALSE;
2239 __ENDTRY
2240 return ret;
2243 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
2244 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2245 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2247 BOOL ret;
2249 __TRY
2251 const CERT_ENHKEY_USAGE *usage =
2252 (const CERT_ENHKEY_USAGE *)pvStructInfo;
2253 DWORD bytesNeeded = 0, lenBytes, size, i;
2255 ret = TRUE;
2256 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2258 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2259 usage->rgpszUsageIdentifier[i],
2260 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
2261 if (ret)
2262 bytesNeeded += size;
2264 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2265 bytesNeeded += 1 + lenBytes;
2266 if (ret)
2268 if (!pbEncoded)
2269 *pcbEncoded = bytesNeeded;
2270 else
2272 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2273 pbEncoded, pcbEncoded, bytesNeeded)))
2275 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2276 pbEncoded = *(BYTE **)pbEncoded;
2277 *pbEncoded++ = ASN_SEQUENCEOF;
2278 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2279 &lenBytes);
2280 pbEncoded += lenBytes;
2281 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2283 size = bytesNeeded;
2284 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2285 usage->rgpszUsageIdentifier[i],
2286 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
2287 &size);
2288 if (ret)
2290 pbEncoded += size;
2291 bytesNeeded -= size;
2298 __EXCEPT_PAGE_FAULT
2300 SetLastError(STATUS_ACCESS_VIOLATION);
2301 ret = FALSE;
2303 __ENDTRY
2304 return ret;
2307 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2308 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2309 void *pvEncoded, DWORD *pcbEncoded)
2311 static HCRYPTOIDFUNCSET set = NULL;
2312 BOOL ret = FALSE;
2313 CryptEncodeObjectExFunc encodeFunc = NULL;
2314 HCRYPTOIDFUNCADDR hFunc = NULL;
2316 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2317 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2318 pvEncoded, pcbEncoded);
2320 if (!pvEncoded && !pcbEncoded)
2322 SetLastError(ERROR_INVALID_PARAMETER);
2323 return FALSE;
2325 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2326 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2328 SetLastError(ERROR_FILE_NOT_FOUND);
2329 return FALSE;
2332 SetLastError(NOERROR);
2333 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2334 *(BYTE **)pvEncoded = NULL;
2335 if (!HIWORD(lpszStructType))
2337 switch (LOWORD(lpszStructType))
2339 case (WORD)X509_CERT:
2340 encodeFunc = CRYPT_AsnEncodeCert;
2341 break;
2342 case (WORD)X509_CERT_TO_BE_SIGNED:
2343 encodeFunc = CRYPT_AsnEncodeCertInfo;
2344 break;
2345 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2346 encodeFunc = CRYPT_AsnEncodeCRLInfo;
2347 break;
2348 case (WORD)X509_EXTENSIONS:
2349 encodeFunc = CRYPT_AsnEncodeExtensions;
2350 break;
2351 case (WORD)X509_NAME:
2352 encodeFunc = CRYPT_AsnEncodeName;
2353 break;
2354 case (WORD)X509_PUBLIC_KEY_INFO:
2355 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2356 break;
2357 case (WORD)X509_ALTERNATE_NAME:
2358 encodeFunc = CRYPT_AsnEncodeAltName;
2359 break;
2360 case (WORD)X509_BASIC_CONSTRAINTS:
2361 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2362 break;
2363 case (WORD)X509_BASIC_CONSTRAINTS2:
2364 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2365 break;
2366 case (WORD)RSA_CSP_PUBLICKEYBLOB:
2367 encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2368 break;
2369 case (WORD)X509_OCTET_STRING:
2370 encodeFunc = CRYPT_AsnEncodeOctets;
2371 break;
2372 case (WORD)X509_BITS:
2373 case (WORD)X509_KEY_USAGE:
2374 encodeFunc = CRYPT_AsnEncodeBits;
2375 break;
2376 case (WORD)X509_INTEGER:
2377 encodeFunc = CRYPT_AsnEncodeInt;
2378 break;
2379 case (WORD)X509_MULTI_BYTE_INTEGER:
2380 encodeFunc = CRYPT_AsnEncodeInteger;
2381 break;
2382 case (WORD)X509_MULTI_BYTE_UINT:
2383 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2384 break;
2385 case (WORD)X509_ENUMERATED:
2386 encodeFunc = CRYPT_AsnEncodeEnumerated;
2387 break;
2388 case (WORD)X509_CHOICE_OF_TIME:
2389 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2390 break;
2391 case (WORD)X509_SEQUENCE_OF_ANY:
2392 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2393 break;
2394 case (WORD)PKCS_UTC_TIME:
2395 encodeFunc = CRYPT_AsnEncodeUtcTime;
2396 break;
2397 case (WORD)X509_CRL_DIST_POINTS:
2398 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2399 break;
2400 case (WORD)X509_ENHANCED_KEY_USAGE:
2401 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2402 break;
2403 default:
2404 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2407 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2408 encodeFunc = CRYPT_AsnEncodeExtensions;
2409 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2410 encodeFunc = CRYPT_AsnEncodeUtcTime;
2411 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2412 encodeFunc = CRYPT_AsnEncodeEnumerated;
2413 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2414 encodeFunc = CRYPT_AsnEncodeBits;
2415 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2416 encodeFunc = CRYPT_AsnEncodeOctets;
2417 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
2418 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2419 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2420 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2421 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2422 encodeFunc = CRYPT_AsnEncodeAltName;
2423 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2424 encodeFunc = CRYPT_AsnEncodeAltName;
2425 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2426 encodeFunc = CRYPT_AsnEncodeAltName;
2427 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2428 encodeFunc = CRYPT_AsnEncodeAltName;
2429 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2430 encodeFunc = CRYPT_AsnEncodeAltName;
2431 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2432 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2433 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2434 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2435 else
2436 TRACE("OID %s not found or unimplemented, looking for DLL\n",
2437 debugstr_a(lpszStructType));
2438 if (!encodeFunc)
2440 if (!set)
2441 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
2442 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2443 (void **)&encodeFunc, &hFunc);
2445 if (encodeFunc)
2446 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2447 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2448 else
2449 SetLastError(ERROR_FILE_NOT_FOUND);
2450 if (hFunc)
2451 CryptFreeOIDFunctionAddress(hFunc, 0);
2452 return ret;
2455 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2456 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
2457 DWORD *pcbStructInfo)
2459 static HCRYPTOIDFUNCSET set = NULL;
2460 BOOL ret = FALSE;
2461 CryptDecodeObjectFunc pCryptDecodeObject;
2462 HCRYPTOIDFUNCADDR hFunc;
2464 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType,
2465 debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
2466 pvStructInfo, pcbStructInfo);
2468 if (!pvStructInfo && !pcbStructInfo)
2470 SetLastError(ERROR_INVALID_PARAMETER);
2471 return FALSE;
2474 /* Try registered DLL first.. */
2475 if (!set)
2476 set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_FUNC, 0);
2477 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2478 (void **)&pCryptDecodeObject, &hFunc);
2479 if (pCryptDecodeObject)
2481 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
2482 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
2483 CryptFreeOIDFunctionAddress(hFunc, 0);
2485 else
2487 /* If not, use CryptDecodeObjectEx */
2488 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
2489 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
2491 return ret;
2494 /* Gets the number of length bytes from the given (leading) length byte */
2495 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
2497 /* Helper function to get the encoded length of the data starting at pbEncoded,
2498 * where pbEncoded[0] is the tag. If the data are too short to contain a
2499 * length or if the length is too large for cbEncoded, sets an appropriate
2500 * error code and returns FALSE.
2502 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
2503 DWORD *len)
2505 BOOL ret;
2507 if (cbEncoded <= 1)
2509 SetLastError(CRYPT_E_ASN1_CORRUPT);
2510 ret = FALSE;
2512 else if (pbEncoded[1] <= 0x7f)
2514 if (pbEncoded[1] + 1 > cbEncoded)
2516 SetLastError(CRYPT_E_ASN1_EOD);
2517 ret = FALSE;
2519 else
2521 *len = pbEncoded[1];
2522 ret = TRUE;
2525 else
2527 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
2529 if (lenLen > sizeof(DWORD) + 1)
2531 SetLastError(CRYPT_E_ASN1_LARGE);
2532 ret = FALSE;
2534 else if (lenLen + 2 > cbEncoded)
2536 SetLastError(CRYPT_E_ASN1_CORRUPT);
2537 ret = FALSE;
2539 else
2541 DWORD out = 0;
2543 pbEncoded += 2;
2544 while (--lenLen)
2546 out <<= 8;
2547 out |= *pbEncoded++;
2549 if (out + lenLen + 1 > cbEncoded)
2551 SetLastError(CRYPT_E_ASN1_EOD);
2552 ret = FALSE;
2554 else
2556 *len = out;
2557 ret = TRUE;
2561 return ret;
2564 /* Helper function to check *pcbStructInfo, set it to the required size, and
2565 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
2566 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
2567 * pointer to the newly allocated memory.
2569 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
2570 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2571 DWORD bytesNeeded)
2573 BOOL ret = TRUE;
2575 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2577 if (pDecodePara && pDecodePara->pfnAlloc)
2578 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
2579 else
2580 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
2581 if (!*(BYTE **)pvStructInfo)
2582 ret = FALSE;
2583 else
2584 *pcbStructInfo = bytesNeeded;
2586 else if (*pcbStructInfo < bytesNeeded)
2588 *pcbStructInfo = bytesNeeded;
2589 SetLastError(ERROR_MORE_DATA);
2590 ret = FALSE;
2592 return ret;
2595 /* tag:
2596 * The expected tag of the item. If tag is 0, decodeFunc is called
2597 * regardless of the tag value seen.
2598 * offset:
2599 * A sequence is decoded into a struct. The offset member is the
2600 * offset of this item within that struct.
2601 * decodeFunc:
2602 * The decoder function to use. If this is NULL, then the member isn't
2603 * decoded, but minSize space is reserved for it.
2604 * minSize:
2605 * The minimum amount of space occupied after decoding. You must set this.
2606 * optional:
2607 * If true, and the tag doesn't match the expected tag for this item,
2608 * or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
2609 * filled with 0 for this member.
2610 * hasPointer, pointerOffset, minSize:
2611 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
2612 * the offset within the (outer) struct of the data pointer (or to the
2613 * first data pointer, if more than one exist).
2614 * size:
2615 * Used by CRYPT_AsnDecodeSequence, not for your use.
2617 struct AsnDecodeSequenceItem
2619 BYTE tag;
2620 DWORD offset;
2621 CryptDecodeObjectExFunc decodeFunc;
2622 DWORD minSize;
2623 BOOL optional;
2624 BOOL hasPointer;
2625 DWORD pointerOffset;
2626 DWORD size;
2629 static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
2630 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2631 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData)
2633 BOOL ret;
2634 DWORD i;
2635 const BYTE *ptr;
2637 ptr = pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]);
2638 for (i = 0, ret = TRUE; ret && i < cItem; i++)
2640 if (cbEncoded - (ptr - pbEncoded) != 0)
2642 DWORD nextItemLen;
2644 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2645 &nextItemLen)))
2647 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2649 if (ptr[0] == items[i].tag || !items[i].tag)
2651 if (nextData && pvStructInfo && items[i].hasPointer)
2653 TRACE("Setting next pointer to %p\n",
2654 nextData);
2655 *(BYTE **)((BYTE *)pvStructInfo +
2656 items[i].pointerOffset) = nextData;
2658 if (items[i].decodeFunc)
2660 if (pvStructInfo)
2661 TRACE("decoding item %ld\n", i);
2662 else
2663 TRACE("sizing item %ld\n", i);
2664 ret = items[i].decodeFunc(dwCertEncodingType,
2665 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
2666 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2667 pvStructInfo ? (BYTE *)pvStructInfo + items[i].offset
2668 : NULL, &items[i].size);
2669 if (ret)
2671 if (nextData && items[i].hasPointer &&
2672 items[i].size > items[i].minSize)
2674 nextData += items[i].size - items[i].minSize;
2675 /* align nextData to DWORD boundaries */
2676 if (items[i].size % sizeof(DWORD))
2677 nextData += sizeof(DWORD) - items[i].size %
2678 sizeof(DWORD);
2680 /* Account for alignment padding */
2681 if (items[i].size % sizeof(DWORD))
2682 items[i].size += sizeof(DWORD) -
2683 items[i].size % sizeof(DWORD);
2684 ptr += 1 + nextItemLenBytes + nextItemLen;
2686 else if (items[i].optional &&
2687 GetLastError() == CRYPT_E_ASN1_BADTAG)
2689 TRACE("skipping optional item %ld\n", i);
2690 items[i].size = items[i].minSize;
2691 SetLastError(NOERROR);
2692 ret = TRUE;
2694 else
2695 TRACE("item %ld failed: %08lx\n", i,
2696 GetLastError());
2698 else
2699 items[i].size = items[i].minSize;
2701 else if (items[i].optional)
2703 TRACE("skipping optional item %ld\n", i);
2704 items[i].size = items[i].minSize;
2706 else
2708 TRACE("tag %02x doesn't match expected %02x\n",
2709 ptr[0], items[i].tag);
2710 SetLastError(CRYPT_E_ASN1_BADTAG);
2711 ret = FALSE;
2715 else if (items[i].optional)
2717 TRACE("missing optional item %ld, skipping\n", i);
2718 items[i].size = items[i].minSize;
2720 else
2722 TRACE("not enough bytes for item %ld, failing\n", i);
2723 SetLastError(CRYPT_E_ASN1_CORRUPT);
2724 ret = FALSE;
2727 if (cbEncoded - (ptr - pbEncoded) != 0)
2729 TRACE("%ld remaining bytes, failing\n", cbEncoded -
2730 (ptr - pbEncoded));
2731 SetLastError(CRYPT_E_ASN1_CORRUPT);
2732 ret = FALSE;
2734 return ret;
2737 /* This decodes an arbitrary sequence into a contiguous block of memory
2738 * (basically, a struct.) Each element being decoded is described by a struct
2739 * AsnDecodeSequenceItem, see above.
2740 * startingPointer is an optional pointer to the first place where dynamic
2741 * data will be stored. If you know the starting offset, you may pass it
2742 * here. Otherwise, pass NULL, and one will be inferred from the items.
2743 * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
2744 * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
2746 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
2747 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2748 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
2749 void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer)
2751 BOOL ret;
2753 TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld, %p\n", items, cItem, pbEncoded,
2754 cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
2755 startingPointer);
2757 if (pbEncoded[0] == ASN_SEQUENCE)
2759 DWORD dataLen;
2761 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2763 DWORD i;
2765 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, pbEncoded,
2766 cbEncoded, dwFlags, NULL, NULL);
2767 if (ret)
2769 DWORD bytesNeeded = 0, structSize = 0;
2771 for (i = 0; i < cItem; i++)
2773 bytesNeeded += items[i].size;
2774 structSize += items[i].minSize;
2776 if (!pvStructInfo)
2777 *pcbStructInfo = bytesNeeded;
2778 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2779 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2781 BYTE *nextData;
2783 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2784 pvStructInfo = *(BYTE **)pvStructInfo;
2785 if (startingPointer)
2786 nextData = (BYTE *)startingPointer;
2787 else
2788 nextData = (BYTE *)pvStructInfo + structSize;
2789 memset(pvStructInfo, 0, structSize);
2790 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
2791 pbEncoded, cbEncoded, dwFlags, pvStructInfo, nextData);
2796 else
2798 SetLastError(CRYPT_E_ASN1_BADTAG);
2799 ret = FALSE;
2801 TRACE("returning %d (%08lx)\n", ret, GetLastError());
2802 return ret;
2805 /* tag:
2806 * The expected tag of the entire encoded array (usually a variant
2807 * of ASN_SETOF or ASN_SEQUENCEOF.)
2808 * decodeFunc:
2809 * used to decode each item in the array
2810 * itemSize:
2811 * is the minimum size of each decoded item
2812 * hasPointer:
2813 * indicates whether each item has a dynamic pointer
2814 * pointerOffset:
2815 * indicates the offset within itemSize at which the pointer exists
2817 struct AsnArrayDescriptor
2819 BYTE tag;
2820 CryptDecodeObjectExFunc decodeFunc;
2821 DWORD itemSize;
2822 BOOL hasPointer;
2823 DWORD pointerOffset;
2826 struct AsnArrayItemSize
2828 DWORD encodedLen;
2829 DWORD size;
2832 /* Decodes an array of like types into a struct GenericArray.
2833 * The layout and decoding of the array are described by a struct
2834 * AsnArrayDescriptor.
2836 static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc,
2837 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2838 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2839 void *startingPointer)
2841 BOOL ret = TRUE;
2843 TRACE("%p, %p, %ld, %08lx, %p, %p, %ld, %p\n", arrayDesc, pbEncoded,
2844 cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
2845 startingPointer);
2847 if (pbEncoded[0] == arrayDesc->tag)
2849 DWORD dataLen;
2851 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2853 DWORD bytesNeeded, cItems = 0;
2854 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2855 /* There can be arbitrarily many items, but there is often only one.
2857 struct AsnArrayItemSize itemSize = { 0 }, *itemSizes = &itemSize;
2859 bytesNeeded = sizeof(struct GenericArray);
2860 if (dataLen)
2862 const BYTE *ptr;
2864 for (ptr = pbEncoded + 1 + lenBytes; ret &&
2865 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2867 DWORD itemLenBytes, itemDataLen, size;
2869 itemLenBytes = GET_LEN_BYTES(ptr[1]);
2870 /* Each item decoded may not tolerate extraneous bytes, so
2871 * get the length of the next element and pass it directly.
2873 ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2874 &itemDataLen);
2875 if (ret)
2876 ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr,
2877 1 + itemLenBytes + itemDataLen,
2878 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
2879 &size);
2880 if (ret)
2882 DWORD nextLen;
2884 cItems++;
2885 if (itemSizes != &itemSize)
2886 itemSizes = CryptMemRealloc(itemSizes,
2887 cItems * sizeof(struct AsnArrayItemSize));
2888 else
2890 itemSizes =
2891 CryptMemAlloc(
2892 cItems * sizeof(struct AsnArrayItemSize));
2893 memcpy(itemSizes, &itemSize, sizeof(itemSize));
2895 if (itemSizes)
2897 itemSizes[cItems - 1].encodedLen = 1 + itemLenBytes
2898 + itemDataLen;
2899 itemSizes[cItems - 1].size = size;
2900 bytesNeeded += size;
2901 ret = CRYPT_GetLen(ptr,
2902 cbEncoded - (ptr - pbEncoded), &nextLen);
2903 if (ret)
2904 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2906 else
2907 ret = FALSE;
2911 if (ret)
2913 if (!pvStructInfo)
2914 *pcbStructInfo = bytesNeeded;
2915 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2916 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2918 DWORD i;
2919 BYTE *nextData;
2920 const BYTE *ptr;
2921 struct GenericArray *array;
2923 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2924 pvStructInfo = *(BYTE **)pvStructInfo;
2925 array = (struct GenericArray *)pvStructInfo;
2926 array->cItems = cItems;
2927 if (startingPointer)
2928 array->rgItems = startingPointer;
2929 else
2930 array->rgItems = (BYTE *)array +
2931 sizeof(struct GenericArray);
2932 nextData = (BYTE *)array->rgItems +
2933 array->cItems * arrayDesc->itemSize;
2934 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
2935 i < cItems && ptr - pbEncoded - 1 - lenBytes <
2936 dataLen; i++)
2938 if (arrayDesc->hasPointer)
2939 *(BYTE **)(array->rgItems + i * arrayDesc->itemSize
2940 + arrayDesc->pointerOffset) = nextData;
2941 ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr,
2942 itemSizes[i].encodedLen,
2943 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2944 array->rgItems + i * arrayDesc->itemSize,
2945 &itemSizes[i].size);
2946 if (ret)
2948 DWORD nextLen;
2950 nextData += itemSizes[i].size - arrayDesc->itemSize;
2951 ret = CRYPT_GetLen(ptr,
2952 cbEncoded - (ptr - pbEncoded), &nextLen);
2953 if (ret)
2954 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2959 if (itemSizes != &itemSize)
2960 CryptMemFree(itemSizes);
2963 else
2965 SetLastError(CRYPT_E_ASN1_BADTAG);
2966 ret = FALSE;
2968 return ret;
2971 /* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
2972 * pvStructInfo. The BLOB must be non-empty, otherwise the last error is set
2973 * to CRYPT_E_ASN1_CORRUPT.
2974 * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
2975 * set!
2977 static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
2978 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2979 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2981 BOOL ret;
2982 DWORD dataLen;
2984 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2986 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2987 DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
2989 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2990 bytesNeeded += 1 + lenBytes + dataLen;
2992 if (!pvStructInfo)
2993 *pcbStructInfo = bytesNeeded;
2994 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2995 pvStructInfo, pcbStructInfo, bytesNeeded)))
2997 CRYPT_DER_BLOB *blob;
2999 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3000 pvStructInfo = *(BYTE **)pvStructInfo;
3001 blob = (CRYPT_DER_BLOB *)pvStructInfo;
3002 blob->cbData = 1 + lenBytes + dataLen;
3003 if (blob->cbData)
3005 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3006 blob->pbData = (BYTE *)pbEncoded;
3007 else
3009 assert(blob->pbData);
3010 memcpy(blob->pbData, pbEncoded, blob->cbData);
3013 else
3015 SetLastError(CRYPT_E_ASN1_CORRUPT);
3016 ret = FALSE;
3020 return ret;
3023 /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */
3024 static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType,
3025 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3026 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3028 BOOL ret;
3030 TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
3031 pDecodePara, pvStructInfo, *pcbStructInfo);
3033 /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in-
3034 * place.
3036 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType,
3037 pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pDecodePara,
3038 pvStructInfo, pcbStructInfo);
3039 if (ret && pvStructInfo)
3041 CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
3043 if (blob->cbData)
3045 DWORD i;
3046 BYTE temp;
3048 for (i = 0; i < blob->cbData / 2; i++)
3050 temp = blob->pbData[i];
3051 blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
3052 blob->pbData[blob->cbData - i - 1] = temp;
3056 TRACE("returning %d (%08lx)\n", ret, GetLastError());
3057 return ret;
3060 static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
3061 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3062 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3064 BOOL ret = TRUE;
3066 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3067 pDecodePara, pvStructInfo, *pcbStructInfo);
3069 __TRY
3071 struct AsnDecodeSequenceItem items[] = {
3072 { 0, offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
3073 CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
3074 offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 },
3075 { ASN_SEQUENCEOF, offsetof(CERT_SIGNED_CONTENT_INFO,
3076 SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
3077 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE,
3078 offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm.pszObjId), 0 },
3079 { ASN_BITSTRING, offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
3080 CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
3081 offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 },
3084 if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
3085 items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
3086 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3087 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3088 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3090 __EXCEPT_PAGE_FAULT
3092 SetLastError(STATUS_ACCESS_VIOLATION);
3093 ret = FALSE;
3095 __ENDTRY
3096 return ret;
3099 /* Internal function */
3100 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
3101 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3102 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3104 BOOL ret;
3105 DWORD dataLen;
3107 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3109 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3111 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
3112 pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
3113 pvStructInfo, pcbStructInfo);
3115 return ret;
3118 static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
3119 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3120 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3122 BOOL ret;
3124 struct AsnDecodeSequenceItem items[] = {
3125 { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
3126 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
3127 { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
3128 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
3131 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3132 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3133 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3134 return ret;
3137 /* Internal function */
3138 static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType,
3139 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3140 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3142 BOOL ret;
3143 DWORD dataLen;
3145 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3147 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3149 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3150 X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
3151 pDecodePara, pvStructInfo, pcbStructInfo);
3153 return ret;
3156 static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
3157 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3158 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3160 BOOL ret = TRUE;
3162 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3163 pDecodePara, pvStructInfo, *pcbStructInfo);
3165 __TRY
3167 struct AsnDecodeSequenceItem items[] = {
3168 { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CERT_INFO, dwVersion),
3169 CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 },
3170 { ASN_INTEGER, offsetof(CERT_INFO, SerialNumber),
3171 CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE,
3172 TRUE, offsetof(CERT_INFO, SerialNumber.pbData), 0 },
3173 { ASN_SEQUENCEOF, offsetof(CERT_INFO, SignatureAlgorithm),
3174 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3175 FALSE, TRUE, offsetof(CERT_INFO, SignatureAlgorithm.pszObjId), 0 },
3176 { 0, offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
3177 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
3178 Issuer.pbData) },
3179 { ASN_SEQUENCEOF, offsetof(CERT_INFO, NotBefore),
3180 CRYPT_AsnDecodeValidity, sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE,
3181 FALSE, 0 },
3182 { 0, offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
3183 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
3184 Subject.pbData) },
3185 { ASN_SEQUENCEOF, offsetof(CERT_INFO, SubjectPublicKeyInfo),
3186 CRYPT_AsnDecodePubKeyInfoInternal, sizeof(CERT_PUBLIC_KEY_INFO),
3187 FALSE, TRUE, offsetof(CERT_INFO,
3188 SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
3189 { ASN_BITSTRING, offsetof(CERT_INFO, IssuerUniqueId),
3190 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
3191 offsetof(CERT_INFO, IssuerUniqueId.pbData), 0 },
3192 { ASN_BITSTRING, offsetof(CERT_INFO, SubjectUniqueId),
3193 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
3194 offsetof(CERT_INFO, SubjectUniqueId.pbData), 0 },
3195 { ASN_CONTEXT | ASN_CONSTRUCTOR | 3, offsetof(CERT_INFO, cExtension),
3196 CRYPT_AsnDecodeCertExtensions, sizeof(CERT_EXTENSIONS), TRUE, TRUE,
3197 offsetof(CERT_INFO, rgExtension), 0 },
3200 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3201 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3202 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3204 __EXCEPT_PAGE_FAULT
3206 SetLastError(STATUS_ACCESS_VIOLATION);
3207 ret = FALSE;
3209 __ENDTRY
3210 return ret;
3213 static BOOL WINAPI CRYPT_AsnDecodeCRLEntry(DWORD dwCertEncodingType,
3214 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3215 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3217 BOOL ret;
3218 struct AsnDecodeSequenceItem items[] = {
3219 { ASN_INTEGER, offsetof(CRL_ENTRY, SerialNumber),
3220 CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE,
3221 offsetof(CRL_ENTRY, SerialNumber.pbData), 0 },
3222 { 0, offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
3223 sizeof(FILETIME), FALSE, FALSE, 0 },
3224 { ASN_SEQUENCEOF, offsetof(CRL_ENTRY, cExtension),
3225 CRYPT_AsnDecodeExtensionsInternal, sizeof(CERT_EXTENSIONS), TRUE, TRUE,
3226 offsetof(CRL_ENTRY, rgExtension), 0 },
3228 PCRL_ENTRY entry = (PCRL_ENTRY)pvStructInfo;
3230 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry,
3231 *pcbStructInfo);
3233 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3234 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3235 NULL, entry, pcbStructInfo, entry ? entry->SerialNumber.pbData : NULL);
3236 return ret;
3239 /* Warning: assumes pvStructInfo is a struct GenericArray whose rgItems has
3240 * been set prior to calling.
3242 static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
3243 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3244 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3246 BOOL ret;
3247 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
3248 CRYPT_AsnDecodeCRLEntry, sizeof(CRL_ENTRY), TRUE,
3249 offsetof(CRL_ENTRY, SerialNumber.pbData) };
3250 struct GenericArray *entries = (struct GenericArray *)pvStructInfo;
3252 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3253 pDecodePara, pvStructInfo, *pcbStructInfo);
3255 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3256 pDecodePara, pvStructInfo, pcbStructInfo,
3257 entries ? entries->rgItems : NULL);
3258 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3259 return ret;
3262 static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
3263 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3264 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3266 BOOL ret = TRUE;
3268 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3269 pDecodePara, pvStructInfo, *pcbStructInfo);
3271 __TRY
3273 struct AsnDecodeSequenceItem items[] = {
3274 { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CRL_INFO, dwVersion),
3275 CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 },
3276 { ASN_SEQUENCEOF, offsetof(CRL_INFO, SignatureAlgorithm),
3277 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3278 FALSE, TRUE, offsetof(CRL_INFO, SignatureAlgorithm.pszObjId), 0 },
3279 { 0, offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
3280 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO,
3281 Issuer.pbData) },
3282 { 0, offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
3283 sizeof(FILETIME), FALSE, FALSE, 0 },
3284 { 0, offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
3285 sizeof(FILETIME), TRUE, FALSE, 0 },
3286 { ASN_SEQUENCEOF, offsetof(CRL_INFO, cCRLEntry),
3287 CRYPT_AsnDecodeCRLEntries, sizeof(struct GenericArray), TRUE, TRUE,
3288 offsetof(CRL_INFO, rgCRLEntry), 0 },
3289 /* Note that the extensions are ignored by MS, so I'll ignore them too
3291 { 0, offsetof(CRL_INFO, cExtension), NULL,
3292 sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 },
3295 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3296 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3297 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3299 __EXCEPT_PAGE_FAULT
3301 SetLastError(STATUS_ACCESS_VIOLATION);
3302 ret = FALSE;
3304 __ENDTRY
3306 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3307 return ret;
3310 /* Differences between this and CRYPT_AsnDecodeOid:
3311 * - pvStructInfo is a LPSTR *, not an LPSTR
3312 * - CRYPT_AsnDecodeOid doesn't account for the size of an LPSTR in its byte
3313 * count, whereas our callers (typically CRYPT_AsnDecodeSequence) expect this
3314 * to
3316 static BOOL WINAPI CRYPT_AsnDecodeOidWrapper(DWORD dwCertEncodingType,
3317 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3318 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3320 BOOL ret;
3322 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3323 pDecodePara, pvStructInfo, *pcbStructInfo);
3325 ret = CRYPT_AsnDecodeOid(pbEncoded, cbEncoded, dwFlags,
3326 pvStructInfo ? *(LPSTR *)pvStructInfo : NULL, pcbStructInfo);
3327 if (ret || GetLastError() == ERROR_MORE_DATA)
3328 *pcbStructInfo += sizeof(LPSTR);
3329 if (ret && pvStructInfo)
3330 TRACE("returning %s\n", debugstr_a(*(LPSTR *)pvStructInfo));
3331 return ret;
3334 /* Warning: assumes pvStructInfo is a CERT_EXTENSION whose pszObjId is set
3335 * ahead of time!
3337 static BOOL WINAPI CRYPT_AsnDecodeExtension(DWORD dwCertEncodingType,
3338 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3339 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3341 struct AsnDecodeSequenceItem items[] = {
3342 { ASN_OBJECTIDENTIFIER, offsetof(CERT_EXTENSION, pszObjId),
3343 CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE,
3344 offsetof(CERT_EXTENSION, pszObjId), 0 },
3345 { ASN_BOOL, offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool,
3346 sizeof(BOOL), TRUE, FALSE, 0, 0 },
3347 { ASN_OCTETSTRING, offsetof(CERT_EXTENSION, Value),
3348 CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE,
3349 offsetof(CERT_EXTENSION, Value.pbData) },
3351 BOOL ret = TRUE;
3352 PCERT_EXTENSION ext = (PCERT_EXTENSION)pvStructInfo;
3354 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, ext,
3355 *pcbStructInfo);
3357 if (ext)
3358 TRACE("ext->pszObjId is %p\n", ext->pszObjId);
3359 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3360 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
3361 ext, pcbStructInfo, ext ? ext->pszObjId : NULL);
3362 if (ext)
3363 TRACE("ext->pszObjId is %p (%s)\n", ext->pszObjId,
3364 debugstr_a(ext->pszObjId));
3365 TRACE("returning %d (%08lx)\n", ret, GetLastError());
3366 return ret;
3369 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
3370 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3371 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3373 BOOL ret = TRUE;
3374 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
3375 CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE,
3376 offsetof(CERT_EXTENSION, pszObjId) };
3377 PCERT_EXTENSIONS exts = (PCERT_EXTENSIONS)pvStructInfo;
3379 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3380 pDecodePara, pvStructInfo, *pcbStructInfo);
3382 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3383 pDecodePara, pvStructInfo, pcbStructInfo, exts ? exts->rgExtension : NULL);
3384 return ret;
3387 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
3388 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3389 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3391 BOOL ret = TRUE;
3393 __TRY
3395 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3396 lpszStructType, pbEncoded, cbEncoded,
3397 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
3398 if (ret && pvStructInfo)
3400 ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
3401 pcbStructInfo, *pcbStructInfo);
3402 if (ret)
3404 CERT_EXTENSIONS *exts;
3406 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3407 pvStructInfo = *(BYTE **)pvStructInfo;
3408 exts = (CERT_EXTENSIONS *)pvStructInfo;
3409 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
3410 sizeof(CERT_EXTENSIONS));
3411 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3412 lpszStructType, pbEncoded, cbEncoded,
3413 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3414 pcbStructInfo);
3418 __EXCEPT_PAGE_FAULT
3420 SetLastError(STATUS_ACCESS_VIOLATION);
3421 ret = FALSE;
3423 __ENDTRY
3424 return ret;
3427 /* FIXME: honor the CRYPT_DECODE_SHARE_OID_STRING_FLAG. */
3428 static BOOL WINAPI CRYPT_AsnDecodeOid(const BYTE *pbEncoded, DWORD cbEncoded,
3429 DWORD dwFlags, LPSTR pszObjId, DWORD *pcbObjId)
3431 BOOL ret = TRUE;
3433 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, pszObjId,
3434 *pcbObjId);
3436 __TRY
3438 if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
3440 DWORD dataLen;
3442 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3444 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3445 DWORD bytesNeeded;
3447 if (dataLen)
3449 /* The largest possible string for the first two components
3450 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
3452 char firstTwo[6];
3453 const BYTE *ptr;
3455 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
3456 pbEncoded[1 + lenBytes] / 40,
3457 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
3458 * 40);
3459 bytesNeeded = strlen(firstTwo) + 1;
3460 for (ptr = pbEncoded + 2 + lenBytes; ret &&
3461 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3463 /* large enough for ".4000000" */
3464 char str[9];
3465 int val = 0;
3467 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3468 (*ptr & 0x80))
3470 val <<= 7;
3471 val |= *ptr & 0x7f;
3472 ptr++;
3474 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
3475 (*ptr & 0x80))
3477 SetLastError(CRYPT_E_ASN1_CORRUPT);
3478 ret = FALSE;
3480 else
3482 val <<= 7;
3483 val |= *ptr++;
3484 snprintf(str, sizeof(str), ".%d", val);
3485 bytesNeeded += strlen(str);
3488 if (!pszObjId)
3489 *pcbObjId = bytesNeeded;
3490 else if (*pcbObjId < bytesNeeded)
3492 *pcbObjId = bytesNeeded;
3493 SetLastError(ERROR_MORE_DATA);
3494 ret = FALSE;
3496 else
3498 *pszObjId = 0;
3499 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
3500 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
3501 40) * 40);
3502 pszObjId += strlen(pszObjId);
3503 for (ptr = pbEncoded + 2 + lenBytes; ret &&
3504 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3506 int val = 0;
3508 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3509 (*ptr & 0x80))
3511 val <<= 7;
3512 val |= *ptr & 0x7f;
3513 ptr++;
3515 val <<= 7;
3516 val |= *ptr++;
3517 sprintf(pszObjId, ".%d", val);
3518 pszObjId += strlen(pszObjId);
3522 else
3523 bytesNeeded = 0;
3524 *pcbObjId = bytesNeeded;
3527 else
3529 SetLastError(CRYPT_E_ASN1_BADTAG);
3530 ret = FALSE;
3533 __EXCEPT_PAGE_FAULT
3535 SetLastError(STATUS_ACCESS_VIOLATION);
3536 ret = FALSE;
3538 __ENDTRY
3539 return ret;
3542 /* Warning: this assumes the address of value->Value.pbData is already set, in
3543 * order to avoid overwriting memory. (In some cases, it may change it, if it
3544 * doesn't copy anything to memory.) Be sure to set it correctly!
3546 static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
3547 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3548 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3550 BOOL ret = TRUE;
3552 __TRY
3554 DWORD dataLen;
3555 CERT_NAME_VALUE *value = (CERT_NAME_VALUE *)pvStructInfo;
3557 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3559 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3561 switch (pbEncoded[0])
3563 case ASN_NUMERICSTRING:
3564 case ASN_PRINTABLESTRING:
3565 case ASN_IA5STRING:
3566 break;
3567 default:
3568 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
3569 SetLastError(OSS_UNIMPLEMENTED);
3570 ret = FALSE;
3572 if (ret)
3574 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
3576 switch (pbEncoded[0])
3578 case ASN_NUMERICSTRING:
3579 case ASN_PRINTABLESTRING:
3580 case ASN_IA5STRING:
3581 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3582 bytesNeeded += dataLen;
3583 break;
3585 if (!value)
3586 *pcbStructInfo = bytesNeeded;
3587 else if (*pcbStructInfo < bytesNeeded)
3589 *pcbStructInfo = bytesNeeded;
3590 SetLastError(ERROR_MORE_DATA);
3591 ret = FALSE;
3593 else
3595 *pcbStructInfo = bytesNeeded;
3596 switch (pbEncoded[0])
3598 case ASN_NUMERICSTRING:
3599 value->dwValueType = CERT_RDN_NUMERIC_STRING;
3600 break;
3601 case ASN_PRINTABLESTRING:
3602 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
3603 break;
3604 case ASN_IA5STRING:
3605 value->dwValueType = CERT_RDN_IA5_STRING;
3606 break;
3608 if (dataLen)
3610 switch (pbEncoded[0])
3612 case ASN_NUMERICSTRING:
3613 case ASN_PRINTABLESTRING:
3614 case ASN_IA5STRING:
3615 value->Value.cbData = dataLen;
3616 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3617 value->Value.pbData = (BYTE *)pbEncoded + 1 +
3618 lenBytes;
3619 else
3621 assert(value->Value.pbData);
3622 memcpy(value->Value.pbData,
3623 pbEncoded + 1 + lenBytes, dataLen);
3625 break;
3628 else
3630 value->Value.cbData = 0;
3631 value->Value.pbData = NULL;
3637 __EXCEPT_PAGE_FAULT
3639 SetLastError(STATUS_ACCESS_VIOLATION);
3640 ret = FALSE;
3642 __ENDTRY
3643 return ret;
3646 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
3647 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3648 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3650 BOOL ret;
3652 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3653 pvStructInfo, *pcbStructInfo);
3655 __TRY
3657 struct AsnDecodeSequenceItem items[] = {
3658 { ASN_OBJECTIDENTIFIER, offsetof(CERT_RDN_ATTR, pszObjId),
3659 CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE,
3660 offsetof(CERT_RDN_ATTR, pszObjId), 0 },
3661 { 0, offsetof(CERT_RDN_ATTR, dwValueType), CRYPT_AsnDecodeNameValue,
3662 sizeof(CERT_NAME_VALUE), FALSE, TRUE, offsetof(CERT_RDN_ATTR,
3663 Value.pbData), 0 },
3665 CERT_RDN_ATTR *attr = (CERT_RDN_ATTR *)pvStructInfo;
3667 if (attr)
3668 TRACE("attr->pszObjId is %p\n", attr->pszObjId);
3669 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3670 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
3671 attr, pcbStructInfo, attr ? attr->pszObjId : NULL);
3672 if (attr)
3674 TRACE("attr->pszObjId is %p (%s)\n", attr->pszObjId,
3675 debugstr_a(attr->pszObjId));
3676 TRACE("attr->dwValueType is %ld\n", attr->dwValueType);
3678 TRACE("returning %d (%08lx)\n", ret, GetLastError());
3680 __EXCEPT_PAGE_FAULT
3682 SetLastError(STATUS_ACCESS_VIOLATION);
3683 ret = FALSE;
3685 __ENDTRY
3686 return ret;
3689 static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
3690 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3691 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3693 BOOL ret = TRUE;
3695 __TRY
3697 struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF,
3698 CRYPT_AsnDecodeRdnAttr, sizeof(CERT_RDN_ATTR), TRUE,
3699 offsetof(CERT_RDN_ATTR, pszObjId) };
3700 PCERT_RDN rdn = (PCERT_RDN)pvStructInfo;
3702 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3703 pDecodePara, pvStructInfo, pcbStructInfo, rdn ? rdn->rgRDNAttr : NULL);
3705 __EXCEPT_PAGE_FAULT
3707 SetLastError(STATUS_ACCESS_VIOLATION);
3708 ret = FALSE;
3710 __ENDTRY
3711 return ret;
3714 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
3715 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3716 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3718 BOOL ret = TRUE;
3720 __TRY
3722 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
3723 CRYPT_AsnDecodeRdn, sizeof(CERT_RDN), TRUE,
3724 offsetof(CERT_RDN, rgRDNAttr) };
3726 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3727 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3729 __EXCEPT_PAGE_FAULT
3731 SetLastError(STATUS_ACCESS_VIOLATION);
3732 ret = FALSE;
3734 __ENDTRY
3735 return ret;
3738 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
3739 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3740 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3742 BOOL ret = TRUE;
3743 DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
3745 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3746 pDecodePara, pvStructInfo, *pcbStructInfo);
3748 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3749 bytesNeeded += cbEncoded;
3750 if (!pvStructInfo)
3751 *pcbStructInfo = bytesNeeded;
3752 else if (*pcbStructInfo < bytesNeeded)
3754 SetLastError(ERROR_MORE_DATA);
3755 *pcbStructInfo = bytesNeeded;
3756 ret = FALSE;
3758 else
3760 PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
3762 *pcbStructInfo = bytesNeeded;
3763 blob->cbData = cbEncoded;
3764 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3765 blob->pbData = (LPBYTE)pbEncoded;
3766 else
3768 assert(blob->pbData);
3769 memcpy(blob->pbData, pbEncoded, blob->cbData);
3772 return ret;
3775 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
3776 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3777 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3779 CRYPT_ALGORITHM_IDENTIFIER *algo =
3780 (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
3781 BOOL ret = TRUE;
3782 struct AsnDecodeSequenceItem items[] = {
3783 { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
3784 CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), FALSE, TRUE,
3785 offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
3786 { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
3787 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
3788 offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
3791 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3792 pDecodePara, pvStructInfo, *pcbStructInfo);
3794 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3795 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3796 pDecodePara, pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
3797 if (ret && pvStructInfo)
3799 TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
3800 debugstr_a(algo->pszObjId));
3802 return ret;
3805 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType,
3806 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3807 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3809 BOOL ret = TRUE;
3810 struct AsnDecodeSequenceItem items[] = {
3811 { ASN_SEQUENCEOF, offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
3812 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3813 FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO,
3814 Algorithm.pszObjId) },
3815 { ASN_BITSTRING, offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
3816 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
3817 offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) },
3819 PCERT_PUBLIC_KEY_INFO info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo;
3821 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3822 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3823 pDecodePara, pvStructInfo, pcbStructInfo, info ?
3824 info->Algorithm.Parameters.pbData : NULL);
3825 return ret;
3828 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
3829 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3830 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3832 BOOL ret = TRUE;
3834 __TRY
3836 DWORD bytesNeeded;
3838 if ((ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType,
3839 lpszStructType, pbEncoded, cbEncoded,
3840 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
3842 if (!pvStructInfo)
3843 *pcbStructInfo = bytesNeeded;
3844 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3845 pvStructInfo, pcbStructInfo, bytesNeeded)))
3847 PCERT_PUBLIC_KEY_INFO info;
3849 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3850 pvStructInfo = *(BYTE **)pvStructInfo;
3851 info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo;
3852 info->Algorithm.Parameters.pbData = (BYTE *)pvStructInfo +
3853 sizeof(CERT_PUBLIC_KEY_INFO);
3854 ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType,
3855 lpszStructType, pbEncoded, cbEncoded,
3856 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3857 &bytesNeeded);
3861 __EXCEPT_PAGE_FAULT
3863 SetLastError(STATUS_ACCESS_VIOLATION);
3864 ret = FALSE;
3866 __ENDTRY
3867 return ret;
3870 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
3871 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3872 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3874 BOOL ret;
3876 if (cbEncoded < 3)
3878 SetLastError(CRYPT_E_ASN1_CORRUPT);
3879 return FALSE;
3881 if (GET_LEN_BYTES(pbEncoded[1]) > 1)
3883 SetLastError(CRYPT_E_ASN1_CORRUPT);
3884 return FALSE;
3886 if (pbEncoded[1] > 1)
3888 SetLastError(CRYPT_E_ASN1_CORRUPT);
3889 return FALSE;
3891 if (!pvStructInfo)
3893 *pcbStructInfo = sizeof(BOOL);
3894 ret = TRUE;
3896 else if (*pcbStructInfo < sizeof(BOOL))
3898 *pcbStructInfo = sizeof(BOOL);
3899 SetLastError(ERROR_MORE_DATA);
3900 ret = FALSE;
3902 else
3904 *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
3905 ret = TRUE;
3907 TRACE("returning %d (%08lx)\n", ret, GetLastError());
3908 return ret;
3911 static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType,
3912 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3913 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3915 PCERT_ALT_NAME_ENTRY entry = (PCERT_ALT_NAME_ENTRY)pvStructInfo;
3916 DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY);
3917 BOOL ret;
3919 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3920 pDecodePara, pvStructInfo, *pcbStructInfo);
3922 if (cbEncoded < 2)
3924 SetLastError(CRYPT_E_ASN1_CORRUPT);
3925 return FALSE;
3927 if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT)
3929 SetLastError(CRYPT_E_ASN1_BADTAG);
3930 return FALSE;
3932 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3933 if (1 + lenBytes > cbEncoded)
3935 SetLastError(CRYPT_E_ASN1_CORRUPT);
3936 return FALSE;
3938 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3940 switch (pbEncoded[0] & ASN_TYPE_MASK)
3942 case 1: /* rfc822Name */
3943 case 2: /* dNSName */
3944 case 6: /* uniformResourceIdentifier */
3945 bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
3946 break;
3947 case 7: /* iPAddress */
3948 bytesNeeded += dataLen;
3949 break;
3950 case 8: /* registeredID */
3951 /* FIXME: decode as OID */
3952 case 0: /* otherName */
3953 case 4: /* directoryName */
3954 FIXME("stub\n");
3955 SetLastError(CRYPT_E_ASN1_BADTAG);
3956 ret = FALSE;
3957 break;
3958 case 3: /* x400Address, unimplemented */
3959 case 5: /* ediPartyName, unimplemented */
3960 SetLastError(CRYPT_E_ASN1_BADTAG);
3961 ret = FALSE;
3962 break;
3963 default:
3964 SetLastError(CRYPT_E_ASN1_CORRUPT);
3965 ret = FALSE;
3967 if (ret)
3969 if (!entry)
3970 *pcbStructInfo = bytesNeeded;
3971 else if (*pcbStructInfo < bytesNeeded)
3973 *pcbStructInfo = bytesNeeded;
3974 SetLastError(ERROR_MORE_DATA);
3975 ret = FALSE;
3977 else
3979 *pcbStructInfo = bytesNeeded;
3980 /* MS used values one greater than the asn1 ones.. sigh */
3981 entry->dwAltNameChoice = (pbEncoded[0] & 0x7f) + 1;
3982 switch (pbEncoded[0] & ASN_TYPE_MASK)
3984 case 1: /* rfc822Name */
3985 case 2: /* dNSName */
3986 case 6: /* uniformResourceIdentifier */
3988 DWORD i;
3990 for (i = 0; i < dataLen; i++)
3991 entry->u.pwszURL[i] =
3992 (WCHAR)pbEncoded[1 + lenBytes + i];
3993 entry->u.pwszURL[i] = 0;
3994 TRACE("URL is %p (%s)\n", entry->u.pwszURL,
3995 debugstr_w(entry->u.pwszURL));
3996 break;
3998 case 7: /* iPAddress */
3999 /* The next data pointer is in the pwszURL spot, that is,
4000 * the first 4 bytes. Need to move it to the next spot.
4002 entry->u.IPAddress.pbData = (LPBYTE)entry->u.pwszURL;
4003 entry->u.IPAddress.cbData = dataLen;
4004 memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes,
4005 dataLen);
4006 break;
4011 return ret;
4014 static BOOL WINAPI CRYPT_AsnDecodeAltNameInternal(DWORD dwCertEncodingType,
4015 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4016 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4018 BOOL ret = TRUE;
4019 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
4020 CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE,
4021 offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) };
4022 PCERT_ALT_NAME_INFO info = (PCERT_ALT_NAME_INFO)pvStructInfo;
4024 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4025 pDecodePara, pvStructInfo, *pcbStructInfo);
4027 if (info)
4028 TRACE("info->rgAltEntry is %p\n", info->rgAltEntry);
4029 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
4030 pDecodePara, pvStructInfo, pcbStructInfo, info ? info->rgAltEntry : NULL);
4031 return ret;
4034 static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
4035 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4036 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4038 BOOL ret = TRUE;
4040 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4041 pDecodePara, pvStructInfo, *pcbStructInfo);
4043 __TRY
4045 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
4046 CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE,
4047 offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) };
4049 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
4050 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4052 __EXCEPT_PAGE_FAULT
4054 SetLastError(STATUS_ACCESS_VIOLATION);
4055 ret = FALSE;
4057 __ENDTRY
4058 return ret;
4061 struct PATH_LEN_CONSTRAINT
4063 BOOL fPathLenConstraint;
4064 DWORD dwPathLenConstraint;
4067 static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType,
4068 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4069 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4071 BOOL ret = TRUE;
4073 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4074 pvStructInfo, *pcbStructInfo);
4076 if (cbEncoded)
4078 if (pbEncoded[0] == ASN_INTEGER)
4080 DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT);
4082 if (!pvStructInfo)
4083 *pcbStructInfo = bytesNeeded;
4084 else if (*pcbStructInfo < bytesNeeded)
4086 SetLastError(ERROR_MORE_DATA);
4087 *pcbStructInfo = bytesNeeded;
4088 ret = FALSE;
4090 else
4092 struct PATH_LEN_CONSTRAINT *constraint =
4093 (struct PATH_LEN_CONSTRAINT *)pvStructInfo;
4094 DWORD size = sizeof(constraint->dwPathLenConstraint);
4096 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
4097 pbEncoded, cbEncoded, 0, NULL,
4098 &constraint->dwPathLenConstraint, &size);
4099 if (ret)
4100 constraint->fPathLenConstraint = TRUE;
4101 TRACE("got an int, dwPathLenConstraint is %ld\n",
4102 constraint->dwPathLenConstraint);
4105 else
4107 SetLastError(CRYPT_E_ASN1_CORRUPT);
4108 ret = FALSE;
4111 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4112 return ret;
4115 static BOOL WINAPI CRYPT_AsnDecodeSubtreeConstraints(DWORD dwCertEncodingType,
4116 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4117 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4119 BOOL ret;
4120 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
4121 CRYPT_AsnDecodeCopyBytes, sizeof(CERT_NAME_BLOB), TRUE,
4122 offsetof(CERT_NAME_BLOB, pbData) };
4123 struct GenericArray *entries = (struct GenericArray *)pvStructInfo;
4125 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4126 pDecodePara, pvStructInfo, *pcbStructInfo);
4128 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
4129 pDecodePara, pvStructInfo, pcbStructInfo,
4130 entries ? entries->rgItems : NULL);
4131 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
4132 return ret;
4135 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints(DWORD dwCertEncodingType,
4136 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4137 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4139 BOOL ret;
4141 __TRY
4143 struct AsnDecodeSequenceItem items[] = {
4144 { ASN_BITSTRING, offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType),
4145 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
4146 offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType.pbData), 0 },
4147 { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS_INFO,
4148 fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint,
4149 sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 },
4150 { ASN_SEQUENCEOF, offsetof(CERT_BASIC_CONSTRAINTS_INFO,
4151 cSubtreesConstraint), CRYPT_AsnDecodeSubtreeConstraints,
4152 sizeof(struct GenericArray), TRUE, TRUE,
4153 offsetof(CERT_BASIC_CONSTRAINTS_INFO, rgSubtreesConstraint), 0 },
4156 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4157 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4158 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4160 __EXCEPT_PAGE_FAULT
4162 SetLastError(STATUS_ACCESS_VIOLATION);
4163 ret = FALSE;
4165 __ENDTRY
4166 return ret;
4169 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(DWORD dwCertEncodingType,
4170 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4171 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4173 BOOL ret;
4175 __TRY
4177 struct AsnDecodeSequenceItem items[] = {
4178 { ASN_BOOL, offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA),
4179 CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, FALSE, 0, 0 },
4180 { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS2_INFO,
4181 fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint,
4182 sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 },
4185 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4186 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4187 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4189 __EXCEPT_PAGE_FAULT
4191 SetLastError(STATUS_ACCESS_VIOLATION);
4192 ret = FALSE;
4194 __ENDTRY
4195 return ret;
4198 #define RSA1_MAGIC 0x31415352
4200 struct DECODED_RSA_PUB_KEY
4202 DWORD pubexp;
4203 CRYPT_INTEGER_BLOB modulus;
4206 static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
4207 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4208 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4210 BOOL ret;
4212 __TRY
4214 struct AsnDecodeSequenceItem items[] = {
4215 { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, modulus),
4216 CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB),
4217 FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData),
4218 0 },
4219 { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
4220 CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
4222 struct DECODED_RSA_PUB_KEY *decodedKey = NULL;
4223 DWORD size = 0;
4225 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4226 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
4227 CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL);
4228 if (ret)
4230 DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
4231 decodedKey->modulus.cbData;
4233 if (!pvStructInfo)
4235 *pcbStructInfo = bytesNeeded;
4236 ret = TRUE;
4238 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4239 pvStructInfo, pcbStructInfo, bytesNeeded)))
4241 BLOBHEADER *hdr;
4242 RSAPUBKEY *rsaPubKey;
4244 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4245 pvStructInfo = *(BYTE **)pvStructInfo;
4246 hdr = (BLOBHEADER *)pvStructInfo;
4247 hdr->bType = PUBLICKEYBLOB;
4248 hdr->bVersion = CUR_BLOB_VERSION;
4249 hdr->reserved = 0;
4250 hdr->aiKeyAlg = CALG_RSA_KEYX;
4251 rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo +
4252 sizeof(BLOBHEADER));
4253 rsaPubKey->magic = RSA1_MAGIC;
4254 rsaPubKey->pubexp = decodedKey->pubexp;
4255 rsaPubKey->bitlen = decodedKey->modulus.cbData * 8;
4256 memcpy((BYTE *)pvStructInfo + sizeof(BLOBHEADER) +
4257 sizeof(RSAPUBKEY), decodedKey->modulus.pbData,
4258 decodedKey->modulus.cbData);
4260 LocalFree(decodedKey);
4263 __EXCEPT_PAGE_FAULT
4265 SetLastError(STATUS_ACCESS_VIOLATION);
4266 ret = FALSE;
4268 __ENDTRY
4269 return ret;
4272 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
4273 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4274 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4276 BOOL ret;
4277 DWORD bytesNeeded, dataLen;
4279 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4280 pDecodePara, pvStructInfo, *pcbStructInfo);
4282 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4284 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4285 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
4286 else
4287 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
4288 if (!pvStructInfo)
4289 *pcbStructInfo = bytesNeeded;
4290 else if (*pcbStructInfo < bytesNeeded)
4292 SetLastError(ERROR_MORE_DATA);
4293 *pcbStructInfo = bytesNeeded;
4294 ret = FALSE;
4296 else
4298 CRYPT_DATA_BLOB *blob;
4299 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4301 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4302 blob->cbData = dataLen;
4303 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4304 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
4305 else
4307 assert(blob->pbData);
4308 if (blob->cbData)
4309 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
4310 blob->cbData);
4314 return ret;
4317 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
4318 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4319 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4321 BOOL ret;
4323 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4324 pDecodePara, pvStructInfo, *pcbStructInfo);
4326 __TRY
4328 DWORD bytesNeeded;
4330 if (!cbEncoded)
4332 SetLastError(CRYPT_E_ASN1_CORRUPT);
4333 ret = FALSE;
4335 else if (pbEncoded[0] != ASN_OCTETSTRING)
4337 SetLastError(CRYPT_E_ASN1_BADTAG);
4338 ret = FALSE;
4340 else if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4341 lpszStructType, pbEncoded, cbEncoded,
4342 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4344 if (!pvStructInfo)
4345 *pcbStructInfo = bytesNeeded;
4346 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4347 pvStructInfo, pcbStructInfo, bytesNeeded)))
4349 CRYPT_DATA_BLOB *blob;
4351 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4352 pvStructInfo = *(BYTE **)pvStructInfo;
4353 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4354 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB);
4355 ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4356 lpszStructType, pbEncoded, cbEncoded,
4357 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4358 &bytesNeeded);
4362 __EXCEPT_PAGE_FAULT
4364 SetLastError(STATUS_ACCESS_VIOLATION);
4365 ret = FALSE;
4367 __ENDTRY
4368 return ret;
4371 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
4372 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4373 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4375 BOOL ret;
4377 TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
4378 pDecodePara, pvStructInfo, *pcbStructInfo);
4380 if (pbEncoded[0] == ASN_BITSTRING)
4382 DWORD bytesNeeded, dataLen;
4384 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4386 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4387 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
4388 else
4389 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
4390 if (!pvStructInfo)
4391 *pcbStructInfo = bytesNeeded;
4392 else if (*pcbStructInfo < bytesNeeded)
4394 *pcbStructInfo = bytesNeeded;
4395 SetLastError(ERROR_MORE_DATA);
4396 ret = FALSE;
4398 else
4400 CRYPT_BIT_BLOB *blob;
4402 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4403 blob->cbData = dataLen - 1;
4404 blob->cUnusedBits = *(pbEncoded + 1 +
4405 GET_LEN_BYTES(pbEncoded[1]));
4406 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4408 blob->pbData = (BYTE *)pbEncoded + 2 +
4409 GET_LEN_BYTES(pbEncoded[1]);
4411 else
4413 assert(blob->pbData);
4414 if (blob->cbData)
4416 BYTE mask = 0xff << blob->cUnusedBits;
4418 memcpy(blob->pbData, pbEncoded + 2 +
4419 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
4420 blob->pbData[blob->cbData - 1] &= mask;
4426 else
4428 SetLastError(CRYPT_E_ASN1_BADTAG);
4429 ret = FALSE;
4431 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4432 return ret;
4435 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
4436 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4437 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4439 BOOL ret;
4441 TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
4442 pDecodePara, pvStructInfo, pcbStructInfo);
4444 __TRY
4446 DWORD bytesNeeded;
4448 if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4449 lpszStructType, pbEncoded, cbEncoded,
4450 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4452 if (!pvStructInfo)
4453 *pcbStructInfo = bytesNeeded;
4454 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4455 pvStructInfo, pcbStructInfo, bytesNeeded)))
4457 CRYPT_BIT_BLOB *blob;
4459 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4460 pvStructInfo = *(BYTE **)pvStructInfo;
4461 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4462 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
4463 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4464 lpszStructType, pbEncoded, cbEncoded,
4465 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4466 &bytesNeeded);
4470 __EXCEPT_PAGE_FAULT
4472 SetLastError(STATUS_ACCESS_VIOLATION);
4473 ret = FALSE;
4475 __ENDTRY
4476 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4477 return ret;
4480 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
4481 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4482 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4484 BOOL ret;
4486 if (!pvStructInfo)
4488 *pcbStructInfo = sizeof(int);
4489 return TRUE;
4491 __TRY
4493 BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
4494 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
4495 DWORD size = sizeof(buf);
4497 blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
4498 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4499 X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
4500 if (ret)
4502 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4503 pvStructInfo, pcbStructInfo, sizeof(int))))
4505 int val, i;
4507 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4508 pvStructInfo = *(BYTE **)pvStructInfo;
4509 if (blob->pbData[blob->cbData - 1] & 0x80)
4511 /* initialize to a negative value to sign-extend */
4512 val = -1;
4514 else
4515 val = 0;
4516 for (i = 0; i < blob->cbData; i++)
4518 val <<= 8;
4519 val |= blob->pbData[blob->cbData - i - 1];
4521 memcpy(pvStructInfo, &val, sizeof(int));
4524 else if (GetLastError() == ERROR_MORE_DATA)
4525 SetLastError(CRYPT_E_ASN1_LARGE);
4527 __EXCEPT_PAGE_FAULT
4529 SetLastError(STATUS_ACCESS_VIOLATION);
4530 ret = FALSE;
4532 __ENDTRY
4533 return ret;
4536 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
4537 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4538 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4540 BOOL ret;
4542 if (pbEncoded[0] == ASN_INTEGER)
4544 DWORD bytesNeeded, dataLen;
4546 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4548 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4550 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4551 if (!pvStructInfo)
4552 *pcbStructInfo = bytesNeeded;
4553 else if (*pcbStructInfo < bytesNeeded)
4555 *pcbStructInfo = bytesNeeded;
4556 SetLastError(ERROR_MORE_DATA);
4557 ret = FALSE;
4559 else
4561 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4563 blob->cbData = dataLen;
4564 assert(blob->pbData);
4565 if (blob->cbData)
4567 DWORD i;
4569 for (i = 0; i < blob->cbData; i++)
4571 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4572 dataLen - i - 1);
4578 else
4580 SetLastError(CRYPT_E_ASN1_BADTAG);
4581 ret = FALSE;
4583 return ret;
4586 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
4587 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4588 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4590 BOOL ret;
4592 __TRY
4594 DWORD bytesNeeded;
4596 if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4597 lpszStructType, pbEncoded, cbEncoded,
4598 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4600 if (!pvStructInfo)
4601 *pcbStructInfo = bytesNeeded;
4602 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4603 pvStructInfo, pcbStructInfo, bytesNeeded)))
4605 CRYPT_INTEGER_BLOB *blob;
4607 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4608 pvStructInfo = *(BYTE **)pvStructInfo;
4609 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4610 blob->pbData = (BYTE *)pvStructInfo +
4611 sizeof(CRYPT_INTEGER_BLOB);
4612 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4613 lpszStructType, pbEncoded, cbEncoded,
4614 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4615 &bytesNeeded);
4619 __EXCEPT_PAGE_FAULT
4621 SetLastError(STATUS_ACCESS_VIOLATION);
4622 ret = FALSE;
4624 __ENDTRY
4625 return ret;
4628 static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
4629 DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
4630 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
4631 void *pvStructInfo, DWORD *pcbStructInfo)
4633 BOOL ret;
4635 if (pbEncoded[0] == ASN_INTEGER)
4637 DWORD bytesNeeded, dataLen;
4639 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4641 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4643 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4644 if (!pvStructInfo)
4645 *pcbStructInfo = bytesNeeded;
4646 else if (*pcbStructInfo < bytesNeeded)
4648 *pcbStructInfo = bytesNeeded;
4649 SetLastError(ERROR_MORE_DATA);
4650 ret = FALSE;
4652 else
4654 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4656 blob->cbData = dataLen;
4657 assert(blob->pbData);
4658 /* remove leading zero byte if it exists */
4659 if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
4661 blob->cbData--;
4662 blob->pbData++;
4664 if (blob->cbData)
4666 DWORD i;
4668 for (i = 0; i < blob->cbData; i++)
4670 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4671 dataLen - i - 1);
4677 else
4679 SetLastError(CRYPT_E_ASN1_BADTAG);
4680 ret = FALSE;
4682 return ret;
4685 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
4686 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4687 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4689 BOOL ret;
4691 __TRY
4693 DWORD bytesNeeded;
4695 if ((ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType,
4696 lpszStructType, pbEncoded, cbEncoded,
4697 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4699 if (!pvStructInfo)
4700 *pcbStructInfo = bytesNeeded;
4701 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4702 pvStructInfo, pcbStructInfo, bytesNeeded)))
4704 CRYPT_INTEGER_BLOB *blob;
4706 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4707 pvStructInfo = *(BYTE **)pvStructInfo;
4708 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4709 blob->pbData = (BYTE *)pvStructInfo +
4710 sizeof(CRYPT_INTEGER_BLOB);
4711 ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType,
4712 lpszStructType, pbEncoded, cbEncoded,
4713 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4714 &bytesNeeded);
4718 __EXCEPT_PAGE_FAULT
4720 SetLastError(STATUS_ACCESS_VIOLATION);
4721 ret = FALSE;
4723 __ENDTRY
4724 return ret;
4727 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
4728 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4729 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4731 BOOL ret;
4733 if (!pvStructInfo)
4735 *pcbStructInfo = sizeof(int);
4736 return TRUE;
4738 __TRY
4740 if (pbEncoded[0] == ASN_ENUMERATED)
4742 unsigned int val = 0, i;
4744 if (cbEncoded <= 1)
4746 SetLastError(CRYPT_E_ASN1_EOD);
4747 ret = FALSE;
4749 else if (pbEncoded[1] == 0)
4751 SetLastError(CRYPT_E_ASN1_CORRUPT);
4752 ret = FALSE;
4754 else
4756 /* A little strange looking, but we have to accept a sign byte:
4757 * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff. Also,
4758 * assuming a small length is okay here, it has to be in short
4759 * form.
4761 if (pbEncoded[1] > sizeof(unsigned int) + 1)
4763 SetLastError(CRYPT_E_ASN1_LARGE);
4764 return FALSE;
4766 for (i = 0; i < pbEncoded[1]; i++)
4768 val <<= 8;
4769 val |= pbEncoded[2 + i];
4771 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4772 pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
4774 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4775 pvStructInfo = *(BYTE **)pvStructInfo;
4776 memcpy(pvStructInfo, &val, sizeof(unsigned int));
4780 else
4782 SetLastError(CRYPT_E_ASN1_BADTAG);
4783 ret = FALSE;
4786 __EXCEPT_PAGE_FAULT
4788 SetLastError(STATUS_ACCESS_VIOLATION);
4789 ret = FALSE;
4791 __ENDTRY
4792 return ret;
4795 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
4796 * if it fails.
4798 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
4799 do { \
4800 BYTE i; \
4802 (word) = 0; \
4803 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
4805 if (!isdigit(*(pbEncoded))) \
4807 SetLastError(CRYPT_E_ASN1_CORRUPT); \
4808 ret = FALSE; \
4810 else \
4812 (word) *= 10; \
4813 (word) += *(pbEncoded)++ - '0'; \
4816 } while (0)
4818 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
4819 SYSTEMTIME *sysTime)
4821 BOOL ret;
4823 __TRY
4825 ret = TRUE;
4826 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
4828 WORD hours, minutes = 0;
4829 BYTE sign = *pbEncoded++;
4831 len--;
4832 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
4833 if (ret && hours >= 24)
4835 SetLastError(CRYPT_E_ASN1_CORRUPT);
4836 ret = FALSE;
4838 else if (len >= 2)
4840 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
4841 if (ret && minutes >= 60)
4843 SetLastError(CRYPT_E_ASN1_CORRUPT);
4844 ret = FALSE;
4847 if (ret)
4849 if (sign == '+')
4851 sysTime->wHour += hours;
4852 sysTime->wMinute += minutes;
4854 else
4856 if (hours > sysTime->wHour)
4858 sysTime->wDay--;
4859 sysTime->wHour = 24 - (hours - sysTime->wHour);
4861 else
4862 sysTime->wHour -= hours;
4863 if (minutes > sysTime->wMinute)
4865 sysTime->wHour--;
4866 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
4868 else
4869 sysTime->wMinute -= minutes;
4874 __EXCEPT_PAGE_FAULT
4876 SetLastError(STATUS_ACCESS_VIOLATION);
4877 ret = FALSE;
4879 __ENDTRY
4880 return ret;
4883 #define MIN_ENCODED_TIME_LENGTH 10
4885 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
4886 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4887 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4889 BOOL ret;
4891 if (!pvStructInfo)
4893 *pcbStructInfo = sizeof(FILETIME);
4894 return TRUE;
4896 __TRY
4898 ret = TRUE;
4899 if (pbEncoded[0] == ASN_UTCTIME)
4901 if (cbEncoded <= 1)
4903 SetLastError(CRYPT_E_ASN1_EOD);
4904 ret = FALSE;
4906 else if (pbEncoded[1] > 0x7f)
4908 /* long-form date strings really can't be valid */
4909 SetLastError(CRYPT_E_ASN1_CORRUPT);
4910 ret = FALSE;
4912 else
4914 SYSTEMTIME sysTime = { 0 };
4915 BYTE len = pbEncoded[1];
4917 if (len < MIN_ENCODED_TIME_LENGTH)
4919 SetLastError(CRYPT_E_ASN1_CORRUPT);
4920 ret = FALSE;
4922 else
4924 pbEncoded += 2;
4925 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
4926 if (sysTime.wYear >= 50)
4927 sysTime.wYear += 1900;
4928 else
4929 sysTime.wYear += 2000;
4930 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
4931 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
4932 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
4933 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
4934 if (ret && len > 0)
4936 if (len >= 2 && isdigit(*pbEncoded) &&
4937 isdigit(*(pbEncoded + 1)))
4938 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4939 sysTime.wSecond);
4940 else if (isdigit(*pbEncoded))
4941 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
4942 sysTime.wSecond);
4943 if (ret)
4944 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
4945 &sysTime);
4947 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
4948 pDecodePara, pvStructInfo, pcbStructInfo,
4949 sizeof(FILETIME))))
4951 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4952 pvStructInfo = *(BYTE **)pvStructInfo;
4953 ret = SystemTimeToFileTime(&sysTime,
4954 (FILETIME *)pvStructInfo);
4959 else
4961 SetLastError(CRYPT_E_ASN1_BADTAG);
4962 ret = FALSE;
4965 __EXCEPT_PAGE_FAULT
4967 SetLastError(STATUS_ACCESS_VIOLATION);
4968 ret = FALSE;
4970 __ENDTRY
4971 return ret;
4974 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
4975 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4976 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4978 BOOL ret;
4980 if (!pvStructInfo)
4982 *pcbStructInfo = sizeof(FILETIME);
4983 return TRUE;
4985 __TRY
4987 ret = TRUE;
4988 if (pbEncoded[0] == ASN_GENERALTIME)
4990 if (cbEncoded <= 1)
4992 SetLastError(CRYPT_E_ASN1_EOD);
4993 ret = FALSE;
4995 else if (pbEncoded[1] > 0x7f)
4997 /* long-form date strings really can't be valid */
4998 SetLastError(CRYPT_E_ASN1_CORRUPT);
4999 ret = FALSE;
5001 else
5003 BYTE len = pbEncoded[1];
5005 if (len < MIN_ENCODED_TIME_LENGTH)
5007 SetLastError(CRYPT_E_ASN1_CORRUPT);
5008 ret = FALSE;
5010 else
5012 SYSTEMTIME sysTime = { 0 };
5014 pbEncoded += 2;
5015 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
5016 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
5017 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
5018 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
5019 if (ret && len > 0)
5021 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5022 sysTime.wMinute);
5023 if (ret && len > 0)
5024 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
5025 sysTime.wSecond);
5026 if (ret && len > 0 && (*pbEncoded == '.' ||
5027 *pbEncoded == ','))
5029 BYTE digits;
5031 pbEncoded++;
5032 len--;
5033 /* workaround macro weirdness */
5034 digits = min(len, 3);
5035 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
5036 sysTime.wMilliseconds);
5038 if (ret)
5039 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
5040 &sysTime);
5042 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
5043 pDecodePara, pvStructInfo, pcbStructInfo,
5044 sizeof(FILETIME))))
5046 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5047 pvStructInfo = *(BYTE **)pvStructInfo;
5048 ret = SystemTimeToFileTime(&sysTime,
5049 (FILETIME *)pvStructInfo);
5054 else
5056 SetLastError(CRYPT_E_ASN1_BADTAG);
5057 ret = FALSE;
5060 __EXCEPT_PAGE_FAULT
5062 SetLastError(STATUS_ACCESS_VIOLATION);
5063 ret = FALSE;
5065 __ENDTRY
5066 return ret;
5069 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
5070 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5071 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5073 BOOL ret;
5075 __TRY
5077 if (pbEncoded[0] == ASN_UTCTIME)
5078 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
5079 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
5080 pcbStructInfo);
5081 else if (pbEncoded[0] == ASN_GENERALTIME)
5082 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
5083 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
5084 pvStructInfo, pcbStructInfo);
5085 else
5087 SetLastError(CRYPT_E_ASN1_BADTAG);
5088 ret = FALSE;
5091 __EXCEPT_PAGE_FAULT
5093 SetLastError(STATUS_ACCESS_VIOLATION);
5094 ret = FALSE;
5096 __ENDTRY
5097 return ret;
5100 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
5101 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5102 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5104 BOOL ret = TRUE;
5106 __TRY
5108 if (pbEncoded[0] == ASN_SEQUENCEOF)
5110 DWORD bytesNeeded, dataLen, remainingLen, cValue;
5112 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
5114 BYTE lenBytes;
5115 const BYTE *ptr;
5117 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
5118 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
5119 cValue = 0;
5120 ptr = pbEncoded + 1 + lenBytes;
5121 remainingLen = dataLen;
5122 while (ret && remainingLen)
5124 DWORD nextLen;
5126 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5127 if (ret)
5129 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5131 remainingLen -= 1 + nextLenBytes + nextLen;
5132 ptr += 1 + nextLenBytes + nextLen;
5133 bytesNeeded += sizeof(CRYPT_DER_BLOB);
5134 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
5135 bytesNeeded += 1 + nextLenBytes + nextLen;
5136 cValue++;
5139 if (ret)
5141 CRYPT_SEQUENCE_OF_ANY *seq;
5142 BYTE *nextPtr;
5143 DWORD i;
5145 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
5146 pvStructInfo, pcbStructInfo, bytesNeeded)))
5148 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5149 pvStructInfo = *(BYTE **)pvStructInfo;
5150 seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
5151 seq->cValue = cValue;
5152 seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
5153 sizeof(*seq));
5154 nextPtr = (BYTE *)seq->rgValue +
5155 cValue * sizeof(CRYPT_DER_BLOB);
5156 ptr = pbEncoded + 1 + lenBytes;
5157 remainingLen = dataLen;
5158 i = 0;
5159 while (ret && remainingLen)
5161 DWORD nextLen;
5163 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5164 if (ret)
5166 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5168 seq->rgValue[i].cbData = 1 + nextLenBytes +
5169 nextLen;
5170 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
5171 seq->rgValue[i].pbData = (BYTE *)ptr;
5172 else
5174 seq->rgValue[i].pbData = nextPtr;
5175 memcpy(nextPtr, ptr, 1 + nextLenBytes +
5176 nextLen);
5177 nextPtr += 1 + nextLenBytes + nextLen;
5179 remainingLen -= 1 + nextLenBytes + nextLen;
5180 ptr += 1 + nextLenBytes + nextLen;
5181 i++;
5188 else
5190 SetLastError(CRYPT_E_ASN1_BADTAG);
5191 return FALSE;
5194 __EXCEPT_PAGE_FAULT
5196 SetLastError(STATUS_ACCESS_VIOLATION);
5197 ret = FALSE;
5199 __ENDTRY
5200 return ret;
5203 static BOOL WINAPI CRYPT_AsnDecodeDistPoint(DWORD dwCertEncodingType,
5204 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5205 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5207 struct AsnDecodeSequenceItem items[] = {
5208 { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CRL_DIST_POINT,
5209 DistPointName), CRYPT_AsnDecodeAltNameInternal,
5210 sizeof(CRL_DIST_POINT_NAME), TRUE, TRUE, offsetof(CRL_DIST_POINT,
5211 DistPointName.u.FullName.rgAltEntry), 0 },
5212 { ASN_CONTEXT | 1, offsetof(CRL_DIST_POINT, ReasonFlags),
5213 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
5214 offsetof(CRL_DIST_POINT, ReasonFlags.pbData), 0 },
5215 { ASN_CONTEXT | ASN_CONSTRUCTOR | 2, offsetof(CRL_DIST_POINT, CRLIssuer),
5216 CRYPT_AsnDecodeAltNameInternal, sizeof(CERT_ALT_NAME_INFO), TRUE, TRUE,
5217 offsetof(CRL_DIST_POINT, CRLIssuer.rgAltEntry), 0 },
5219 BOOL ret;
5221 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
5222 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
5223 dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL);
5224 return ret;
5227 static BOOL WINAPI CRYPT_AsnDecodeCRLDistPoints(DWORD dwCertEncodingType,
5228 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5229 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5231 BOOL ret;
5233 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
5234 pDecodePara, pvStructInfo, *pcbStructInfo);
5236 __TRY
5238 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
5239 CRYPT_AsnDecodeDistPoint, sizeof(CRL_DIST_POINT), TRUE,
5240 offsetof(CRL_DIST_POINT, DistPointName.u.FullName.rgAltEntry) };
5242 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
5243 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
5245 __EXCEPT_PAGE_FAULT
5247 SetLastError(STATUS_ACCESS_VIOLATION);
5248 ret = FALSE;
5250 __ENDTRY
5251 return ret;
5254 static BOOL WINAPI CRYPT_AsnDecodeEnhancedKeyUsage(DWORD dwCertEncodingType,
5255 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5256 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5258 BOOL ret;
5260 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
5261 pDecodePara, pvStructInfo, *pcbStructInfo);
5263 __TRY
5265 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
5266 CRYPT_AsnDecodeOidWrapper, sizeof(LPSTR), TRUE, 0 };
5268 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
5269 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
5271 __EXCEPT_PAGE_FAULT
5273 SetLastError(STATUS_ACCESS_VIOLATION);
5274 ret = FALSE;
5276 __ENDTRY
5277 return ret;
5280 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
5281 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5282 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5284 static HCRYPTOIDFUNCSET set = NULL;
5285 BOOL ret = FALSE;
5286 CryptDecodeObjectExFunc decodeFunc = NULL;
5287 HCRYPTOIDFUNCADDR hFunc = NULL;
5289 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
5290 dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded,
5291 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5293 if (!pvStructInfo && !pcbStructInfo)
5295 SetLastError(ERROR_INVALID_PARAMETER);
5296 return FALSE;
5298 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
5299 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
5301 SetLastError(ERROR_FILE_NOT_FOUND);
5302 return FALSE;
5304 if (!cbEncoded)
5306 SetLastError(CRYPT_E_ASN1_EOD);
5307 return FALSE;
5309 if (cbEncoded > MAX_ENCODED_LEN)
5311 SetLastError(CRYPT_E_ASN1_LARGE);
5312 return FALSE;
5315 SetLastError(NOERROR);
5316 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
5317 *(BYTE **)pvStructInfo = NULL;
5318 if (!HIWORD(lpszStructType))
5320 switch (LOWORD(lpszStructType))
5322 case (WORD)X509_CERT:
5323 decodeFunc = CRYPT_AsnDecodeCert;
5324 break;
5325 case (WORD)X509_CERT_TO_BE_SIGNED:
5326 decodeFunc = CRYPT_AsnDecodeCertInfo;
5327 break;
5328 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
5329 decodeFunc = CRYPT_AsnDecodeCRLInfo;
5330 break;
5331 case (WORD)X509_EXTENSIONS:
5332 decodeFunc = CRYPT_AsnDecodeExtensions;
5333 break;
5334 case (WORD)X509_NAME:
5335 decodeFunc = CRYPT_AsnDecodeName;
5336 break;
5337 case (WORD)X509_PUBLIC_KEY_INFO:
5338 decodeFunc = CRYPT_AsnDecodePubKeyInfo;
5339 break;
5340 case (WORD)X509_ALTERNATE_NAME:
5341 decodeFunc = CRYPT_AsnDecodeAltName;
5342 break;
5343 case (WORD)X509_BASIC_CONSTRAINTS:
5344 decodeFunc = CRYPT_AsnDecodeBasicConstraints;
5345 break;
5346 case (WORD)X509_BASIC_CONSTRAINTS2:
5347 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5348 break;
5349 case (WORD)RSA_CSP_PUBLICKEYBLOB:
5350 decodeFunc = CRYPT_AsnDecodeRsaPubKey;
5351 break;
5352 case (WORD)X509_OCTET_STRING:
5353 decodeFunc = CRYPT_AsnDecodeOctets;
5354 break;
5355 case (WORD)X509_BITS:
5356 case (WORD)X509_KEY_USAGE:
5357 decodeFunc = CRYPT_AsnDecodeBits;
5358 break;
5359 case (WORD)X509_INTEGER:
5360 decodeFunc = CRYPT_AsnDecodeInt;
5361 break;
5362 case (WORD)X509_MULTI_BYTE_INTEGER:
5363 decodeFunc = CRYPT_AsnDecodeInteger;
5364 break;
5365 case (WORD)X509_MULTI_BYTE_UINT:
5366 decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
5367 break;
5368 case (WORD)X509_ENUMERATED:
5369 decodeFunc = CRYPT_AsnDecodeEnumerated;
5370 break;
5371 case (WORD)X509_CHOICE_OF_TIME:
5372 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
5373 break;
5374 case (WORD)X509_SEQUENCE_OF_ANY:
5375 decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
5376 break;
5377 case (WORD)PKCS_UTC_TIME:
5378 decodeFunc = CRYPT_AsnDecodeUtcTime;
5379 break;
5380 case (WORD)X509_CRL_DIST_POINTS:
5381 decodeFunc = CRYPT_AsnDecodeCRLDistPoints;
5382 break;
5383 case (WORD)X509_ENHANCED_KEY_USAGE:
5384 decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage;
5385 break;
5386 default:
5387 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
5390 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
5391 decodeFunc = CRYPT_AsnDecodeExtensions;
5392 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
5393 decodeFunc = CRYPT_AsnDecodeUtcTime;
5394 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
5395 decodeFunc = CRYPT_AsnDecodeEnumerated;
5396 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
5397 decodeFunc = CRYPT_AsnDecodeBits;
5398 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
5399 decodeFunc = CRYPT_AsnDecodeOctets;
5400 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
5401 decodeFunc = CRYPT_AsnDecodeBasicConstraints;
5402 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
5403 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5404 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
5405 decodeFunc = CRYPT_AsnDecodeAltName;
5406 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
5407 decodeFunc = CRYPT_AsnDecodeAltName;
5408 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
5409 decodeFunc = CRYPT_AsnDecodeAltName;
5410 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
5411 decodeFunc = CRYPT_AsnDecodeAltName;
5412 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
5413 decodeFunc = CRYPT_AsnDecodeAltName;
5414 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
5415 decodeFunc = CRYPT_AsnDecodeCRLDistPoints;
5416 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
5417 decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage;
5418 else
5419 TRACE("OID %s not found or unimplemented, looking for DLL\n",
5420 debugstr_a(lpszStructType));
5421 if (!decodeFunc)
5423 if (!set)
5424 set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_EX_FUNC, 0);
5425 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
5426 (void **)&decodeFunc, &hFunc);
5428 if (decodeFunc)
5429 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
5430 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5431 else
5432 SetLastError(ERROR_FILE_NOT_FOUND);
5433 if (hFunc)
5434 CryptFreeOIDFunctionAddress(hFunc, 0);
5435 return ret;
5438 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
5439 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5441 return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
5442 NULL, 0, NULL, pInfo, pcbInfo);
5445 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5446 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
5447 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5449 BOOL ret;
5450 HCRYPTKEY key;
5452 TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
5453 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
5454 pInfo, pcbInfo);
5456 if (!pszPublicKeyObjId)
5457 pszPublicKeyObjId = szOID_RSA_RSA;
5458 if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
5460 DWORD keySize = 0;
5462 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
5463 if (ret)
5465 LPBYTE pubKey = CryptMemAlloc(keySize);
5467 if (pubKey)
5469 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
5470 &keySize);
5471 if (ret)
5473 DWORD encodedLen = 0;
5475 ret = CryptEncodeObject(dwCertEncodingType,
5476 RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
5477 if (ret)
5479 DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
5480 strlen(pszPublicKeyObjId) + 1 + encodedLen;
5482 if (!pInfo)
5483 *pcbInfo = sizeNeeded;
5484 else if (*pcbInfo < sizeNeeded)
5486 SetLastError(ERROR_MORE_DATA);
5487 *pcbInfo = sizeNeeded;
5488 ret = FALSE;
5490 else
5492 pInfo->Algorithm.pszObjId = (char *)pInfo +
5493 sizeof(CERT_PUBLIC_KEY_INFO);
5494 lstrcpyA(pInfo->Algorithm.pszObjId,
5495 pszPublicKeyObjId);
5496 pInfo->Algorithm.Parameters.cbData = 0;
5497 pInfo->Algorithm.Parameters.pbData = NULL;
5498 pInfo->PublicKey.pbData =
5499 (BYTE *)pInfo->Algorithm.pszObjId
5500 + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
5501 pInfo->PublicKey.cbData = encodedLen;
5502 pInfo->PublicKey.cUnusedBits = 0;
5503 ret = CryptEncodeObject(dwCertEncodingType,
5504 RSA_CSP_PUBLICKEYBLOB, pubKey,
5505 pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
5509 CryptMemFree(pubKey);
5511 else
5512 ret = FALSE;
5514 CryptDestroyKey(key);
5516 return ret;
5519 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
5520 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
5521 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
5523 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
5524 DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
5525 void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5527 static HCRYPTOIDFUNCSET set = NULL;
5528 BOOL ret;
5529 ExportPublicKeyInfoExFunc exportFunc = NULL;
5530 HCRYPTOIDFUNCADDR hFunc = NULL;
5532 TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
5533 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
5534 pInfo, pcbInfo);
5536 if (!hCryptProv)
5538 SetLastError(ERROR_INVALID_PARAMETER);
5539 return FALSE;
5542 if (pszPublicKeyObjId)
5544 if (!set)
5545 set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
5547 CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
5548 0, (void **)&exportFunc, &hFunc);
5550 if (!exportFunc)
5551 exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
5552 ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
5553 pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
5554 if (hFunc)
5555 CryptFreeOIDFunctionAddress(hFunc, 0);
5556 return ret;
5559 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
5560 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
5562 return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
5563 0, 0, NULL, phKey);
5566 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5567 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5568 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
5570 BOOL ret;
5571 DWORD pubKeySize = 0;
5573 TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
5574 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
5576 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
5577 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
5578 if (ret)
5580 LPBYTE pubKey = CryptMemAlloc(pubKeySize);
5582 if (pubKey)
5584 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
5585 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
5586 &pubKeySize);
5587 if (ret)
5588 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
5589 phKey);
5590 CryptMemFree(pubKey);
5592 else
5593 ret = FALSE;
5595 return ret;
5598 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
5599 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5600 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
5602 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5603 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5604 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
5606 static HCRYPTOIDFUNCSET set = NULL;
5607 BOOL ret;
5608 ImportPublicKeyInfoExFunc importFunc = NULL;
5609 HCRYPTOIDFUNCADDR hFunc = NULL;
5611 TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
5612 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
5614 if (!set)
5615 set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
5616 CryptGetOIDFunctionAddress(set, dwCertEncodingType,
5617 pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
5618 if (!importFunc)
5619 importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
5620 ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
5621 pvAuxInfo, phKey);
5622 if (hFunc)
5623 CryptFreeOIDFunctionAddress(hFunc, 0);
5624 return ret;