crypt32: Use the HRESULT synonyms for converted Win32 error codes.
[wine/wine64.git] / dlls / crypt32 / encode.c
blob20d411816d555ac3dbe77f3e5cab862472f6171a
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 /* Assumes algo->Parameters.pbData is set ahead of time. Internal func. */
145 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
146 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
147 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
148 /* Internal function */
149 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
150 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
151 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
152 /* Assumes the CRYPT_DATA_BLOB's pbData member has been initialized */
153 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
154 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
155 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
156 /* Like CRYPT_AsnDecodeBits, but assumes the CRYPT_INTEGER_BLOB's pbData
157 * member has been initialized, doesn't do exception handling, and doesn't do
158 * memory allocation.
160 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
161 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
162 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
163 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
164 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
165 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
166 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
167 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
168 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
169 /* Like CRYPT_AsnDecodeInteger, but assumes the CRYPT_INTEGER_BLOB's pbData
170 * member has been initialized, doesn't do exception handling, and doesn't do
171 * memory allocation.
173 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
174 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
175 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo);
176 /* Like CRYPT_AsnDecodeInteger, but unsigned. */
177 static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
178 DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
179 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
180 void *pvStructInfo, DWORD *pcbStructInfo);
182 BOOL WINAPI CryptEncodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
183 const void *pvStructInfo, BYTE *pbEncoded, DWORD *pcbEncoded)
185 static HCRYPTOIDFUNCSET set = NULL;
186 BOOL ret = FALSE;
187 HCRYPTOIDFUNCADDR hFunc;
188 CryptEncodeObjectFunc pCryptEncodeObject;
190 TRACE("(0x%08lx, %s, %p, %p, %p)\n", dwCertEncodingType,
191 debugstr_a(lpszStructType), pvStructInfo, pbEncoded,
192 pcbEncoded);
194 if (!pbEncoded && !pcbEncoded)
196 SetLastError(ERROR_INVALID_PARAMETER);
197 return FALSE;
200 /* Try registered DLL first.. */
201 if (!set)
202 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_FUNC, 0);
203 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
204 (void **)&pCryptEncodeObject, &hFunc);
205 if (pCryptEncodeObject)
207 ret = pCryptEncodeObject(dwCertEncodingType, lpszStructType,
208 pvStructInfo, pbEncoded, pcbEncoded);
209 CryptFreeOIDFunctionAddress(hFunc, 0);
211 else
213 /* If not, use CryptEncodeObjectEx */
214 ret = CryptEncodeObjectEx(dwCertEncodingType, lpszStructType,
215 pvStructInfo, 0, NULL, pbEncoded, pcbEncoded);
217 return ret;
220 /* Helper function to check *pcbEncoded, set it to the required size, and
221 * optionally to allocate memory. Assumes pbEncoded is not NULL.
222 * If CRYPT_ENCODE_ALLOC_FLAG is set in dwFlags, *pbEncoded will be set to a
223 * pointer to the newly allocated memory.
225 static BOOL CRYPT_EncodeEnsureSpace(DWORD dwFlags,
226 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded,
227 DWORD bytesNeeded)
229 BOOL ret = TRUE;
231 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
233 if (pEncodePara && pEncodePara->pfnAlloc)
234 *(BYTE **)pbEncoded = pEncodePara->pfnAlloc(bytesNeeded);
235 else
236 *(BYTE **)pbEncoded = LocalAlloc(0, bytesNeeded);
237 if (!*(BYTE **)pbEncoded)
238 ret = FALSE;
239 else
240 *pcbEncoded = bytesNeeded;
242 else if (bytesNeeded > *pcbEncoded)
244 *pcbEncoded = bytesNeeded;
245 SetLastError(ERROR_MORE_DATA);
246 ret = FALSE;
248 return ret;
251 static BOOL CRYPT_EncodeLen(DWORD len, BYTE *pbEncoded, DWORD *pcbEncoded)
253 DWORD bytesNeeded, significantBytes = 0;
255 if (len <= 0x7f)
256 bytesNeeded = 1;
257 else
259 DWORD temp;
261 for (temp = len, significantBytes = sizeof(temp); !(temp & 0xff000000);
262 temp <<= 8, significantBytes--)
264 bytesNeeded = significantBytes + 1;
266 if (!pbEncoded)
268 *pcbEncoded = bytesNeeded;
269 return TRUE;
271 if (*pcbEncoded < bytesNeeded)
273 SetLastError(ERROR_MORE_DATA);
274 return FALSE;
276 if (len <= 0x7f)
277 *pbEncoded = (BYTE)len;
278 else
280 DWORD i;
282 *pbEncoded++ = significantBytes | 0x80;
283 for (i = 0; i < significantBytes; i++)
285 *(pbEncoded + significantBytes - i - 1) = (BYTE)(len & 0xff);
286 len >>= 8;
289 *pcbEncoded = bytesNeeded;
290 return TRUE;
293 struct AsnEncodeSequenceItem
295 const void *pvStructInfo;
296 CryptEncodeObjectExFunc encodeFunc;
297 DWORD size; /* used during encoding, not for your use */
300 static BOOL WINAPI CRYPT_AsnEncodeSequence(DWORD dwCertEncodingType,
301 struct AsnEncodeSequenceItem items[], DWORD cItem, DWORD dwFlags,
302 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
304 BOOL ret;
305 DWORD i, dataLen = 0;
307 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", items, cItem, dwFlags, pEncodePara,
308 pbEncoded, *pcbEncoded);
309 for (i = 0, ret = TRUE; ret && i < cItem; i++)
311 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
312 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
313 NULL, &items[i].size);
314 /* Some functions propagate their errors through the size */
315 if (!ret)
316 *pcbEncoded = items[i].size;
317 dataLen += items[i].size;
319 if (ret)
321 DWORD lenBytes, bytesNeeded;
323 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
324 bytesNeeded = 1 + lenBytes + dataLen;
325 if (!pbEncoded)
326 *pcbEncoded = bytesNeeded;
327 else
329 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
330 pcbEncoded, bytesNeeded)))
332 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
333 pbEncoded = *(BYTE **)pbEncoded;
334 *pbEncoded++ = ASN_SEQUENCE;
335 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
336 pbEncoded += lenBytes;
337 for (i = 0; ret && i < cItem; i++)
339 ret = items[i].encodeFunc(dwCertEncodingType, NULL,
340 items[i].pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG,
341 NULL, pbEncoded, &items[i].size);
342 /* Some functions propagate their errors through the size */
343 if (!ret)
344 *pcbEncoded = items[i].size;
345 pbEncoded += items[i].size;
350 TRACE("returning %d (%08lx)\n", ret, GetLastError());
351 return ret;
354 struct AsnConstructedItem
356 BYTE tag;
357 const void *pvStructInfo;
358 CryptEncodeObjectExFunc encodeFunc;
361 static BOOL WINAPI CRYPT_AsnEncodeConstructed(DWORD dwCertEncodingType,
362 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
363 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
365 BOOL ret;
366 const struct AsnConstructedItem *item =
367 (const struct AsnConstructedItem *)pvStructInfo;
368 DWORD len;
370 if ((ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
371 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &len)))
373 DWORD dataLen, bytesNeeded;
375 CRYPT_EncodeLen(len, NULL, &dataLen);
376 bytesNeeded = 1 + dataLen + len;
377 if (!pbEncoded)
378 *pcbEncoded = bytesNeeded;
379 else if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
380 pbEncoded, pcbEncoded, bytesNeeded)))
382 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
383 pbEncoded = *(BYTE **)pbEncoded;
384 *pbEncoded++ = ASN_CONTEXT | ASN_CONSTRUCTOR | item->tag;
385 CRYPT_EncodeLen(len, pbEncoded, &dataLen);
386 pbEncoded += dataLen;
387 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
388 item->pvStructInfo, dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL,
389 pbEncoded, &len);
390 if (!ret)
392 /* Some functions propagate their errors through the size */
393 *pcbEncoded = len;
397 else
399 /* Some functions propagate their errors through the size */
400 *pcbEncoded = len;
402 return ret;
405 struct AsnEncodeTagSwappedItem
407 BYTE tag;
408 const void *pvStructInfo;
409 CryptEncodeObjectExFunc encodeFunc;
412 /* Sort of a wacky hack, it encodes something using the struct
413 * AsnEncodeTagSwappedItem's encodeFunc, then replaces the tag byte with the tag
414 * given in the struct AsnEncodeTagSwappedItem.
416 static BOOL WINAPI CRYPT_AsnEncodeSwapTag(DWORD dwCertEncodingType,
417 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
418 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
420 BOOL ret;
421 const struct AsnEncodeTagSwappedItem *item =
422 (const struct AsnEncodeTagSwappedItem *)pvStructInfo;
424 ret = item->encodeFunc(dwCertEncodingType, lpszStructType,
425 item->pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
426 if (ret && pbEncoded)
427 *pbEncoded = item->tag;
428 return ret;
431 static BOOL WINAPI CRYPT_AsnEncodeCertVersion(DWORD dwCertEncodingType,
432 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
433 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
435 const DWORD *ver = (const DWORD *)pvStructInfo;
436 BOOL ret;
438 /* CERT_V1 is not encoded */
439 if (*ver == CERT_V1)
441 *pcbEncoded = 0;
442 ret = TRUE;
444 else
446 struct AsnConstructedItem item = { 0, ver, CRYPT_AsnEncodeInt };
448 ret = CRYPT_AsnEncodeConstructed(dwCertEncodingType, X509_INTEGER,
449 &item, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
451 return ret;
454 static BOOL WINAPI CRYPT_CopyEncodedBlob(DWORD dwCertEncodingType,
455 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
456 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
458 const CRYPT_DER_BLOB *blob = (const CRYPT_DER_BLOB *)pvStructInfo;
459 BOOL ret;
461 if (!pbEncoded)
463 *pcbEncoded = blob->cbData;
464 ret = TRUE;
466 else if (*pcbEncoded < blob->cbData)
468 *pcbEncoded = blob->cbData;
469 SetLastError(ERROR_MORE_DATA);
470 ret = FALSE;
472 else
474 if (blob->cbData)
475 memcpy(pbEncoded, blob->pbData, blob->cbData);
476 *pcbEncoded = blob->cbData;
477 ret = TRUE;
479 return ret;
482 static BOOL WINAPI CRYPT_AsnEncodeValidity(DWORD dwCertEncodingType,
483 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
484 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
486 BOOL ret;
487 /* This has two filetimes in a row, a NotBefore and a NotAfter */
488 const FILETIME *timePtr = (const FILETIME *)pvStructInfo;
489 struct AsnEncodeSequenceItem items[] = {
490 { timePtr++, CRYPT_AsnEncodeChoiceOfTime, 0 },
491 { timePtr, CRYPT_AsnEncodeChoiceOfTime, 0 },
494 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
495 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
496 pcbEncoded);
497 return ret;
500 static BOOL WINAPI CRYPT_AsnEncodeAlgorithmId(
501 DWORD dwCertEncodingType, LPCSTR lpszStructType, const void *pvStructInfo,
502 DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded,
503 DWORD *pcbEncoded)
505 const CRYPT_ALGORITHM_IDENTIFIER *algo =
506 (const CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
507 BOOL ret;
508 struct AsnEncodeSequenceItem items[] = {
509 { algo->pszObjId, CRYPT_AsnEncodeOid, 0 },
510 { &algo->Parameters, CRYPT_CopyEncodedBlob, 0 },
513 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
514 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
515 pcbEncoded);
516 return ret;
519 static BOOL WINAPI CRYPT_AsnEncodePubKeyInfo(DWORD dwCertEncodingType,
520 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
521 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
523 BOOL ret;
525 __TRY
527 const CERT_PUBLIC_KEY_INFO *info =
528 (const CERT_PUBLIC_KEY_INFO *)pvStructInfo;
529 struct AsnEncodeSequenceItem items[] = {
530 { &info->Algorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
531 { &info->PublicKey, CRYPT_AsnEncodeBits, 0 },
534 TRACE("Encoding public key with OID %s\n",
535 debugstr_a(info->Algorithm.pszObjId));
536 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
537 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
538 pcbEncoded);
540 __EXCEPT_PAGE_FAULT
542 SetLastError(STATUS_ACCESS_VIOLATION);
543 ret = FALSE;
545 __ENDTRY
546 return ret;
549 static BOOL WINAPI CRYPT_AsnEncodeCert(DWORD dwCertEncodingType,
550 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
551 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
553 BOOL ret;
555 __TRY
557 const CERT_SIGNED_CONTENT_INFO *info =
558 (const CERT_SIGNED_CONTENT_INFO *)pvStructInfo;
559 struct AsnEncodeSequenceItem items[] = {
560 { &info->ToBeSigned, CRYPT_CopyEncodedBlob, 0 },
561 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
562 { &info->Signature, CRYPT_AsnEncodeBitsSwapBytes, 0 },
565 if (dwFlags & CRYPT_ENCODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
566 items[2].encodeFunc = CRYPT_AsnEncodeBits;
567 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
568 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
569 pcbEncoded);
571 __EXCEPT_PAGE_FAULT
573 SetLastError(STATUS_ACCESS_VIOLATION);
574 ret = FALSE;
576 __ENDTRY
577 return ret;
580 /* Like in Windows, this blithely ignores the validity of the passed-in
581 * CERT_INFO, and just encodes it as-is. The resulting encoded data may not
582 * decode properly, see CRYPT_AsnDecodeCertInfo.
584 static BOOL WINAPI CRYPT_AsnEncodeCertInfo(DWORD dwCertEncodingType,
585 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
586 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
588 BOOL ret;
590 __TRY
592 const CERT_INFO *info = (const CERT_INFO *)pvStructInfo;
593 struct AsnEncodeSequenceItem items[10] = {
594 { &info->dwVersion, CRYPT_AsnEncodeCertVersion, 0 },
595 { &info->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
596 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
597 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
598 { &info->NotBefore, CRYPT_AsnEncodeValidity, 0 },
599 { &info->Subject, CRYPT_CopyEncodedBlob, 0 },
600 { &info->SubjectPublicKeyInfo, CRYPT_AsnEncodePubKeyInfo, 0 },
601 { 0 }
603 struct AsnConstructedItem constructed[3] = { { 0 } };
604 DWORD cItem = 7, cConstructed = 0;
606 if (info->IssuerUniqueId.cbData)
608 constructed[cConstructed].tag = 1;
609 constructed[cConstructed].pvStructInfo = &info->IssuerUniqueId;
610 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
611 items[cItem].pvStructInfo = &constructed[cConstructed];
612 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
613 cConstructed++;
614 cItem++;
616 if (info->SubjectUniqueId.cbData)
618 constructed[cConstructed].tag = 2;
619 constructed[cConstructed].pvStructInfo = &info->SubjectUniqueId;
620 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeBits;
621 items[cItem].pvStructInfo = &constructed[cConstructed];
622 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
623 cConstructed++;
624 cItem++;
626 if (info->cExtension)
628 constructed[cConstructed].tag = 3;
629 constructed[cConstructed].pvStructInfo = &info->cExtension;
630 constructed[cConstructed].encodeFunc = CRYPT_AsnEncodeExtensions;
631 items[cItem].pvStructInfo = &constructed[cConstructed];
632 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
633 cConstructed++;
634 cItem++;
637 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
638 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
640 __EXCEPT_PAGE_FAULT
642 SetLastError(STATUS_ACCESS_VIOLATION);
643 ret = FALSE;
645 __ENDTRY
646 return ret;
649 static BOOL WINAPI CRYPT_AsnEncodeCRLEntry(const CRL_ENTRY *entry,
650 BYTE *pbEncoded, DWORD *pcbEncoded)
652 struct AsnEncodeSequenceItem items[3] = {
653 { &entry->SerialNumber, CRYPT_AsnEncodeInteger, 0 },
654 { &entry->RevocationDate, CRYPT_AsnEncodeChoiceOfTime, 0 },
655 { 0 }
657 DWORD cItem = 2;
658 BOOL ret;
660 TRACE("%p, %p, %p\n", entry, pbEncoded, pcbEncoded);
662 if (entry->cExtension)
664 items[cItem].pvStructInfo = &entry->cExtension;
665 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
666 cItem++;
669 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
670 pbEncoded, pcbEncoded);
672 TRACE("returning %d (%08lx)\n", ret, GetLastError());
673 return ret;
676 static BOOL WINAPI CRYPT_AsnEncodeCRLEntries(DWORD dwCertEncodingType,
677 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
678 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
680 DWORD cCRLEntry = *(const DWORD *)pvStructInfo;
681 DWORD bytesNeeded, dataLen, lenBytes, i;
682 const CRL_ENTRY *rgCRLEntry = *(const CRL_ENTRY **)
683 ((const BYTE *)pvStructInfo + sizeof(DWORD));
684 BOOL ret = TRUE;
686 for (i = 0, dataLen = 0; ret && i < cCRLEntry; i++)
688 DWORD size;
690 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], NULL, &size);
691 if (ret)
692 dataLen += size;
694 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
695 bytesNeeded = 1 + lenBytes + dataLen;
696 if (!pbEncoded)
697 *pcbEncoded = bytesNeeded;
698 else
700 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
701 pcbEncoded, bytesNeeded)))
703 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
704 pbEncoded = *(BYTE **)pbEncoded;
705 *pbEncoded++ = ASN_SEQUENCEOF;
706 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
707 pbEncoded += lenBytes;
708 for (i = 0; i < cCRLEntry; i++)
710 DWORD size = dataLen;
712 ret = CRYPT_AsnEncodeCRLEntry(&rgCRLEntry[i], pbEncoded, &size);
713 pbEncoded += size;
714 dataLen -= size;
718 return ret;
721 static BOOL WINAPI CRYPT_AsnEncodeCRLVersion(DWORD dwCertEncodingType,
722 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
723 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
725 const DWORD *ver = (const DWORD *)pvStructInfo;
726 BOOL ret;
728 /* CRL_V1 is not encoded */
729 if (*ver == CRL_V1)
731 *pcbEncoded = 0;
732 ret = TRUE;
734 else
735 ret = CRYPT_AsnEncodeInt(dwCertEncodingType, X509_INTEGER, ver,
736 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
737 return ret;
740 /* Like in Windows, this blithely ignores the validity of the passed-in
741 * CRL_INFO, and just encodes it as-is. The resulting encoded data may not
742 * decode properly, see CRYPT_AsnDecodeCRLInfo.
744 static BOOL WINAPI CRYPT_AsnEncodeCRLInfo(DWORD dwCertEncodingType,
745 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
746 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
748 BOOL ret;
750 __TRY
752 const CRL_INFO *info = (const CRL_INFO *)pvStructInfo;
753 struct AsnEncodeSequenceItem items[7] = {
754 { &info->dwVersion, CRYPT_AsnEncodeCRLVersion, 0 },
755 { &info->SignatureAlgorithm, CRYPT_AsnEncodeAlgorithmId, 0 },
756 { &info->Issuer, CRYPT_CopyEncodedBlob, 0 },
757 { &info->ThisUpdate, CRYPT_AsnEncodeChoiceOfTime, 0 },
758 { 0 }
760 DWORD cItem = 4;
762 if (info->NextUpdate.dwLowDateTime || info->NextUpdate.dwHighDateTime)
764 items[cItem].pvStructInfo = &info->NextUpdate;
765 items[cItem].encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
766 cItem++;
768 if (info->cCRLEntry)
770 items[cItem].pvStructInfo = &info->cCRLEntry;
771 items[cItem].encodeFunc = CRYPT_AsnEncodeCRLEntries;
772 cItem++;
774 if (info->cExtension)
776 items[cItem].pvStructInfo = &info->cExtension;
777 items[cItem].encodeFunc = CRYPT_AsnEncodeExtensions;
778 cItem++;
781 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
782 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
784 __EXCEPT_PAGE_FAULT
786 SetLastError(STATUS_ACCESS_VIOLATION);
787 ret = FALSE;
789 __ENDTRY
790 return ret;
793 static BOOL CRYPT_AsnEncodeExtension(CERT_EXTENSION *ext, BYTE *pbEncoded,
794 DWORD *pcbEncoded)
796 BOOL ret;
797 struct AsnEncodeSequenceItem items[3] = {
798 { ext->pszObjId, CRYPT_AsnEncodeOid, 0 },
799 { NULL, NULL, 0 },
800 { NULL, NULL, 0 },
802 DWORD cItem = 1;
804 TRACE("%p, %p, %ld\n", ext, pbEncoded, *pcbEncoded);
806 if (ext->fCritical)
808 items[cItem].pvStructInfo = &ext->fCritical;
809 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
810 cItem++;
812 items[cItem].pvStructInfo = &ext->Value;
813 items[cItem].encodeFunc = CRYPT_AsnEncodeOctets;
814 cItem++;
816 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
817 pbEncoded, pcbEncoded);
818 TRACE("returning %d (%08lx)\n", ret, GetLastError());
819 return ret;
822 static BOOL WINAPI CRYPT_AsnEncodeExtensions(DWORD dwCertEncodingType,
823 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
824 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
826 BOOL ret;
828 __TRY
830 DWORD bytesNeeded, dataLen, lenBytes, i;
831 const CERT_EXTENSIONS *exts = (const CERT_EXTENSIONS *)pvStructInfo;
833 ret = TRUE;
834 for (i = 0, dataLen = 0; ret && i < exts->cExtension; i++)
836 DWORD size;
838 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i], NULL, &size);
839 if (ret)
840 dataLen += size;
842 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
843 bytesNeeded = 1 + lenBytes + dataLen;
844 if (!pbEncoded)
845 *pcbEncoded = bytesNeeded;
846 else
848 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
849 pcbEncoded, bytesNeeded)))
851 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
852 pbEncoded = *(BYTE **)pbEncoded;
853 *pbEncoded++ = ASN_SEQUENCEOF;
854 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
855 pbEncoded += lenBytes;
856 for (i = 0; i < exts->cExtension; i++)
858 DWORD size = dataLen;
860 ret = CRYPT_AsnEncodeExtension(&exts->rgExtension[i],
861 pbEncoded, &size);
862 pbEncoded += size;
863 dataLen -= size;
868 __EXCEPT_PAGE_FAULT
870 SetLastError(STATUS_ACCESS_VIOLATION);
871 ret = FALSE;
873 __ENDTRY
874 return ret;
877 static BOOL WINAPI CRYPT_AsnEncodeOid(DWORD dwCertEncodingType,
878 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
879 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
881 LPCSTR pszObjId = (LPCSTR)pvStructInfo;
882 DWORD bytesNeeded = 0, lenBytes;
883 BOOL ret = TRUE;
884 int firstPos = 0;
885 BYTE firstByte = 0;
887 TRACE("%s\n", debugstr_a(pszObjId));
889 if (pszObjId)
891 const char *ptr;
892 int val1, val2;
894 if (sscanf(pszObjId, "%d.%d.%n", &val1, &val2, &firstPos) != 2)
896 SetLastError(CRYPT_E_ASN1_ERROR);
897 return FALSE;
899 bytesNeeded++;
900 firstByte = val1 * 40 + val2;
901 ptr = pszObjId + firstPos;
902 while (ret && *ptr)
904 int pos;
906 /* note I assume each component is at most 32-bits long in base 2 */
907 if (sscanf(ptr, "%d%n", &val1, &pos) == 1)
909 if (val1 >= 0x10000000)
910 bytesNeeded += 5;
911 else if (val1 >= 0x200000)
912 bytesNeeded += 4;
913 else if (val1 >= 0x4000)
914 bytesNeeded += 3;
915 else if (val1 >= 0x80)
916 bytesNeeded += 2;
917 else
918 bytesNeeded += 1;
919 ptr += pos;
920 if (*ptr == '.')
921 ptr++;
923 else
925 SetLastError(CRYPT_E_ASN1_ERROR);
926 return FALSE;
929 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
931 else
932 lenBytes = 1;
933 bytesNeeded += 1 + lenBytes;
934 if (pbEncoded)
936 if (*pcbEncoded < bytesNeeded)
938 SetLastError(ERROR_MORE_DATA);
939 ret = FALSE;
941 else
943 *pbEncoded++ = ASN_OBJECTIDENTIFIER;
944 CRYPT_EncodeLen(bytesNeeded - 1 - lenBytes, pbEncoded, &lenBytes);
945 pbEncoded += lenBytes;
946 if (pszObjId)
948 const char *ptr;
949 int val, pos;
951 *pbEncoded++ = firstByte;
952 ptr = pszObjId + firstPos;
953 while (ret && *ptr)
955 sscanf(ptr, "%d%n", &val, &pos);
957 unsigned char outBytes[5];
958 int numBytes, i;
960 if (val >= 0x10000000)
961 numBytes = 5;
962 else if (val >= 0x200000)
963 numBytes = 4;
964 else if (val >= 0x4000)
965 numBytes = 3;
966 else if (val >= 0x80)
967 numBytes = 2;
968 else
969 numBytes = 1;
970 for (i = numBytes; i > 0; i--)
972 outBytes[i - 1] = val & 0x7f;
973 val >>= 7;
975 for (i = 0; i < numBytes - 1; i++)
976 *pbEncoded++ = outBytes[i] | 0x80;
977 *pbEncoded++ = outBytes[i];
978 ptr += pos;
979 if (*ptr == '.')
980 ptr++;
986 *pcbEncoded = bytesNeeded;
987 return ret;
990 static BOOL WINAPI CRYPT_AsnEncodeNameValue(DWORD dwCertEncodingType,
991 CERT_NAME_VALUE *value, BYTE *pbEncoded, DWORD *pcbEncoded)
993 BYTE tag;
994 DWORD bytesNeeded, lenBytes, encodedLen;
995 BOOL ret = TRUE;
997 switch (value->dwValueType)
999 case CERT_RDN_NUMERIC_STRING:
1000 tag = ASN_NUMERICSTRING;
1001 encodedLen = value->Value.cbData;
1002 break;
1003 case CERT_RDN_PRINTABLE_STRING:
1004 tag = ASN_PRINTABLESTRING;
1005 encodedLen = value->Value.cbData;
1006 break;
1007 case CERT_RDN_IA5_STRING:
1008 tag = ASN_IA5STRING;
1009 encodedLen = value->Value.cbData;
1010 break;
1011 case CERT_RDN_ANY_TYPE:
1012 /* explicitly disallowed */
1013 SetLastError(E_INVALIDARG);
1014 return FALSE;
1015 default:
1016 FIXME("String type %ld unimplemented\n", value->dwValueType);
1017 return FALSE;
1019 CRYPT_EncodeLen(encodedLen, NULL, &lenBytes);
1020 bytesNeeded = 1 + lenBytes + encodedLen;
1021 if (pbEncoded)
1023 if (*pcbEncoded < bytesNeeded)
1025 SetLastError(ERROR_MORE_DATA);
1026 ret = FALSE;
1028 else
1030 *pbEncoded++ = tag;
1031 CRYPT_EncodeLen(encodedLen, pbEncoded, &lenBytes);
1032 pbEncoded += lenBytes;
1033 switch (value->dwValueType)
1035 case CERT_RDN_NUMERIC_STRING:
1036 case CERT_RDN_PRINTABLE_STRING:
1037 case CERT_RDN_IA5_STRING:
1038 memcpy(pbEncoded, value->Value.pbData, value->Value.cbData);
1042 *pcbEncoded = bytesNeeded;
1043 return ret;
1046 static BOOL WINAPI CRYPT_AsnEncodeRdnAttr(DWORD dwCertEncodingType,
1047 CERT_RDN_ATTR *attr, BYTE *pbEncoded, DWORD *pcbEncoded)
1049 DWORD bytesNeeded = 0, lenBytes, size;
1050 BOOL ret;
1052 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL, attr->pszObjId,
1053 0, NULL, NULL, &size);
1054 if (ret)
1056 bytesNeeded += size;
1057 /* hack: a CERT_RDN_ATTR is identical to a CERT_NAME_VALUE beginning
1058 * with dwValueType, so "cast" it to get its encoded size
1060 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1061 (CERT_NAME_VALUE *)&attr->dwValueType, NULL, &size);
1062 if (ret)
1064 bytesNeeded += size;
1065 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1066 bytesNeeded += 1 + lenBytes;
1067 if (pbEncoded)
1069 if (*pcbEncoded < bytesNeeded)
1071 SetLastError(ERROR_MORE_DATA);
1072 ret = FALSE;
1074 else
1076 *pbEncoded++ = ASN_SEQUENCE;
1077 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1078 &lenBytes);
1079 pbEncoded += lenBytes;
1080 size = bytesNeeded - 1 - lenBytes;
1081 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
1082 attr->pszObjId, 0, NULL, pbEncoded, &size);
1083 if (ret)
1085 pbEncoded += size;
1086 size = bytesNeeded - 1 - lenBytes - size;
1087 ret = CRYPT_AsnEncodeNameValue(dwCertEncodingType,
1088 (CERT_NAME_VALUE *)&attr->dwValueType, pbEncoded,
1089 &size);
1093 *pcbEncoded = bytesNeeded;
1096 return ret;
1099 static int BLOBComp(const void *l, const void *r)
1101 CRYPT_DER_BLOB *a = (CRYPT_DER_BLOB *)l, *b = (CRYPT_DER_BLOB *)r;
1102 int ret;
1104 if (!(ret = memcmp(a->pbData, b->pbData, min(a->cbData, b->cbData))))
1105 ret = a->cbData - b->cbData;
1106 return ret;
1109 /* This encodes as a SET OF, which in DER must be lexicographically sorted.
1111 static BOOL WINAPI CRYPT_AsnEncodeRdn(DWORD dwCertEncodingType, CERT_RDN *rdn,
1112 BYTE *pbEncoded, DWORD *pcbEncoded)
1114 BOOL ret;
1115 CRYPT_DER_BLOB *blobs = NULL;
1117 __TRY
1119 DWORD bytesNeeded = 0, lenBytes, i;
1121 blobs = NULL;
1122 ret = TRUE;
1123 if (rdn->cRDNAttr)
1125 blobs = CryptMemAlloc(rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1126 if (!blobs)
1127 ret = FALSE;
1128 else
1129 memset(blobs, 0, rdn->cRDNAttr * sizeof(CRYPT_DER_BLOB));
1131 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1133 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType, &rdn->rgRDNAttr[i],
1134 NULL, &blobs[i].cbData);
1135 if (ret)
1136 bytesNeeded += blobs[i].cbData;
1138 if (ret)
1140 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1141 bytesNeeded += 1 + lenBytes;
1142 if (pbEncoded)
1144 if (*pcbEncoded < bytesNeeded)
1146 SetLastError(ERROR_MORE_DATA);
1147 ret = FALSE;
1149 else
1151 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1153 blobs[i].pbData = CryptMemAlloc(blobs[i].cbData);
1154 if (!blobs[i].pbData)
1155 ret = FALSE;
1156 else
1157 ret = CRYPT_AsnEncodeRdnAttr(dwCertEncodingType,
1158 &rdn->rgRDNAttr[i], blobs[i].pbData,
1159 &blobs[i].cbData);
1161 if (ret)
1163 qsort(blobs, rdn->cRDNAttr, sizeof(CRYPT_DER_BLOB),
1164 BLOBComp);
1165 *pbEncoded++ = ASN_CONSTRUCTOR | ASN_SETOF;
1166 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1167 &lenBytes);
1168 pbEncoded += lenBytes;
1169 for (i = 0; ret && i < rdn->cRDNAttr; i++)
1171 memcpy(pbEncoded, blobs[i].pbData, blobs[i].cbData);
1172 pbEncoded += blobs[i].cbData;
1177 *pcbEncoded = bytesNeeded;
1179 if (blobs)
1181 for (i = 0; i < rdn->cRDNAttr; i++)
1182 CryptMemFree(blobs[i].pbData);
1185 __EXCEPT_PAGE_FAULT
1187 SetLastError(STATUS_ACCESS_VIOLATION);
1188 ret = FALSE;
1190 __ENDTRY
1191 CryptMemFree(blobs);
1192 return ret;
1195 static BOOL WINAPI CRYPT_AsnEncodeName(DWORD dwCertEncodingType,
1196 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1197 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1199 BOOL ret;
1201 __TRY
1203 const CERT_NAME_INFO *info = (const CERT_NAME_INFO *)pvStructInfo;
1204 DWORD bytesNeeded = 0, lenBytes, size, i;
1206 TRACE("encoding name with %ld RDNs\n", info->cRDN);
1207 ret = TRUE;
1208 for (i = 0; ret && i < info->cRDN; i++)
1210 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType, &info->rgRDN[i], NULL,
1211 &size);
1212 if (ret)
1213 bytesNeeded += size;
1215 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
1216 bytesNeeded += 1 + lenBytes;
1217 if (ret)
1219 if (!pbEncoded)
1220 *pcbEncoded = bytesNeeded;
1221 else
1223 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1224 pbEncoded, pcbEncoded, bytesNeeded)))
1226 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1227 pbEncoded = *(BYTE **)pbEncoded;
1228 *pbEncoded++ = ASN_SEQUENCEOF;
1229 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
1230 &lenBytes);
1231 pbEncoded += lenBytes;
1232 for (i = 0; ret && i < info->cRDN; i++)
1234 size = bytesNeeded;
1235 ret = CRYPT_AsnEncodeRdn(dwCertEncodingType,
1236 &info->rgRDN[i], pbEncoded, &size);
1237 if (ret)
1239 pbEncoded += size;
1240 bytesNeeded -= size;
1247 __EXCEPT_PAGE_FAULT
1249 SetLastError(STATUS_ACCESS_VIOLATION);
1250 ret = FALSE;
1252 __ENDTRY
1253 return ret;
1256 static BOOL WINAPI CRYPT_AsnEncodeBool(DWORD dwCertEncodingType,
1257 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1258 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1260 BOOL val = *(const BOOL *)pvStructInfo, ret;
1262 TRACE("%d\n", val);
1264 if (!pbEncoded)
1266 *pcbEncoded = 3;
1267 ret = TRUE;
1269 else if (*pcbEncoded < 3)
1271 *pcbEncoded = 3;
1272 SetLastError(ERROR_MORE_DATA);
1273 ret = FALSE;
1275 else
1277 *pcbEncoded = 3;
1278 *pbEncoded++ = ASN_BOOL;
1279 *pbEncoded++ = 1;
1280 *pbEncoded++ = val ? 0xff : 0;
1281 ret = TRUE;
1283 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1284 return ret;
1287 static BOOL CRYPT_AsnEncodeAltNameEntry(const CERT_ALT_NAME_ENTRY *entry,
1288 BYTE *pbEncoded, DWORD *pcbEncoded)
1290 BOOL ret;
1291 DWORD dataLen;
1293 ret = TRUE;
1294 switch (entry->dwAltNameChoice)
1296 case CERT_ALT_NAME_RFC822_NAME:
1297 case CERT_ALT_NAME_DNS_NAME:
1298 case CERT_ALT_NAME_URL:
1299 if (entry->u.pwszURL)
1301 DWORD i;
1303 /* Not + 1: don't encode the NULL-terminator */
1304 dataLen = lstrlenW(entry->u.pwszURL);
1305 for (i = 0; ret && i < dataLen; i++)
1307 if (entry->u.pwszURL[i] > 0x7f)
1309 SetLastError(CRYPT_E_INVALID_IA5_STRING);
1310 ret = FALSE;
1311 *pcbEncoded = i;
1315 else
1316 dataLen = 0;
1317 break;
1318 case CERT_ALT_NAME_IP_ADDRESS:
1319 dataLen = entry->u.IPAddress.cbData;
1320 break;
1321 case CERT_ALT_NAME_REGISTERED_ID:
1322 /* FIXME: encode OID */
1323 case CERT_ALT_NAME_OTHER_NAME:
1324 case CERT_ALT_NAME_DIRECTORY_NAME:
1325 FIXME("name type %ld unimplemented\n", entry->dwAltNameChoice);
1326 return FALSE;
1327 default:
1328 SetLastError(E_INVALIDARG);
1329 return FALSE;
1331 if (ret)
1333 DWORD bytesNeeded, lenBytes;
1335 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1336 bytesNeeded = 1 + dataLen + lenBytes;
1337 if (!pbEncoded)
1338 *pcbEncoded = bytesNeeded;
1339 else if (*pcbEncoded < bytesNeeded)
1341 SetLastError(ERROR_MORE_DATA);
1342 *pcbEncoded = bytesNeeded;
1343 ret = FALSE;
1345 else
1347 *pbEncoded++ = ASN_CONTEXT | (entry->dwAltNameChoice - 1);
1348 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1349 pbEncoded += lenBytes;
1350 switch (entry->dwAltNameChoice)
1352 case CERT_ALT_NAME_RFC822_NAME:
1353 case CERT_ALT_NAME_DNS_NAME:
1354 case CERT_ALT_NAME_URL:
1356 DWORD i;
1358 for (i = 0; i < dataLen; i++)
1359 *pbEncoded++ = (BYTE)entry->u.pwszURL[i];
1360 break;
1362 case CERT_ALT_NAME_IP_ADDRESS:
1363 memcpy(pbEncoded, entry->u.IPAddress.pbData, dataLen);
1364 break;
1366 if (ret)
1367 *pcbEncoded = bytesNeeded;
1370 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1371 return ret;
1374 static BOOL WINAPI CRYPT_AsnEncodeAltName(DWORD dwCertEncodingType,
1375 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1376 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1378 BOOL ret;
1380 __TRY
1382 const CERT_ALT_NAME_INFO *info =
1383 (const CERT_ALT_NAME_INFO *)pvStructInfo;
1384 DWORD bytesNeeded, dataLen, lenBytes, i;
1386 ret = TRUE;
1387 /* FIXME: should check that cAltEntry is not bigger than 0xff, since we
1388 * can't encode an erroneous entry index if it's bigger than this.
1390 for (i = 0, dataLen = 0; ret && i < info->cAltEntry; i++)
1392 DWORD len;
1394 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i], NULL,
1395 &len);
1396 if (ret)
1397 dataLen += len;
1398 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
1400 /* CRYPT_AsnEncodeAltNameEntry encoded the index of
1401 * the bad character, now set the index of the bad
1402 * entry
1404 *pcbEncoded = (BYTE)i <<
1405 CERT_ALT_NAME_ENTRY_ERR_INDEX_SHIFT | len;
1408 if (ret)
1410 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
1411 bytesNeeded = 1 + lenBytes + dataLen;
1412 if (!pbEncoded)
1414 *pcbEncoded = bytesNeeded;
1415 ret = TRUE;
1417 else
1419 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1420 pbEncoded, pcbEncoded, bytesNeeded)))
1422 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1423 pbEncoded = *(BYTE **)pbEncoded;
1424 *pbEncoded++ = ASN_SEQUENCEOF;
1425 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
1426 pbEncoded += lenBytes;
1427 for (i = 0; ret && i < info->cAltEntry; i++)
1429 DWORD len = dataLen;
1431 ret = CRYPT_AsnEncodeAltNameEntry(&info->rgAltEntry[i],
1432 pbEncoded, &len);
1433 if (ret)
1435 pbEncoded += len;
1436 dataLen -= len;
1443 __EXCEPT_PAGE_FAULT
1445 SetLastError(STATUS_ACCESS_VIOLATION);
1446 ret = FALSE;
1448 __ENDTRY
1449 return ret;
1452 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints(DWORD dwCertEncodingType,
1453 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1454 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1456 BOOL ret;
1458 __TRY
1460 const CERT_BASIC_CONSTRAINTS_INFO *info =
1461 (const CERT_BASIC_CONSTRAINTS_INFO *)pvStructInfo;
1462 struct AsnEncodeSequenceItem items[3] = {
1463 { &info->SubjectType, CRYPT_AsnEncodeBits, 0 },
1464 { 0 }
1466 DWORD cItem = 1;
1468 if (info->fPathLenConstraint)
1470 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1471 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1472 cItem++;
1474 if (info->cSubtreesConstraint)
1476 items[cItem].pvStructInfo = &info->cSubtreesConstraint;
1477 items[cItem].encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
1478 cItem++;
1480 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1481 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1483 __EXCEPT_PAGE_FAULT
1485 SetLastError(STATUS_ACCESS_VIOLATION);
1486 ret = FALSE;
1488 __ENDTRY
1489 return ret;
1492 static BOOL WINAPI CRYPT_AsnEncodeBasicConstraints2(DWORD dwCertEncodingType,
1493 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1494 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1496 BOOL ret;
1498 __TRY
1500 const CERT_BASIC_CONSTRAINTS2_INFO *info =
1501 (const CERT_BASIC_CONSTRAINTS2_INFO *)pvStructInfo;
1502 struct AsnEncodeSequenceItem items[2] = { { 0 } };
1503 DWORD cItem = 0;
1505 if (info->fCA)
1507 items[cItem].pvStructInfo = &info->fCA;
1508 items[cItem].encodeFunc = CRYPT_AsnEncodeBool;
1509 cItem++;
1511 if (info->fPathLenConstraint)
1513 items[cItem].pvStructInfo = &info->dwPathLenConstraint;
1514 items[cItem].encodeFunc = CRYPT_AsnEncodeInt;
1515 cItem++;
1517 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items, cItem,
1518 dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1520 __EXCEPT_PAGE_FAULT
1522 SetLastError(STATUS_ACCESS_VIOLATION);
1523 ret = FALSE;
1525 __ENDTRY
1526 return ret;
1529 static BOOL WINAPI CRYPT_AsnEncodeRsaPubKey(DWORD dwCertEncodingType,
1530 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1531 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1533 BOOL ret;
1535 __TRY
1537 const BLOBHEADER *hdr =
1538 (const BLOBHEADER *)pvStructInfo;
1540 if (hdr->bType != PUBLICKEYBLOB)
1542 SetLastError(E_INVALIDARG);
1543 ret = FALSE;
1545 else
1547 const RSAPUBKEY *rsaPubKey = (const RSAPUBKEY *)
1548 ((const BYTE *)pvStructInfo + sizeof(BLOBHEADER));
1549 CRYPT_INTEGER_BLOB blob = { rsaPubKey->bitlen / 8,
1550 (BYTE *)pvStructInfo + sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) };
1551 struct AsnEncodeSequenceItem items[] = {
1552 { &blob, CRYPT_AsnEncodeUnsignedInteger, 0 },
1553 { &rsaPubKey->pubexp, CRYPT_AsnEncodeInt, 0 },
1556 ret = CRYPT_AsnEncodeSequence(dwCertEncodingType, items,
1557 sizeof(items) / sizeof(items[0]), dwFlags, pEncodePara, pbEncoded,
1558 pcbEncoded);
1561 __EXCEPT_PAGE_FAULT
1563 SetLastError(STATUS_ACCESS_VIOLATION);
1564 ret = FALSE;
1566 __ENDTRY
1567 return ret;
1570 static BOOL WINAPI CRYPT_AsnEncodeOctets(DWORD dwCertEncodingType,
1571 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1572 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1574 BOOL ret;
1576 __TRY
1578 const CRYPT_DATA_BLOB *blob = (const CRYPT_DATA_BLOB *)pvStructInfo;
1579 DWORD bytesNeeded, lenBytes;
1581 TRACE("(%ld, %p), %08lx, %p, %p, %ld\n", blob->cbData, blob->pbData,
1582 dwFlags, pEncodePara, pbEncoded, *pcbEncoded);
1584 CRYPT_EncodeLen(blob->cbData, NULL, &lenBytes);
1585 bytesNeeded = 1 + lenBytes + blob->cbData;
1586 if (!pbEncoded)
1588 *pcbEncoded = bytesNeeded;
1589 ret = TRUE;
1591 else
1593 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1594 pcbEncoded, bytesNeeded)))
1596 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1597 pbEncoded = *(BYTE **)pbEncoded;
1598 *pbEncoded++ = ASN_OCTETSTRING;
1599 CRYPT_EncodeLen(blob->cbData, pbEncoded, &lenBytes);
1600 pbEncoded += lenBytes;
1601 if (blob->cbData)
1602 memcpy(pbEncoded, blob->pbData, blob->cbData);
1606 __EXCEPT_PAGE_FAULT
1608 SetLastError(STATUS_ACCESS_VIOLATION);
1609 ret = FALSE;
1611 __ENDTRY
1612 TRACE("returning %d (%08lx)\n", ret, GetLastError());
1613 return ret;
1616 static BOOL WINAPI CRYPT_AsnEncodeBits(DWORD dwCertEncodingType,
1617 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1618 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1620 BOOL ret;
1622 __TRY
1624 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1625 DWORD bytesNeeded, lenBytes, dataBytes;
1626 BYTE unusedBits;
1628 /* yep, MS allows cUnusedBits to be >= 8 */
1629 if (!blob->cUnusedBits)
1631 dataBytes = blob->cbData;
1632 unusedBits = 0;
1634 else if (blob->cbData * 8 > blob->cUnusedBits)
1636 dataBytes = (blob->cbData * 8 - blob->cUnusedBits) / 8 + 1;
1637 unusedBits = blob->cUnusedBits >= 8 ? blob->cUnusedBits / 8 :
1638 blob->cUnusedBits;
1640 else
1642 dataBytes = 0;
1643 unusedBits = 0;
1645 CRYPT_EncodeLen(dataBytes + 1, NULL, &lenBytes);
1646 bytesNeeded = 1 + lenBytes + dataBytes + 1;
1647 if (!pbEncoded)
1649 *pcbEncoded = bytesNeeded;
1650 ret = TRUE;
1652 else
1654 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1655 pcbEncoded, bytesNeeded)))
1657 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1658 pbEncoded = *(BYTE **)pbEncoded;
1659 *pbEncoded++ = ASN_BITSTRING;
1660 CRYPT_EncodeLen(dataBytes + 1, pbEncoded, &lenBytes);
1661 pbEncoded += lenBytes;
1662 *pbEncoded++ = unusedBits;
1663 if (dataBytes)
1665 BYTE mask = 0xff << unusedBits;
1667 if (dataBytes > 1)
1669 memcpy(pbEncoded, blob->pbData, dataBytes - 1);
1670 pbEncoded += dataBytes - 1;
1672 *pbEncoded = *(blob->pbData + dataBytes - 1) & mask;
1677 __EXCEPT_PAGE_FAULT
1679 SetLastError(STATUS_ACCESS_VIOLATION);
1680 ret = FALSE;
1682 __ENDTRY
1683 return ret;
1686 static BOOL WINAPI CRYPT_AsnEncodeBitsSwapBytes(DWORD dwCertEncodingType,
1687 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1688 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1690 BOOL ret;
1692 __TRY
1694 const CRYPT_BIT_BLOB *blob = (const CRYPT_BIT_BLOB *)pvStructInfo;
1695 CRYPT_BIT_BLOB newBlob = { blob->cbData, NULL, blob->cUnusedBits };
1697 ret = TRUE;
1698 if (newBlob.cbData)
1700 newBlob.pbData = CryptMemAlloc(newBlob.cbData);
1701 if (newBlob.pbData)
1703 DWORD i;
1705 for (i = 0; i < newBlob.cbData; i++)
1706 newBlob.pbData[newBlob.cbData - i - 1] = blob->pbData[i];
1708 else
1709 ret = FALSE;
1711 if (ret)
1712 ret = CRYPT_AsnEncodeBits(dwCertEncodingType, lpszStructType,
1713 &newBlob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1714 CryptMemFree(newBlob.pbData);
1716 __EXCEPT_PAGE_FAULT
1718 SetLastError(STATUS_ACCESS_VIOLATION);
1719 ret = FALSE;
1721 __ENDTRY
1722 return ret;
1725 static BOOL WINAPI CRYPT_AsnEncodeInt(DWORD dwCertEncodingType,
1726 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1727 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1729 CRYPT_INTEGER_BLOB blob = { sizeof(INT), (BYTE *)pvStructInfo };
1731 return CRYPT_AsnEncodeInteger(dwCertEncodingType, X509_MULTI_BYTE_INTEGER,
1732 &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1735 static BOOL WINAPI CRYPT_AsnEncodeInteger(DWORD dwCertEncodingType,
1736 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1737 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1739 BOOL ret;
1741 __TRY
1743 DWORD significantBytes, lenBytes;
1744 BYTE padByte = 0, bytesNeeded;
1745 BOOL pad = FALSE;
1746 const CRYPT_INTEGER_BLOB *blob =
1747 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1749 significantBytes = blob->cbData;
1750 if (significantBytes)
1752 if (blob->pbData[significantBytes - 1] & 0x80)
1754 /* negative, lop off leading (little-endian) 0xffs */
1755 for (; significantBytes > 0 &&
1756 blob->pbData[significantBytes - 1] == 0xff; significantBytes--)
1758 if (blob->pbData[significantBytes - 1] < 0x80)
1760 padByte = 0xff;
1761 pad = TRUE;
1764 else
1766 /* positive, lop off leading (little-endian) zeroes */
1767 for (; significantBytes > 0 &&
1768 !blob->pbData[significantBytes - 1]; significantBytes--)
1770 if (significantBytes == 0)
1771 significantBytes = 1;
1772 if (blob->pbData[significantBytes - 1] > 0x7f)
1774 padByte = 0;
1775 pad = TRUE;
1779 if (pad)
1780 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1781 else
1782 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1783 bytesNeeded = 1 + lenBytes + significantBytes;
1784 if (pad)
1785 bytesNeeded++;
1786 if (!pbEncoded)
1788 *pcbEncoded = bytesNeeded;
1789 ret = TRUE;
1791 else
1793 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1794 pcbEncoded, bytesNeeded)))
1796 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1797 pbEncoded = *(BYTE **)pbEncoded;
1798 *pbEncoded++ = ASN_INTEGER;
1799 if (pad)
1801 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1802 pbEncoded += lenBytes;
1803 *pbEncoded++ = padByte;
1805 else
1807 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1808 pbEncoded += lenBytes;
1810 for (; significantBytes > 0; significantBytes--)
1811 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1815 __EXCEPT_PAGE_FAULT
1817 SetLastError(STATUS_ACCESS_VIOLATION);
1818 ret = FALSE;
1820 __ENDTRY
1821 return ret;
1824 static BOOL WINAPI CRYPT_AsnEncodeUnsignedInteger(DWORD dwCertEncodingType,
1825 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1826 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1828 BOOL ret;
1830 __TRY
1832 DWORD significantBytes, lenBytes;
1833 BYTE bytesNeeded;
1834 BOOL pad = FALSE;
1835 const CRYPT_INTEGER_BLOB *blob =
1836 (const CRYPT_INTEGER_BLOB *)pvStructInfo;
1838 significantBytes = blob->cbData;
1839 if (significantBytes)
1841 /* positive, lop off leading (little-endian) zeroes */
1842 for (; significantBytes > 0 && !blob->pbData[significantBytes - 1];
1843 significantBytes--)
1845 if (significantBytes == 0)
1846 significantBytes = 1;
1847 if (blob->pbData[significantBytes - 1] > 0x7f)
1848 pad = TRUE;
1850 if (pad)
1851 CRYPT_EncodeLen(significantBytes + 1, NULL, &lenBytes);
1852 else
1853 CRYPT_EncodeLen(significantBytes, NULL, &lenBytes);
1854 bytesNeeded = 1 + lenBytes + significantBytes;
1855 if (pad)
1856 bytesNeeded++;
1857 if (!pbEncoded)
1859 *pcbEncoded = bytesNeeded;
1860 ret = TRUE;
1862 else
1864 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
1865 pcbEncoded, bytesNeeded)))
1867 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1868 pbEncoded = *(BYTE **)pbEncoded;
1869 *pbEncoded++ = ASN_INTEGER;
1870 if (pad)
1872 CRYPT_EncodeLen(significantBytes + 1, pbEncoded, &lenBytes);
1873 pbEncoded += lenBytes;
1874 *pbEncoded++ = 0;
1876 else
1878 CRYPT_EncodeLen(significantBytes, pbEncoded, &lenBytes);
1879 pbEncoded += lenBytes;
1881 for (; significantBytes > 0; significantBytes--)
1882 *(pbEncoded++) = blob->pbData[significantBytes - 1];
1886 __EXCEPT_PAGE_FAULT
1888 SetLastError(STATUS_ACCESS_VIOLATION);
1889 ret = FALSE;
1891 __ENDTRY
1892 return ret;
1895 static BOOL WINAPI CRYPT_AsnEncodeEnumerated(DWORD dwCertEncodingType,
1896 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1897 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1899 CRYPT_INTEGER_BLOB blob;
1900 BOOL ret;
1902 /* Encode as an unsigned integer, then change the tag to enumerated */
1903 blob.cbData = sizeof(DWORD);
1904 blob.pbData = (BYTE *)pvStructInfo;
1905 ret = CRYPT_AsnEncodeUnsignedInteger(dwCertEncodingType,
1906 X509_MULTI_BYTE_UINT, &blob, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
1907 if (ret && pbEncoded)
1909 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1910 pbEncoded = *(BYTE **)pbEncoded;
1911 pbEncoded[0] = ASN_ENUMERATED;
1913 return ret;
1916 static BOOL WINAPI CRYPT_AsnEncodeUtcTime(DWORD dwCertEncodingType,
1917 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1918 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1920 BOOL ret;
1922 __TRY
1924 SYSTEMTIME sysTime;
1925 /* sorry, magic number: enough for tag, len, YYMMDDHHMMSSZ\0. I use a
1926 * temporary buffer because the output buffer is not NULL-terminated.
1928 char buf[16];
1929 static const DWORD bytesNeeded = sizeof(buf) - 1;
1931 if (!pbEncoded)
1933 *pcbEncoded = bytesNeeded;
1934 ret = TRUE;
1936 else
1938 /* Sanity check the year, this is a two-digit year format */
1939 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1940 &sysTime);
1941 if (ret && (sysTime.wYear < 1950 || sysTime.wYear > 2050))
1943 SetLastError(CRYPT_E_BAD_ENCODE);
1944 ret = FALSE;
1946 if (ret)
1948 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
1949 pbEncoded, pcbEncoded, bytesNeeded)))
1951 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
1952 pbEncoded = *(BYTE **)pbEncoded;
1953 buf[0] = ASN_UTCTIME;
1954 buf[1] = bytesNeeded - 2;
1955 snprintf(buf + 2, sizeof(buf) - 2,
1956 "%02d%02d%02d%02d%02d%02dZ", sysTime.wYear >= 2000 ?
1957 sysTime.wYear - 2000 : sysTime.wYear - 1900,
1958 sysTime.wMonth, sysTime.wDay, sysTime.wHour,
1959 sysTime.wMinute, sysTime.wSecond);
1960 memcpy(pbEncoded, buf, bytesNeeded);
1965 __EXCEPT_PAGE_FAULT
1967 SetLastError(STATUS_ACCESS_VIOLATION);
1968 ret = FALSE;
1970 __ENDTRY
1971 return ret;
1974 static BOOL WINAPI CRYPT_AsnEncodeGeneralizedTime(DWORD dwCertEncodingType,
1975 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
1976 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
1978 BOOL ret;
1980 __TRY
1982 SYSTEMTIME sysTime;
1983 /* sorry, magic number: enough for tag, len, YYYYMMDDHHMMSSZ\0. I use a
1984 * temporary buffer because the output buffer is not NULL-terminated.
1986 char buf[18];
1987 static const DWORD bytesNeeded = sizeof(buf) - 1;
1989 if (!pbEncoded)
1991 *pcbEncoded = bytesNeeded;
1992 ret = TRUE;
1994 else
1996 ret = FileTimeToSystemTime((const FILETIME *)pvStructInfo,
1997 &sysTime);
1998 if (ret)
1999 ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2000 pcbEncoded, bytesNeeded);
2001 if (ret)
2003 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2004 pbEncoded = *(BYTE **)pbEncoded;
2005 buf[0] = ASN_GENERALTIME;
2006 buf[1] = bytesNeeded - 2;
2007 snprintf(buf + 2, sizeof(buf) - 2, "%04d%02d%02d%02d%02d%02dZ",
2008 sysTime.wYear, sysTime.wMonth, sysTime.wDay, sysTime.wHour,
2009 sysTime.wMinute, sysTime.wSecond);
2010 memcpy(pbEncoded, buf, bytesNeeded);
2014 __EXCEPT_PAGE_FAULT
2016 SetLastError(STATUS_ACCESS_VIOLATION);
2017 ret = FALSE;
2019 __ENDTRY
2020 return ret;
2023 static BOOL WINAPI CRYPT_AsnEncodeChoiceOfTime(DWORD dwCertEncodingType,
2024 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2025 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2027 BOOL ret;
2029 __TRY
2031 SYSTEMTIME sysTime;
2033 /* Check the year, if it's in the UTCTime range call that encode func */
2034 if (!FileTimeToSystemTime((const FILETIME *)pvStructInfo, &sysTime))
2035 return FALSE;
2036 if (sysTime.wYear >= 1950 && sysTime.wYear <= 2050)
2037 ret = CRYPT_AsnEncodeUtcTime(dwCertEncodingType, lpszStructType,
2038 pvStructInfo, dwFlags, pEncodePara, pbEncoded, pcbEncoded);
2039 else
2040 ret = CRYPT_AsnEncodeGeneralizedTime(dwCertEncodingType,
2041 lpszStructType, pvStructInfo, dwFlags, pEncodePara, pbEncoded,
2042 pcbEncoded);
2044 __EXCEPT_PAGE_FAULT
2046 SetLastError(STATUS_ACCESS_VIOLATION);
2047 ret = FALSE;
2049 __ENDTRY
2050 return ret;
2053 static BOOL WINAPI CRYPT_AsnEncodeSequenceOfAny(DWORD dwCertEncodingType,
2054 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2055 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2057 BOOL ret;
2059 __TRY
2061 DWORD bytesNeeded, dataLen, lenBytes, i;
2062 const CRYPT_SEQUENCE_OF_ANY *seq =
2063 (const CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
2065 for (i = 0, dataLen = 0; i < seq->cValue; i++)
2066 dataLen += seq->rgValue[i].cbData;
2067 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2068 bytesNeeded = 1 + lenBytes + dataLen;
2069 if (!pbEncoded)
2071 *pcbEncoded = bytesNeeded;
2072 ret = TRUE;
2074 else
2076 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara, pbEncoded,
2077 pcbEncoded, bytesNeeded)))
2079 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2080 pbEncoded = *(BYTE **)pbEncoded;
2081 *pbEncoded++ = ASN_SEQUENCEOF;
2082 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2083 pbEncoded += lenBytes;
2084 for (i = 0; i < seq->cValue; i++)
2086 memcpy(pbEncoded, seq->rgValue[i].pbData,
2087 seq->rgValue[i].cbData);
2088 pbEncoded += seq->rgValue[i].cbData;
2093 __EXCEPT_PAGE_FAULT
2095 SetLastError(STATUS_ACCESS_VIOLATION);
2096 ret = FALSE;
2098 __ENDTRY
2099 return ret;
2102 static BOOL CRYPT_AsnEncodeDistPoint(const CRL_DIST_POINT *distPoint,
2103 BYTE *pbEncoded, DWORD *pcbEncoded)
2105 BOOL ret = TRUE;
2106 struct AsnEncodeSequenceItem items[3] = { { 0 } };
2107 struct AsnConstructedItem constructed = { 0 };
2108 struct AsnEncodeTagSwappedItem swapped[3] = { { 0 } };
2109 DWORD cItem = 0, cSwapped = 0;
2111 switch (distPoint->DistPointName.dwDistPointNameChoice)
2113 case CRL_DIST_POINT_NO_NAME:
2114 /* do nothing */
2115 break;
2116 case CRL_DIST_POINT_FULL_NAME:
2117 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 0;
2118 swapped[cSwapped].pvStructInfo = &distPoint->DistPointName.u.FullName;
2119 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2120 constructed.tag = 0;
2121 constructed.pvStructInfo = &swapped[cSwapped];
2122 constructed.encodeFunc = CRYPT_AsnEncodeSwapTag;
2123 items[cItem].pvStructInfo = &constructed;
2124 items[cItem].encodeFunc = CRYPT_AsnEncodeConstructed;
2125 cSwapped++;
2126 cItem++;
2127 break;
2128 case CRL_DIST_POINT_ISSUER_RDN_NAME:
2129 FIXME("unimplemented for CRL_DIST_POINT_ISSUER_RDN_NAME\n");
2130 ret = FALSE;
2131 break;
2132 default:
2133 ret = FALSE;
2135 if (ret && distPoint->ReasonFlags.cbData)
2137 swapped[cSwapped].tag = ASN_CONTEXT | 1;
2138 swapped[cSwapped].pvStructInfo = &distPoint->ReasonFlags;
2139 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeBits;
2140 items[cItem].pvStructInfo = &swapped[cSwapped];
2141 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2142 cSwapped++;
2143 cItem++;
2145 if (ret && distPoint->CRLIssuer.cAltEntry)
2147 swapped[cSwapped].tag = ASN_CONTEXT | ASN_CONSTRUCTOR | 2;
2148 swapped[cSwapped].pvStructInfo = &distPoint->CRLIssuer;
2149 swapped[cSwapped].encodeFunc = CRYPT_AsnEncodeAltName;
2150 items[cItem].pvStructInfo = &swapped[cSwapped];
2151 items[cItem].encodeFunc = CRYPT_AsnEncodeSwapTag;
2152 cSwapped++;
2153 cItem++;
2155 if (ret)
2156 ret = CRYPT_AsnEncodeSequence(X509_ASN_ENCODING, items, cItem, 0, NULL,
2157 pbEncoded, pcbEncoded);
2158 return ret;
2161 static BOOL WINAPI CRYPT_AsnEncodeCRLDistPoints(DWORD dwCertEncodingType,
2162 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2163 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2165 BOOL ret;
2167 __TRY
2169 const CRL_DIST_POINTS_INFO *info =
2170 (const CRL_DIST_POINTS_INFO *)pvStructInfo;
2172 if (!info->cDistPoint)
2174 SetLastError(E_INVALIDARG);
2175 ret = FALSE;
2177 else
2179 DWORD bytesNeeded, dataLen, lenBytes, i;
2181 ret = TRUE;
2182 for (i = 0, dataLen = 0; ret && i < info->cDistPoint; i++)
2184 DWORD len;
2186 ret = CRYPT_AsnEncodeDistPoint(&info->rgDistPoint[i], NULL,
2187 &len);
2188 if (ret)
2189 dataLen += len;
2190 else if (GetLastError() == CRYPT_E_INVALID_IA5_STRING)
2192 /* Have to propagate index of failing character */
2193 *pcbEncoded = len;
2196 if (ret)
2198 CRYPT_EncodeLen(dataLen, NULL, &lenBytes);
2199 bytesNeeded = 1 + lenBytes + dataLen;
2200 if (!pbEncoded)
2202 *pcbEncoded = bytesNeeded;
2203 ret = TRUE;
2205 else
2207 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2208 pbEncoded, pcbEncoded, bytesNeeded)))
2210 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2211 pbEncoded = *(BYTE **)pbEncoded;
2212 *pbEncoded++ = ASN_SEQUENCEOF;
2213 CRYPT_EncodeLen(dataLen, pbEncoded, &lenBytes);
2214 pbEncoded += lenBytes;
2215 for (i = 0; ret && i < info->cDistPoint; i++)
2217 DWORD len = dataLen;
2219 ret = CRYPT_AsnEncodeDistPoint(
2220 &info->rgDistPoint[i], pbEncoded, &len);
2221 if (ret)
2223 pbEncoded += len;
2224 dataLen -= len;
2232 __EXCEPT_PAGE_FAULT
2234 SetLastError(STATUS_ACCESS_VIOLATION);
2235 ret = FALSE;
2237 __ENDTRY
2238 return ret;
2241 static BOOL WINAPI CRYPT_AsnEncodeEnhancedKeyUsage(DWORD dwCertEncodingType,
2242 LPCSTR lpszStructType, const void *pvStructInfo, DWORD dwFlags,
2243 PCRYPT_ENCODE_PARA pEncodePara, BYTE *pbEncoded, DWORD *pcbEncoded)
2245 BOOL ret;
2247 __TRY
2249 const CERT_ENHKEY_USAGE *usage =
2250 (const CERT_ENHKEY_USAGE *)pvStructInfo;
2251 DWORD bytesNeeded = 0, lenBytes, size, i;
2253 ret = TRUE;
2254 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2256 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2257 usage->rgpszUsageIdentifier[i],
2258 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &size);
2259 if (ret)
2260 bytesNeeded += size;
2262 CRYPT_EncodeLen(bytesNeeded, NULL, &lenBytes);
2263 bytesNeeded += 1 + lenBytes;
2264 if (ret)
2266 if (!pbEncoded)
2267 *pcbEncoded = bytesNeeded;
2268 else
2270 if ((ret = CRYPT_EncodeEnsureSpace(dwFlags, pEncodePara,
2271 pbEncoded, pcbEncoded, bytesNeeded)))
2273 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG)
2274 pbEncoded = *(BYTE **)pbEncoded;
2275 *pbEncoded++ = ASN_SEQUENCEOF;
2276 CRYPT_EncodeLen(bytesNeeded - lenBytes - 1, pbEncoded,
2277 &lenBytes);
2278 pbEncoded += lenBytes;
2279 for (i = 0; ret && i < usage->cUsageIdentifier; i++)
2281 size = bytesNeeded;
2282 ret = CRYPT_AsnEncodeOid(dwCertEncodingType, NULL,
2283 usage->rgpszUsageIdentifier[i],
2284 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pbEncoded,
2285 &size);
2286 if (ret)
2288 pbEncoded += size;
2289 bytesNeeded -= size;
2296 __EXCEPT_PAGE_FAULT
2298 SetLastError(STATUS_ACCESS_VIOLATION);
2299 ret = FALSE;
2301 __ENDTRY
2302 return ret;
2305 BOOL WINAPI CryptEncodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2306 const void *pvStructInfo, DWORD dwFlags, PCRYPT_ENCODE_PARA pEncodePara,
2307 void *pvEncoded, DWORD *pcbEncoded)
2309 static HCRYPTOIDFUNCSET set = NULL;
2310 BOOL ret = FALSE;
2311 CryptEncodeObjectExFunc encodeFunc = NULL;
2312 HCRYPTOIDFUNCADDR hFunc = NULL;
2314 TRACE("(0x%08lx, %s, %p, 0x%08lx, %p, %p, %p)\n", dwCertEncodingType,
2315 debugstr_a(lpszStructType), pvStructInfo, dwFlags, pEncodePara,
2316 pvEncoded, pcbEncoded);
2318 if (!pvEncoded && !pcbEncoded)
2320 SetLastError(ERROR_INVALID_PARAMETER);
2321 return FALSE;
2323 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
2324 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
2326 SetLastError(ERROR_FILE_NOT_FOUND);
2327 return FALSE;
2330 SetLastError(NOERROR);
2331 if (dwFlags & CRYPT_ENCODE_ALLOC_FLAG && pvEncoded)
2332 *(BYTE **)pvEncoded = NULL;
2333 if (!HIWORD(lpszStructType))
2335 switch (LOWORD(lpszStructType))
2337 case (WORD)X509_CERT:
2338 encodeFunc = CRYPT_AsnEncodeCert;
2339 break;
2340 case (WORD)X509_CERT_TO_BE_SIGNED:
2341 encodeFunc = CRYPT_AsnEncodeCertInfo;
2342 break;
2343 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
2344 encodeFunc = CRYPT_AsnEncodeCRLInfo;
2345 break;
2346 case (WORD)X509_EXTENSIONS:
2347 encodeFunc = CRYPT_AsnEncodeExtensions;
2348 break;
2349 case (WORD)X509_NAME:
2350 encodeFunc = CRYPT_AsnEncodeName;
2351 break;
2352 case (WORD)X509_PUBLIC_KEY_INFO:
2353 encodeFunc = CRYPT_AsnEncodePubKeyInfo;
2354 break;
2355 case (WORD)X509_ALTERNATE_NAME:
2356 encodeFunc = CRYPT_AsnEncodeAltName;
2357 break;
2358 case (WORD)X509_BASIC_CONSTRAINTS:
2359 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2360 break;
2361 case (WORD)X509_BASIC_CONSTRAINTS2:
2362 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2363 break;
2364 case (WORD)RSA_CSP_PUBLICKEYBLOB:
2365 encodeFunc = CRYPT_AsnEncodeRsaPubKey;
2366 break;
2367 case (WORD)X509_OCTET_STRING:
2368 encodeFunc = CRYPT_AsnEncodeOctets;
2369 break;
2370 case (WORD)X509_BITS:
2371 case (WORD)X509_KEY_USAGE:
2372 encodeFunc = CRYPT_AsnEncodeBits;
2373 break;
2374 case (WORD)X509_INTEGER:
2375 encodeFunc = CRYPT_AsnEncodeInt;
2376 break;
2377 case (WORD)X509_MULTI_BYTE_INTEGER:
2378 encodeFunc = CRYPT_AsnEncodeInteger;
2379 break;
2380 case (WORD)X509_MULTI_BYTE_UINT:
2381 encodeFunc = CRYPT_AsnEncodeUnsignedInteger;
2382 break;
2383 case (WORD)X509_ENUMERATED:
2384 encodeFunc = CRYPT_AsnEncodeEnumerated;
2385 break;
2386 case (WORD)X509_CHOICE_OF_TIME:
2387 encodeFunc = CRYPT_AsnEncodeChoiceOfTime;
2388 break;
2389 case (WORD)X509_SEQUENCE_OF_ANY:
2390 encodeFunc = CRYPT_AsnEncodeSequenceOfAny;
2391 break;
2392 case (WORD)PKCS_UTC_TIME:
2393 encodeFunc = CRYPT_AsnEncodeUtcTime;
2394 break;
2395 case (WORD)X509_CRL_DIST_POINTS:
2396 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2397 break;
2398 case (WORD)X509_ENHANCED_KEY_USAGE:
2399 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2400 break;
2401 default:
2402 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
2405 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
2406 encodeFunc = CRYPT_AsnEncodeExtensions;
2407 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
2408 encodeFunc = CRYPT_AsnEncodeUtcTime;
2409 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
2410 encodeFunc = CRYPT_AsnEncodeEnumerated;
2411 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
2412 encodeFunc = CRYPT_AsnEncodeBits;
2413 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
2414 encodeFunc = CRYPT_AsnEncodeOctets;
2415 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
2416 encodeFunc = CRYPT_AsnEncodeBasicConstraints;
2417 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
2418 encodeFunc = CRYPT_AsnEncodeBasicConstraints2;
2419 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
2420 encodeFunc = CRYPT_AsnEncodeAltName;
2421 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
2422 encodeFunc = CRYPT_AsnEncodeAltName;
2423 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
2424 encodeFunc = CRYPT_AsnEncodeAltName;
2425 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
2426 encodeFunc = CRYPT_AsnEncodeAltName;
2427 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
2428 encodeFunc = CRYPT_AsnEncodeAltName;
2429 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
2430 encodeFunc = CRYPT_AsnEncodeCRLDistPoints;
2431 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
2432 encodeFunc = CRYPT_AsnEncodeEnhancedKeyUsage;
2433 else
2434 TRACE("OID %s not found or unimplemented, looking for DLL\n",
2435 debugstr_a(lpszStructType));
2436 if (!encodeFunc)
2438 if (!set)
2439 set = CryptInitOIDFunctionSet(CRYPT_OID_ENCODE_OBJECT_EX_FUNC, 0);
2440 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2441 (void **)&encodeFunc, &hFunc);
2443 if (encodeFunc)
2444 ret = encodeFunc(dwCertEncodingType, lpszStructType, pvStructInfo,
2445 dwFlags, pEncodePara, pvEncoded, pcbEncoded);
2446 else
2447 SetLastError(ERROR_FILE_NOT_FOUND);
2448 if (hFunc)
2449 CryptFreeOIDFunctionAddress(hFunc, 0);
2450 return ret;
2453 BOOL WINAPI CryptDecodeObject(DWORD dwCertEncodingType, LPCSTR lpszStructType,
2454 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo,
2455 DWORD *pcbStructInfo)
2457 static HCRYPTOIDFUNCSET set = NULL;
2458 BOOL ret = FALSE;
2459 CryptDecodeObjectFunc pCryptDecodeObject;
2460 HCRYPTOIDFUNCADDR hFunc;
2462 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p)\n", dwCertEncodingType,
2463 debugstr_a(lpszStructType), pbEncoded, cbEncoded, dwFlags,
2464 pvStructInfo, pcbStructInfo);
2466 if (!pvStructInfo && !pcbStructInfo)
2468 SetLastError(ERROR_INVALID_PARAMETER);
2469 return FALSE;
2472 /* Try registered DLL first.. */
2473 if (!set)
2474 set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_FUNC, 0);
2475 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
2476 (void **)&pCryptDecodeObject, &hFunc);
2477 if (pCryptDecodeObject)
2479 ret = pCryptDecodeObject(dwCertEncodingType, lpszStructType,
2480 pbEncoded, cbEncoded, dwFlags, pvStructInfo, pcbStructInfo);
2481 CryptFreeOIDFunctionAddress(hFunc, 0);
2483 else
2485 /* If not, use CryptDecodeObjectEx */
2486 ret = CryptDecodeObjectEx(dwCertEncodingType, lpszStructType, pbEncoded,
2487 cbEncoded, dwFlags, NULL, pvStructInfo, pcbStructInfo);
2489 return ret;
2492 /* Gets the number of length bytes from the given (leading) length byte */
2493 #define GET_LEN_BYTES(b) ((b) <= 0x7f ? 1 : 1 + ((b) & 0x7f))
2495 /* Helper function to get the encoded length of the data starting at pbEncoded,
2496 * where pbEncoded[0] is the tag. If the data are too short to contain a
2497 * length or if the length is too large for cbEncoded, sets an appropriate
2498 * error code and returns FALSE.
2500 static BOOL WINAPI CRYPT_GetLen(const BYTE *pbEncoded, DWORD cbEncoded,
2501 DWORD *len)
2503 BOOL ret;
2505 if (cbEncoded <= 1)
2507 SetLastError(CRYPT_E_ASN1_CORRUPT);
2508 ret = FALSE;
2510 else if (pbEncoded[1] <= 0x7f)
2512 if (pbEncoded[1] + 1 > cbEncoded)
2514 SetLastError(CRYPT_E_ASN1_EOD);
2515 ret = FALSE;
2517 else
2519 *len = pbEncoded[1];
2520 ret = TRUE;
2523 else
2525 BYTE lenLen = GET_LEN_BYTES(pbEncoded[1]);
2527 if (lenLen > sizeof(DWORD) + 1)
2529 SetLastError(CRYPT_E_ASN1_LARGE);
2530 ret = FALSE;
2532 else if (lenLen + 2 > cbEncoded)
2534 SetLastError(CRYPT_E_ASN1_CORRUPT);
2535 ret = FALSE;
2537 else
2539 DWORD out = 0;
2541 pbEncoded += 2;
2542 while (--lenLen)
2544 out <<= 8;
2545 out |= *pbEncoded++;
2547 if (out + lenLen + 1 > cbEncoded)
2549 SetLastError(CRYPT_E_ASN1_EOD);
2550 ret = FALSE;
2552 else
2554 *len = out;
2555 ret = TRUE;
2559 return ret;
2562 /* Helper function to check *pcbStructInfo, set it to the required size, and
2563 * optionally to allocate memory. Assumes pvStructInfo is not NULL.
2564 * If CRYPT_DECODE_ALLOC_FLAG is set in dwFlags, *pvStructInfo will be set to a
2565 * pointer to the newly allocated memory.
2567 static BOOL CRYPT_DecodeEnsureSpace(DWORD dwFlags,
2568 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2569 DWORD bytesNeeded)
2571 BOOL ret = TRUE;
2573 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2575 if (pDecodePara && pDecodePara->pfnAlloc)
2576 *(BYTE **)pvStructInfo = pDecodePara->pfnAlloc(bytesNeeded);
2577 else
2578 *(BYTE **)pvStructInfo = LocalAlloc(0, bytesNeeded);
2579 if (!*(BYTE **)pvStructInfo)
2580 ret = FALSE;
2581 else
2582 *pcbStructInfo = bytesNeeded;
2584 else if (*pcbStructInfo < bytesNeeded)
2586 *pcbStructInfo = bytesNeeded;
2587 SetLastError(ERROR_MORE_DATA);
2588 ret = FALSE;
2590 return ret;
2593 /* tag:
2594 * The expected tag of the item. If tag is 0, decodeFunc is called
2595 * regardless of the tag value seen.
2596 * offset:
2597 * A sequence is decoded into a struct. The offset member is the
2598 * offset of this item within that struct.
2599 * decodeFunc:
2600 * The decoder function to use. If this is NULL, then the member isn't
2601 * decoded, but minSize space is reserved for it.
2602 * minSize:
2603 * The minimum amount of space occupied after decoding. You must set this.
2604 * optional:
2605 * If true, and the tag doesn't match the expected tag for this item,
2606 * or the decodeFunc fails with CRYPT_E_ASN1_BADTAG, then minSize space is
2607 * filled with 0 for this member.
2608 * hasPointer, pointerOffset, minSize:
2609 * If the item has dynamic data, set hasPointer to TRUE, pointerOffset to
2610 * the offset within the (outer) struct of the data pointer (or to the
2611 * first data pointer, if more than one exist).
2612 * size:
2613 * Used by CRYPT_AsnDecodeSequence, not for your use.
2615 struct AsnDecodeSequenceItem
2617 BYTE tag;
2618 DWORD offset;
2619 CryptDecodeObjectExFunc decodeFunc;
2620 DWORD minSize;
2621 BOOL optional;
2622 BOOL hasPointer;
2623 DWORD pointerOffset;
2624 DWORD size;
2627 static BOOL CRYPT_AsnDecodeSequenceItems(DWORD dwCertEncodingType,
2628 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2629 DWORD cbEncoded, DWORD dwFlags, void *pvStructInfo, BYTE *nextData)
2631 BOOL ret;
2632 DWORD i;
2633 const BYTE *ptr;
2635 ptr = pbEncoded + 1 + GET_LEN_BYTES(pbEncoded[1]);
2636 for (i = 0, ret = TRUE; ret && i < cItem; i++)
2638 if (cbEncoded - (ptr - pbEncoded) != 0)
2640 DWORD nextItemLen;
2642 if ((ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2643 &nextItemLen)))
2645 BYTE nextItemLenBytes = GET_LEN_BYTES(ptr[1]);
2647 if (ptr[0] == items[i].tag || !items[i].tag)
2649 if (nextData && pvStructInfo && items[i].hasPointer)
2651 TRACE("Setting next pointer to %p\n",
2652 nextData);
2653 *(BYTE **)((BYTE *)pvStructInfo +
2654 items[i].pointerOffset) = nextData;
2656 if (items[i].decodeFunc)
2658 if (pvStructInfo)
2659 TRACE("decoding item %ld\n", i);
2660 else
2661 TRACE("sizing item %ld\n", i);
2662 ret = items[i].decodeFunc(dwCertEncodingType,
2663 NULL, ptr, 1 + nextItemLenBytes + nextItemLen,
2664 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2665 pvStructInfo ? (BYTE *)pvStructInfo + items[i].offset
2666 : NULL, &items[i].size);
2667 if (ret)
2669 if (nextData && items[i].hasPointer &&
2670 items[i].size > items[i].minSize)
2672 nextData += items[i].size - items[i].minSize;
2673 /* align nextData to DWORD boundaries */
2674 if (items[i].size % sizeof(DWORD))
2675 nextData += sizeof(DWORD) - items[i].size %
2676 sizeof(DWORD);
2678 /* Account for alignment padding */
2679 if (items[i].size % sizeof(DWORD))
2680 items[i].size += sizeof(DWORD) -
2681 items[i].size % sizeof(DWORD);
2682 ptr += 1 + nextItemLenBytes + nextItemLen;
2684 else if (items[i].optional &&
2685 GetLastError() == CRYPT_E_ASN1_BADTAG)
2687 TRACE("skipping optional item %ld\n", i);
2688 items[i].size = items[i].minSize;
2689 SetLastError(NOERROR);
2690 ret = TRUE;
2692 else
2693 TRACE("item %ld failed: %08lx\n", i,
2694 GetLastError());
2696 else
2697 items[i].size = items[i].minSize;
2699 else if (items[i].optional)
2701 TRACE("skipping optional item %ld\n", i);
2702 items[i].size = items[i].minSize;
2704 else
2706 TRACE("tag %02x doesn't match expected %02x\n",
2707 ptr[0], items[i].tag);
2708 SetLastError(CRYPT_E_ASN1_BADTAG);
2709 ret = FALSE;
2713 else if (items[i].optional)
2715 TRACE("missing optional item %ld, skipping\n", i);
2716 items[i].size = items[i].minSize;
2718 else
2720 TRACE("not enough bytes for item %ld, failing\n", i);
2721 SetLastError(CRYPT_E_ASN1_CORRUPT);
2722 ret = FALSE;
2725 if (cbEncoded - (ptr - pbEncoded) != 0)
2727 TRACE("%ld remaining bytes, failing\n", cbEncoded -
2728 (ptr - pbEncoded));
2729 SetLastError(CRYPT_E_ASN1_CORRUPT);
2730 ret = FALSE;
2732 return ret;
2735 /* This decodes an arbitrary sequence into a contiguous block of memory
2736 * (basically, a struct.) Each element being decoded is described by a struct
2737 * AsnDecodeSequenceItem, see above.
2738 * startingPointer is an optional pointer to the first place where dynamic
2739 * data will be stored. If you know the starting offset, you may pass it
2740 * here. Otherwise, pass NULL, and one will be inferred from the items.
2741 * Each item decoder is never called with CRYPT_DECODE_ALLOC_FLAG set.
2742 * If any undecoded data are left over, fails with CRYPT_E_ASN1_CORRUPT.
2744 static BOOL CRYPT_AsnDecodeSequence(DWORD dwCertEncodingType,
2745 struct AsnDecodeSequenceItem items[], DWORD cItem, const BYTE *pbEncoded,
2746 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
2747 void *pvStructInfo, DWORD *pcbStructInfo, void *startingPointer)
2749 BOOL ret;
2751 TRACE("%p, %ld, %p, %ld, %08lx, %p, %p, %ld, %p\n", items, cItem, pbEncoded,
2752 cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
2753 startingPointer);
2755 if (pbEncoded[0] == ASN_SEQUENCE)
2757 DWORD dataLen;
2759 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2761 DWORD i;
2763 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem, pbEncoded,
2764 cbEncoded, dwFlags, NULL, NULL);
2765 if (ret)
2767 DWORD bytesNeeded = 0, structSize = 0;
2769 for (i = 0; i < cItem; i++)
2771 bytesNeeded += items[i].size;
2772 structSize += items[i].minSize;
2774 if (!pvStructInfo)
2775 *pcbStructInfo = bytesNeeded;
2776 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2777 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2779 BYTE *nextData;
2781 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2782 pvStructInfo = *(BYTE **)pvStructInfo;
2783 if (startingPointer)
2784 nextData = (BYTE *)startingPointer;
2785 else
2786 nextData = (BYTE *)pvStructInfo + structSize;
2787 memset(pvStructInfo, 0, structSize);
2788 ret = CRYPT_AsnDecodeSequenceItems(dwFlags, items, cItem,
2789 pbEncoded, cbEncoded, dwFlags, pvStructInfo, nextData);
2794 else
2796 SetLastError(CRYPT_E_ASN1_BADTAG);
2797 ret = FALSE;
2799 TRACE("returning %d (%08lx)\n", ret, GetLastError());
2800 return ret;
2803 /* tag:
2804 * The expected tag of the entire encoded array (usually a variant
2805 * of ASN_SETOF or ASN_SEQUENCEOF.)
2806 * decodeFunc:
2807 * used to decode each item in the array
2808 * itemSize:
2809 * is the minimum size of each decoded item
2810 * hasPointer:
2811 * indicates whether each item has a dynamic pointer
2812 * pointerOffset:
2813 * indicates the offset within itemSize at which the pointer exists
2815 struct AsnArrayDescriptor
2817 BYTE tag;
2818 CryptDecodeObjectExFunc decodeFunc;
2819 DWORD itemSize;
2820 BOOL hasPointer;
2821 DWORD pointerOffset;
2824 struct AsnArrayItemSize
2826 DWORD encodedLen;
2827 DWORD size;
2830 /* Decodes an array of like types into a struct GenericArray.
2831 * The layout and decoding of the array are described by a struct
2832 * AsnArrayDescriptor.
2834 static BOOL CRYPT_AsnDecodeArray(const struct AsnArrayDescriptor *arrayDesc,
2835 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2836 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo,
2837 void *startingPointer)
2839 BOOL ret = TRUE;
2841 TRACE("%p, %p, %ld, %08lx, %p, %p, %ld, %p\n", arrayDesc, pbEncoded,
2842 cbEncoded, dwFlags, pDecodePara, pvStructInfo, *pcbStructInfo,
2843 startingPointer);
2845 if (pbEncoded[0] == arrayDesc->tag)
2847 DWORD dataLen;
2849 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2851 DWORD bytesNeeded, cItems = 0;
2852 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2853 /* There can be arbitrarily many items, but there is often only one.
2855 struct AsnArrayItemSize itemSize = { 0 }, *itemSizes = &itemSize;
2857 bytesNeeded = sizeof(struct GenericArray);
2858 if (dataLen)
2860 const BYTE *ptr;
2862 for (ptr = pbEncoded + 1 + lenBytes; ret &&
2863 ptr - pbEncoded - 1 - lenBytes < dataLen; )
2865 DWORD itemLenBytes, itemDataLen, size;
2867 itemLenBytes = GET_LEN_BYTES(ptr[1]);
2868 /* Each item decoded may not tolerate extraneous bytes, so
2869 * get the length of the next element and pass it directly.
2871 ret = CRYPT_GetLen(ptr, cbEncoded - (ptr - pbEncoded),
2872 &itemDataLen);
2873 if (ret)
2874 ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr,
2875 1 + itemLenBytes + itemDataLen,
2876 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL,
2877 &size);
2878 if (ret)
2880 DWORD nextLen;
2882 cItems++;
2883 if (itemSizes != &itemSize)
2884 itemSizes = CryptMemRealloc(itemSizes,
2885 cItems * sizeof(struct AsnArrayItemSize));
2886 else
2888 itemSizes =
2889 CryptMemAlloc(
2890 cItems * sizeof(struct AsnArrayItemSize));
2891 memcpy(itemSizes, &itemSize, sizeof(itemSize));
2893 if (itemSizes)
2895 itemSizes[cItems - 1].encodedLen = 1 + itemLenBytes
2896 + itemDataLen;
2897 itemSizes[cItems - 1].size = size;
2898 bytesNeeded += size;
2899 ret = CRYPT_GetLen(ptr,
2900 cbEncoded - (ptr - pbEncoded), &nextLen);
2901 if (ret)
2902 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2904 else
2905 ret = FALSE;
2909 if (ret)
2911 if (!pvStructInfo)
2912 *pcbStructInfo = bytesNeeded;
2913 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags,
2914 pDecodePara, pvStructInfo, pcbStructInfo, bytesNeeded)))
2916 DWORD i;
2917 BYTE *nextData;
2918 const BYTE *ptr;
2919 struct GenericArray *array;
2921 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2922 pvStructInfo = *(BYTE **)pvStructInfo;
2923 array = (struct GenericArray *)pvStructInfo;
2924 array->cItems = cItems;
2925 if (startingPointer)
2926 array->rgItems = startingPointer;
2927 else
2928 array->rgItems = (BYTE *)array +
2929 sizeof(struct GenericArray);
2930 nextData = (BYTE *)array->rgItems +
2931 array->cItems * arrayDesc->itemSize;
2932 for (i = 0, ptr = pbEncoded + 1 + lenBytes; ret &&
2933 i < cItems && ptr - pbEncoded - 1 - lenBytes <
2934 dataLen; i++)
2936 if (arrayDesc->hasPointer)
2937 *(BYTE **)(array->rgItems + i * arrayDesc->itemSize
2938 + arrayDesc->pointerOffset) = nextData;
2939 ret = arrayDesc->decodeFunc(X509_ASN_ENCODING, 0, ptr,
2940 itemSizes[i].encodedLen,
2941 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL,
2942 array->rgItems + i * arrayDesc->itemSize,
2943 &itemSizes[i].size);
2944 if (ret)
2946 DWORD nextLen;
2948 nextData += itemSizes[i].size - arrayDesc->itemSize;
2949 ret = CRYPT_GetLen(ptr,
2950 cbEncoded - (ptr - pbEncoded), &nextLen);
2951 if (ret)
2952 ptr += nextLen + 1 + GET_LEN_BYTES(ptr[1]);
2957 if (itemSizes != &itemSize)
2958 CryptMemFree(itemSizes);
2961 else
2963 SetLastError(CRYPT_E_ASN1_BADTAG);
2964 ret = FALSE;
2966 return ret;
2969 /* Decodes a DER-encoded BLOB into a CRYPT_DER_BLOB struct pointed to by
2970 * pvStructInfo. The BLOB must be non-empty, otherwise the last error is set
2971 * to CRYPT_E_ASN1_CORRUPT.
2972 * Warning: assumes the CRYPT_DER_BLOB pointed to by pvStructInfo has pbData
2973 * set!
2975 static BOOL WINAPI CRYPT_AsnDecodeDerBlob(DWORD dwCertEncodingType,
2976 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
2977 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
2979 BOOL ret;
2980 DWORD dataLen;
2982 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
2984 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
2985 DWORD bytesNeeded = sizeof(CRYPT_DER_BLOB);
2987 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
2988 bytesNeeded += 1 + lenBytes + dataLen;
2990 if (!pvStructInfo)
2991 *pcbStructInfo = bytesNeeded;
2992 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
2993 pvStructInfo, pcbStructInfo, bytesNeeded)))
2995 CRYPT_DER_BLOB *blob;
2997 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
2998 pvStructInfo = *(BYTE **)pvStructInfo;
2999 blob = (CRYPT_DER_BLOB *)pvStructInfo;
3000 blob->cbData = 1 + lenBytes + dataLen;
3001 if (blob->cbData)
3003 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3004 blob->pbData = (BYTE *)pbEncoded;
3005 else
3007 assert(blob->pbData);
3008 memcpy(blob->pbData, pbEncoded, blob->cbData);
3011 else
3013 SetLastError(CRYPT_E_ASN1_CORRUPT);
3014 ret = FALSE;
3018 return ret;
3021 /* Like CRYPT_AsnDecodeBitsInternal, but swaps the bytes */
3022 static BOOL WINAPI CRYPT_AsnDecodeBitsSwapBytes(DWORD dwCertEncodingType,
3023 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3024 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3026 BOOL ret;
3028 TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
3029 pDecodePara, pvStructInfo, *pcbStructInfo);
3031 /* Can't use the CRYPT_DECODE_NOCOPY_FLAG, because we modify the bytes in-
3032 * place.
3034 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType, lpszStructType,
3035 pbEncoded, cbEncoded, dwFlags & ~CRYPT_DECODE_NOCOPY_FLAG, pDecodePara,
3036 pvStructInfo, pcbStructInfo);
3037 if (ret && pvStructInfo)
3039 CRYPT_BIT_BLOB *blob = (CRYPT_BIT_BLOB *)pvStructInfo;
3041 if (blob->cbData)
3043 DWORD i;
3044 BYTE temp;
3046 for (i = 0; i < blob->cbData / 2; i++)
3048 temp = blob->pbData[i];
3049 blob->pbData[i] = blob->pbData[blob->cbData - i - 1];
3050 blob->pbData[blob->cbData - i - 1] = temp;
3054 TRACE("returning %d (%08lx)\n", ret, GetLastError());
3055 return ret;
3058 static BOOL WINAPI CRYPT_AsnDecodeCert(DWORD dwCertEncodingType,
3059 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3060 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3062 BOOL ret = TRUE;
3064 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3065 pDecodePara, pvStructInfo, *pcbStructInfo);
3067 __TRY
3069 struct AsnDecodeSequenceItem items[] = {
3070 { 0, offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned),
3071 CRYPT_AsnDecodeDerBlob, sizeof(CRYPT_DER_BLOB), FALSE, TRUE,
3072 offsetof(CERT_SIGNED_CONTENT_INFO, ToBeSigned.pbData), 0 },
3073 { ASN_SEQUENCEOF, offsetof(CERT_SIGNED_CONTENT_INFO,
3074 SignatureAlgorithm), CRYPT_AsnDecodeAlgorithmId,
3075 sizeof(CRYPT_ALGORITHM_IDENTIFIER), FALSE, TRUE,
3076 offsetof(CERT_SIGNED_CONTENT_INFO, SignatureAlgorithm.pszObjId), 0 },
3077 { ASN_BITSTRING, offsetof(CERT_SIGNED_CONTENT_INFO, Signature),
3078 CRYPT_AsnDecodeBitsSwapBytes, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
3079 offsetof(CERT_SIGNED_CONTENT_INFO, Signature.pbData), 0 },
3082 if (dwFlags & CRYPT_DECODE_NO_SIGNATURE_BYTE_REVERSAL_FLAG)
3083 items[2].decodeFunc = CRYPT_AsnDecodeBitsInternal;
3084 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3085 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3086 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3088 __EXCEPT_PAGE_FAULT
3090 SetLastError(STATUS_ACCESS_VIOLATION);
3091 ret = FALSE;
3093 __ENDTRY
3094 return ret;
3097 /* Internal function */
3098 static BOOL WINAPI CRYPT_AsnDecodeCertVersion(DWORD dwCertEncodingType,
3099 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3100 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3102 BOOL ret;
3103 DWORD dataLen;
3105 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3107 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3109 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
3110 pbEncoded + 1 + lenBytes, dataLen, dwFlags, pDecodePara,
3111 pvStructInfo, pcbStructInfo);
3113 return ret;
3116 static BOOL WINAPI CRYPT_AsnDecodeValidity(DWORD dwCertEncodingType,
3117 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3118 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3120 BOOL ret;
3122 struct AsnDecodeSequenceItem items[] = {
3123 { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotBefore),
3124 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
3125 { 0, offsetof(CERT_PRIVATE_KEY_VALIDITY, NotAfter),
3126 CRYPT_AsnDecodeChoiceOfTime, sizeof(FILETIME), FALSE, FALSE, 0 },
3129 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3130 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3131 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3132 return ret;
3135 /* Internal function */
3136 static BOOL WINAPI CRYPT_AsnDecodeCertExtensions(DWORD dwCertEncodingType,
3137 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3138 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3140 BOOL ret;
3141 DWORD dataLen;
3143 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3145 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3147 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3148 X509_EXTENSIONS, pbEncoded + 1 + lenBytes, dataLen, dwFlags,
3149 pDecodePara, pvStructInfo, pcbStructInfo);
3151 return ret;
3154 static BOOL WINAPI CRYPT_AsnDecodeCertInfo(DWORD dwCertEncodingType,
3155 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3156 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3158 BOOL ret = TRUE;
3160 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3161 pDecodePara, pvStructInfo, *pcbStructInfo);
3163 __TRY
3165 struct AsnDecodeSequenceItem items[] = {
3166 { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CERT_INFO, dwVersion),
3167 CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 },
3168 { ASN_INTEGER, offsetof(CERT_INFO, SerialNumber),
3169 CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE,
3170 TRUE, offsetof(CERT_INFO, SerialNumber.pbData), 0 },
3171 { ASN_SEQUENCEOF, offsetof(CERT_INFO, SignatureAlgorithm),
3172 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3173 FALSE, TRUE, offsetof(CERT_INFO, SignatureAlgorithm.pszObjId), 0 },
3174 { 0, offsetof(CERT_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
3175 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
3176 Issuer.pbData) },
3177 { ASN_SEQUENCEOF, offsetof(CERT_INFO, NotBefore),
3178 CRYPT_AsnDecodeValidity, sizeof(CERT_PRIVATE_KEY_VALIDITY), FALSE,
3179 FALSE, 0 },
3180 { 0, offsetof(CERT_INFO, Subject), CRYPT_AsnDecodeDerBlob,
3181 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CERT_INFO,
3182 Subject.pbData) },
3183 { ASN_SEQUENCEOF, offsetof(CERT_INFO, SubjectPublicKeyInfo),
3184 CRYPT_AsnDecodePubKeyInfoInternal, sizeof(CERT_PUBLIC_KEY_INFO),
3185 FALSE, TRUE, offsetof(CERT_INFO,
3186 SubjectPublicKeyInfo.Algorithm.Parameters.pbData), 0 },
3187 { ASN_BITSTRING, offsetof(CERT_INFO, IssuerUniqueId),
3188 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
3189 offsetof(CERT_INFO, IssuerUniqueId.pbData), 0 },
3190 { ASN_BITSTRING, offsetof(CERT_INFO, SubjectUniqueId),
3191 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
3192 offsetof(CERT_INFO, SubjectUniqueId.pbData), 0 },
3193 { ASN_CONTEXT | ASN_CONSTRUCTOR | 3, offsetof(CERT_INFO, cExtension),
3194 CRYPT_AsnDecodeCertExtensions, sizeof(CERT_EXTENSIONS), TRUE, TRUE,
3195 offsetof(CERT_INFO, rgExtension), 0 },
3198 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3199 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3200 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3202 __EXCEPT_PAGE_FAULT
3204 SetLastError(STATUS_ACCESS_VIOLATION);
3205 ret = FALSE;
3207 __ENDTRY
3208 return ret;
3211 static BOOL WINAPI CRYPT_AsnDecodeCRLEntry(DWORD dwCertEncodingType,
3212 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3213 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3215 BOOL ret;
3216 struct AsnDecodeSequenceItem items[] = {
3217 { ASN_INTEGER, offsetof(CRL_ENTRY, SerialNumber),
3218 CRYPT_AsnDecodeIntegerInternal, sizeof(CRYPT_INTEGER_BLOB), FALSE, TRUE,
3219 offsetof(CRL_ENTRY, SerialNumber.pbData), 0 },
3220 { 0, offsetof(CRL_ENTRY, RevocationDate), CRYPT_AsnDecodeChoiceOfTime,
3221 sizeof(FILETIME), FALSE, FALSE, 0 },
3222 { ASN_SEQUENCEOF, offsetof(CRL_ENTRY, cExtension),
3223 CRYPT_AsnDecodeExtensionsInternal, sizeof(CERT_EXTENSIONS), TRUE, TRUE,
3224 offsetof(CRL_ENTRY, rgExtension), 0 },
3226 PCRL_ENTRY entry = (PCRL_ENTRY)pvStructInfo;
3228 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, entry,
3229 *pcbStructInfo);
3231 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3232 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3233 NULL, entry, pcbStructInfo, entry ? entry->SerialNumber.pbData : NULL);
3234 return ret;
3237 /* Warning: assumes pvStructInfo is a struct GenericArray whose rgItems has
3238 * been set prior to calling.
3240 static BOOL WINAPI CRYPT_AsnDecodeCRLEntries(DWORD dwCertEncodingType,
3241 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3242 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3244 BOOL ret;
3245 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
3246 CRYPT_AsnDecodeCRLEntry, sizeof(CRL_ENTRY), TRUE,
3247 offsetof(CRL_ENTRY, SerialNumber.pbData) };
3248 struct GenericArray *entries = (struct GenericArray *)pvStructInfo;
3250 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3251 pDecodePara, pvStructInfo, *pcbStructInfo);
3253 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3254 pDecodePara, pvStructInfo, pcbStructInfo,
3255 entries ? entries->rgItems : NULL);
3256 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3257 return ret;
3260 static BOOL WINAPI CRYPT_AsnDecodeCRLInfo(DWORD dwCertEncodingType,
3261 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3262 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3264 BOOL ret = TRUE;
3266 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3267 pDecodePara, pvStructInfo, *pcbStructInfo);
3269 __TRY
3271 struct AsnDecodeSequenceItem items[] = {
3272 { ASN_CONTEXT | ASN_CONSTRUCTOR, offsetof(CRL_INFO, dwVersion),
3273 CRYPT_AsnDecodeCertVersion, sizeof(DWORD), TRUE, FALSE, 0, 0 },
3274 { ASN_SEQUENCEOF, offsetof(CRL_INFO, SignatureAlgorithm),
3275 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3276 FALSE, TRUE, offsetof(CRL_INFO, SignatureAlgorithm.pszObjId), 0 },
3277 { 0, offsetof(CRL_INFO, Issuer), CRYPT_AsnDecodeDerBlob,
3278 sizeof(CRYPT_DER_BLOB), FALSE, TRUE, offsetof(CRL_INFO,
3279 Issuer.pbData) },
3280 { 0, offsetof(CRL_INFO, ThisUpdate), CRYPT_AsnDecodeChoiceOfTime,
3281 sizeof(FILETIME), FALSE, FALSE, 0 },
3282 { 0, offsetof(CRL_INFO, NextUpdate), CRYPT_AsnDecodeChoiceOfTime,
3283 sizeof(FILETIME), TRUE, FALSE, 0 },
3284 { ASN_SEQUENCEOF, offsetof(CRL_INFO, cCRLEntry),
3285 CRYPT_AsnDecodeCRLEntries, sizeof(struct GenericArray), TRUE, TRUE,
3286 offsetof(CRL_INFO, rgCRLEntry), 0 },
3287 /* Note that the extensions are ignored by MS, so I'll ignore them too
3289 { 0, offsetof(CRL_INFO, cExtension), NULL,
3290 sizeof(CERT_EXTENSIONS), TRUE, FALSE, 0 },
3293 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3294 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3295 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3297 __EXCEPT_PAGE_FAULT
3299 SetLastError(STATUS_ACCESS_VIOLATION);
3300 ret = FALSE;
3302 __ENDTRY
3304 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
3305 return ret;
3308 static BOOL WINAPI CRYPT_AsnDecodeOidInternal(DWORD dwCertEncodingType,
3309 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3310 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3312 BOOL ret = TRUE;
3314 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3315 pDecodePara, pvStructInfo, *pcbStructInfo);
3317 if (pbEncoded[0] == ASN_OBJECTIDENTIFIER)
3319 DWORD dataLen;
3321 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3323 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3324 DWORD bytesNeeded = sizeof(LPSTR);
3326 if (dataLen)
3328 /* The largest possible string for the first two components
3329 * is 2.175 (= 2 * 40 + 175 = 255), so this is big enough.
3331 char firstTwo[6];
3332 const BYTE *ptr;
3334 snprintf(firstTwo, sizeof(firstTwo), "%d.%d",
3335 pbEncoded[1 + lenBytes] / 40,
3336 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] / 40)
3337 * 40);
3338 bytesNeeded += strlen(firstTwo) + 1;
3339 for (ptr = pbEncoded + 2 + lenBytes; ret &&
3340 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3342 /* large enough for ".4000000" */
3343 char str[9];
3344 int val = 0;
3346 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3347 (*ptr & 0x80))
3349 val <<= 7;
3350 val |= *ptr & 0x7f;
3351 ptr++;
3353 if (ptr - pbEncoded - 1 - lenBytes >= dataLen ||
3354 (*ptr & 0x80))
3356 SetLastError(CRYPT_E_ASN1_CORRUPT);
3357 ret = FALSE;
3359 else
3361 val <<= 7;
3362 val |= *ptr++;
3363 snprintf(str, sizeof(str), ".%d", val);
3364 bytesNeeded += strlen(str);
3368 if (!pvStructInfo)
3369 *pcbStructInfo = bytesNeeded;
3370 else if (*pcbStructInfo < bytesNeeded)
3372 *pcbStructInfo = bytesNeeded;
3373 SetLastError(ERROR_MORE_DATA);
3374 ret = FALSE;
3376 else
3378 if (dataLen)
3380 const BYTE *ptr;
3381 LPSTR pszObjId = *(LPSTR *)pvStructInfo;
3383 *pszObjId = 0;
3384 sprintf(pszObjId, "%d.%d", pbEncoded[1 + lenBytes] / 40,
3385 pbEncoded[1 + lenBytes] - (pbEncoded[1 + lenBytes] /
3386 40) * 40);
3387 pszObjId += strlen(pszObjId);
3388 for (ptr = pbEncoded + 2 + lenBytes; ret &&
3389 ptr - pbEncoded - 1 - lenBytes < dataLen; )
3391 int val = 0;
3393 while (ptr - pbEncoded - 1 - lenBytes < dataLen &&
3394 (*ptr & 0x80))
3396 val <<= 7;
3397 val |= *ptr & 0x7f;
3398 ptr++;
3400 val <<= 7;
3401 val |= *ptr++;
3402 sprintf(pszObjId, ".%d", val);
3403 pszObjId += strlen(pszObjId);
3406 else
3407 *(LPSTR *)pvStructInfo = NULL;
3408 *pcbStructInfo = bytesNeeded;
3412 return ret;
3415 /* Warning: assumes pvStructInfo is a CERT_EXTENSION whose pszObjId is set
3416 * ahead of time!
3418 static BOOL WINAPI CRYPT_AsnDecodeExtension(DWORD dwCertEncodingType,
3419 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3420 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3422 struct AsnDecodeSequenceItem items[] = {
3423 { ASN_OBJECTIDENTIFIER, offsetof(CERT_EXTENSION, pszObjId),
3424 CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE,
3425 offsetof(CERT_EXTENSION, pszObjId), 0 },
3426 { ASN_BOOL, offsetof(CERT_EXTENSION, fCritical), CRYPT_AsnDecodeBool,
3427 sizeof(BOOL), TRUE, FALSE, 0, 0 },
3428 { ASN_OCTETSTRING, offsetof(CERT_EXTENSION, Value),
3429 CRYPT_AsnDecodeOctetsInternal, sizeof(CRYPT_OBJID_BLOB), FALSE, TRUE,
3430 offsetof(CERT_EXTENSION, Value.pbData) },
3432 BOOL ret = TRUE;
3433 PCERT_EXTENSION ext = (PCERT_EXTENSION)pvStructInfo;
3435 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags, ext,
3436 *pcbStructInfo);
3438 if (ext)
3439 TRACE("ext->pszObjId is %p\n", ext->pszObjId);
3440 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3441 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
3442 ext, pcbStructInfo, ext ? ext->pszObjId : NULL);
3443 if (ext)
3444 TRACE("ext->pszObjId is %p (%s)\n", ext->pszObjId,
3445 debugstr_a(ext->pszObjId));
3446 TRACE("returning %d (%08lx)\n", ret, GetLastError());
3447 return ret;
3450 static BOOL WINAPI CRYPT_AsnDecodeExtensionsInternal(DWORD dwCertEncodingType,
3451 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3452 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3454 BOOL ret = TRUE;
3455 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
3456 CRYPT_AsnDecodeExtension, sizeof(CERT_EXTENSION), TRUE,
3457 offsetof(CERT_EXTENSION, pszObjId) };
3458 PCERT_EXTENSIONS exts = (PCERT_EXTENSIONS)pvStructInfo;
3460 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3461 pDecodePara, pvStructInfo, *pcbStructInfo);
3463 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3464 pDecodePara, pvStructInfo, pcbStructInfo, exts ? exts->rgExtension : NULL);
3465 return ret;
3468 static BOOL WINAPI CRYPT_AsnDecodeExtensions(DWORD dwCertEncodingType,
3469 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3470 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3472 BOOL ret = TRUE;
3474 __TRY
3476 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3477 lpszStructType, pbEncoded, cbEncoded,
3478 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, pcbStructInfo);
3479 if (ret && pvStructInfo)
3481 ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara, pvStructInfo,
3482 pcbStructInfo, *pcbStructInfo);
3483 if (ret)
3485 CERT_EXTENSIONS *exts;
3487 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3488 pvStructInfo = *(BYTE **)pvStructInfo;
3489 exts = (CERT_EXTENSIONS *)pvStructInfo;
3490 exts->rgExtension = (CERT_EXTENSION *)((BYTE *)exts +
3491 sizeof(CERT_EXTENSIONS));
3492 ret = CRYPT_AsnDecodeExtensionsInternal(dwCertEncodingType,
3493 lpszStructType, pbEncoded, cbEncoded,
3494 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3495 pcbStructInfo);
3499 __EXCEPT_PAGE_FAULT
3501 SetLastError(STATUS_ACCESS_VIOLATION);
3502 ret = FALSE;
3504 __ENDTRY
3505 return ret;
3508 /* Warning: this assumes the address of value->Value.pbData is already set, in
3509 * order to avoid overwriting memory. (In some cases, it may change it, if it
3510 * doesn't copy anything to memory.) Be sure to set it correctly!
3512 static BOOL WINAPI CRYPT_AsnDecodeNameValue(DWORD dwCertEncodingType,
3513 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3514 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3516 BOOL ret = TRUE;
3518 __TRY
3520 DWORD dataLen;
3521 CERT_NAME_VALUE *value = (CERT_NAME_VALUE *)pvStructInfo;
3523 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3525 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3527 switch (pbEncoded[0])
3529 case ASN_NUMERICSTRING:
3530 case ASN_PRINTABLESTRING:
3531 case ASN_IA5STRING:
3532 break;
3533 default:
3534 FIXME("Unimplemented string type %02x\n", pbEncoded[0]);
3535 SetLastError(OSS_UNIMPLEMENTED);
3536 ret = FALSE;
3538 if (ret)
3540 DWORD bytesNeeded = sizeof(CERT_NAME_VALUE);
3542 switch (pbEncoded[0])
3544 case ASN_NUMERICSTRING:
3545 case ASN_PRINTABLESTRING:
3546 case ASN_IA5STRING:
3547 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3548 bytesNeeded += dataLen;
3549 break;
3551 if (!value)
3552 *pcbStructInfo = bytesNeeded;
3553 else if (*pcbStructInfo < bytesNeeded)
3555 *pcbStructInfo = bytesNeeded;
3556 SetLastError(ERROR_MORE_DATA);
3557 ret = FALSE;
3559 else
3561 *pcbStructInfo = bytesNeeded;
3562 switch (pbEncoded[0])
3564 case ASN_NUMERICSTRING:
3565 value->dwValueType = CERT_RDN_NUMERIC_STRING;
3566 break;
3567 case ASN_PRINTABLESTRING:
3568 value->dwValueType = CERT_RDN_PRINTABLE_STRING;
3569 break;
3570 case ASN_IA5STRING:
3571 value->dwValueType = CERT_RDN_IA5_STRING;
3572 break;
3574 if (dataLen)
3576 switch (pbEncoded[0])
3578 case ASN_NUMERICSTRING:
3579 case ASN_PRINTABLESTRING:
3580 case ASN_IA5STRING:
3581 value->Value.cbData = dataLen;
3582 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3583 value->Value.pbData = (BYTE *)pbEncoded + 1 +
3584 lenBytes;
3585 else
3587 assert(value->Value.pbData);
3588 memcpy(value->Value.pbData,
3589 pbEncoded + 1 + lenBytes, dataLen);
3591 break;
3594 else
3596 value->Value.cbData = 0;
3597 value->Value.pbData = NULL;
3603 __EXCEPT_PAGE_FAULT
3605 SetLastError(STATUS_ACCESS_VIOLATION);
3606 ret = FALSE;
3608 __ENDTRY
3609 return ret;
3612 static BOOL WINAPI CRYPT_AsnDecodeRdnAttr(DWORD dwCertEncodingType,
3613 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3614 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3616 BOOL ret;
3618 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3619 pvStructInfo, *pcbStructInfo);
3621 __TRY
3623 struct AsnDecodeSequenceItem items[] = {
3624 { ASN_OBJECTIDENTIFIER, offsetof(CERT_RDN_ATTR, pszObjId),
3625 CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE,
3626 offsetof(CERT_RDN_ATTR, pszObjId), 0 },
3627 { 0, offsetof(CERT_RDN_ATTR, dwValueType), CRYPT_AsnDecodeNameValue,
3628 sizeof(CERT_NAME_VALUE), FALSE, TRUE, offsetof(CERT_RDN_ATTR,
3629 Value.pbData), 0 },
3631 CERT_RDN_ATTR *attr = (CERT_RDN_ATTR *)pvStructInfo;
3633 if (attr)
3634 TRACE("attr->pszObjId is %p\n", attr->pszObjId);
3635 ret = CRYPT_AsnDecodeSequence(X509_ASN_ENCODING, items,
3636 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags, NULL,
3637 attr, pcbStructInfo, attr ? attr->pszObjId : NULL);
3638 if (attr)
3640 TRACE("attr->pszObjId is %p (%s)\n", attr->pszObjId,
3641 debugstr_a(attr->pszObjId));
3642 TRACE("attr->dwValueType is %ld\n", attr->dwValueType);
3644 TRACE("returning %d (%08lx)\n", ret, GetLastError());
3646 __EXCEPT_PAGE_FAULT
3648 SetLastError(STATUS_ACCESS_VIOLATION);
3649 ret = FALSE;
3651 __ENDTRY
3652 return ret;
3655 static BOOL WINAPI CRYPT_AsnDecodeRdn(DWORD dwCertEncodingType,
3656 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3657 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3659 BOOL ret = TRUE;
3661 __TRY
3663 struct AsnArrayDescriptor arrayDesc = { ASN_CONSTRUCTOR | ASN_SETOF,
3664 CRYPT_AsnDecodeRdnAttr, sizeof(CERT_RDN_ATTR), TRUE,
3665 offsetof(CERT_RDN_ATTR, pszObjId) };
3666 PCERT_RDN rdn = (PCERT_RDN)pvStructInfo;
3668 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3669 pDecodePara, pvStructInfo, pcbStructInfo, rdn ? rdn->rgRDNAttr : NULL);
3671 __EXCEPT_PAGE_FAULT
3673 SetLastError(STATUS_ACCESS_VIOLATION);
3674 ret = FALSE;
3676 __ENDTRY
3677 return ret;
3680 static BOOL WINAPI CRYPT_AsnDecodeName(DWORD dwCertEncodingType,
3681 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3682 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3684 BOOL ret = TRUE;
3686 __TRY
3688 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
3689 CRYPT_AsnDecodeRdn, sizeof(CERT_RDN), TRUE,
3690 offsetof(CERT_RDN, rgRDNAttr) };
3692 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3693 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
3695 __EXCEPT_PAGE_FAULT
3697 SetLastError(STATUS_ACCESS_VIOLATION);
3698 ret = FALSE;
3700 __ENDTRY
3701 return ret;
3704 static BOOL WINAPI CRYPT_AsnDecodeCopyBytes(DWORD dwCertEncodingType,
3705 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3706 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3708 BOOL ret = TRUE;
3709 DWORD bytesNeeded = sizeof(CRYPT_OBJID_BLOB);
3711 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3712 pDecodePara, pvStructInfo, *pcbStructInfo);
3714 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
3715 bytesNeeded += cbEncoded;
3716 if (!pvStructInfo)
3717 *pcbStructInfo = bytesNeeded;
3718 else if (*pcbStructInfo < bytesNeeded)
3720 SetLastError(ERROR_MORE_DATA);
3721 *pcbStructInfo = bytesNeeded;
3722 ret = FALSE;
3724 else
3726 PCRYPT_OBJID_BLOB blob = (PCRYPT_OBJID_BLOB)pvStructInfo;
3728 *pcbStructInfo = bytesNeeded;
3729 blob->cbData = cbEncoded;
3730 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
3731 blob->pbData = (LPBYTE)pbEncoded;
3732 else
3734 assert(blob->pbData);
3735 memcpy(blob->pbData, pbEncoded, blob->cbData);
3738 return ret;
3741 static BOOL WINAPI CRYPT_AsnDecodeAlgorithmId(DWORD dwCertEncodingType,
3742 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3743 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3745 CRYPT_ALGORITHM_IDENTIFIER *algo =
3746 (CRYPT_ALGORITHM_IDENTIFIER *)pvStructInfo;
3747 BOOL ret = TRUE;
3748 struct AsnDecodeSequenceItem items[] = {
3749 { ASN_OBJECTIDENTIFIER, offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId),
3750 CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), FALSE, TRUE,
3751 offsetof(CRYPT_ALGORITHM_IDENTIFIER, pszObjId), 0 },
3752 { 0, offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters),
3753 CRYPT_AsnDecodeCopyBytes, sizeof(CRYPT_OBJID_BLOB), TRUE, TRUE,
3754 offsetof(CRYPT_ALGORITHM_IDENTIFIER, Parameters.pbData), 0 },
3757 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3758 pDecodePara, pvStructInfo, *pcbStructInfo);
3760 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3761 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3762 pDecodePara, pvStructInfo, pcbStructInfo, algo ? algo->pszObjId : NULL);
3763 if (ret && pvStructInfo)
3765 TRACE("pszObjId is %p (%s)\n", algo->pszObjId,
3766 debugstr_a(algo->pszObjId));
3768 return ret;
3771 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfoInternal(DWORD dwCertEncodingType,
3772 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3773 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3775 BOOL ret = TRUE;
3776 struct AsnDecodeSequenceItem items[] = {
3777 { ASN_SEQUENCEOF, offsetof(CERT_PUBLIC_KEY_INFO, Algorithm),
3778 CRYPT_AsnDecodeAlgorithmId, sizeof(CRYPT_ALGORITHM_IDENTIFIER),
3779 FALSE, TRUE, offsetof(CERT_PUBLIC_KEY_INFO,
3780 Algorithm.pszObjId) },
3781 { ASN_BITSTRING, offsetof(CERT_PUBLIC_KEY_INFO, PublicKey),
3782 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
3783 offsetof(CERT_PUBLIC_KEY_INFO, PublicKey.pbData) },
3785 PCERT_PUBLIC_KEY_INFO info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo;
3787 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
3788 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
3789 pDecodePara, pvStructInfo, pcbStructInfo, info ?
3790 info->Algorithm.Parameters.pbData : NULL);
3791 return ret;
3794 static BOOL WINAPI CRYPT_AsnDecodePubKeyInfo(DWORD dwCertEncodingType,
3795 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3796 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3798 BOOL ret = TRUE;
3800 __TRY
3802 DWORD bytesNeeded;
3804 if ((ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType,
3805 lpszStructType, pbEncoded, cbEncoded,
3806 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
3808 if (!pvStructInfo)
3809 *pcbStructInfo = bytesNeeded;
3810 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
3811 pvStructInfo, pcbStructInfo, bytesNeeded)))
3813 PCERT_PUBLIC_KEY_INFO info;
3815 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
3816 pvStructInfo = *(BYTE **)pvStructInfo;
3817 info = (PCERT_PUBLIC_KEY_INFO)pvStructInfo;
3818 info->Algorithm.Parameters.pbData = (BYTE *)pvStructInfo +
3819 sizeof(CERT_PUBLIC_KEY_INFO);
3820 ret = CRYPT_AsnDecodePubKeyInfoInternal(dwCertEncodingType,
3821 lpszStructType, pbEncoded, cbEncoded,
3822 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
3823 &bytesNeeded);
3827 __EXCEPT_PAGE_FAULT
3829 SetLastError(STATUS_ACCESS_VIOLATION);
3830 ret = FALSE;
3832 __ENDTRY
3833 return ret;
3836 static BOOL WINAPI CRYPT_AsnDecodeBool(DWORD dwCertEncodingType,
3837 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3838 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3840 BOOL ret;
3842 if (cbEncoded < 3)
3844 SetLastError(CRYPT_E_ASN1_CORRUPT);
3845 return FALSE;
3847 if (GET_LEN_BYTES(pbEncoded[1]) > 1)
3849 SetLastError(CRYPT_E_ASN1_CORRUPT);
3850 return FALSE;
3852 if (pbEncoded[1] > 1)
3854 SetLastError(CRYPT_E_ASN1_CORRUPT);
3855 return FALSE;
3857 if (!pvStructInfo)
3859 *pcbStructInfo = sizeof(BOOL);
3860 ret = TRUE;
3862 else if (*pcbStructInfo < sizeof(BOOL))
3864 *pcbStructInfo = sizeof(BOOL);
3865 SetLastError(ERROR_MORE_DATA);
3866 ret = FALSE;
3868 else
3870 *(BOOL *)pvStructInfo = pbEncoded[2] ? TRUE : FALSE;
3871 ret = TRUE;
3873 TRACE("returning %d (%08lx)\n", ret, GetLastError());
3874 return ret;
3877 static BOOL WINAPI CRYPT_AsnDecodeAltNameEntry(DWORD dwCertEncodingType,
3878 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3879 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3881 PCERT_ALT_NAME_ENTRY entry = (PCERT_ALT_NAME_ENTRY)pvStructInfo;
3882 DWORD dataLen, lenBytes, bytesNeeded = sizeof(CERT_ALT_NAME_ENTRY);
3883 BOOL ret;
3885 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3886 pDecodePara, pvStructInfo, *pcbStructInfo);
3888 if (cbEncoded < 2)
3890 SetLastError(CRYPT_E_ASN1_CORRUPT);
3891 return FALSE;
3893 if ((pbEncoded[0] & ASN_FLAGS_MASK) != ASN_CONTEXT)
3895 SetLastError(CRYPT_E_ASN1_BADTAG);
3896 return FALSE;
3898 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
3899 if (1 + lenBytes > cbEncoded)
3901 SetLastError(CRYPT_E_ASN1_CORRUPT);
3902 return FALSE;
3904 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
3906 switch (pbEncoded[0] & ASN_TYPE_MASK)
3908 case 1: /* rfc822Name */
3909 case 2: /* dNSName */
3910 case 6: /* uniformResourceIdentifier */
3911 bytesNeeded += (dataLen + 1) * sizeof(WCHAR);
3912 break;
3913 case 7: /* iPAddress */
3914 bytesNeeded += dataLen;
3915 break;
3916 case 8: /* registeredID */
3917 /* FIXME: decode as OID */
3918 case 0: /* otherName */
3919 case 4: /* directoryName */
3920 FIXME("stub\n");
3921 SetLastError(CRYPT_E_ASN1_BADTAG);
3922 ret = FALSE;
3923 break;
3924 case 3: /* x400Address, unimplemented */
3925 case 5: /* ediPartyName, unimplemented */
3926 SetLastError(CRYPT_E_ASN1_BADTAG);
3927 ret = FALSE;
3928 break;
3929 default:
3930 SetLastError(CRYPT_E_ASN1_CORRUPT);
3931 ret = FALSE;
3933 if (ret)
3935 if (!entry)
3936 *pcbStructInfo = bytesNeeded;
3937 else if (*pcbStructInfo < bytesNeeded)
3939 *pcbStructInfo = bytesNeeded;
3940 SetLastError(ERROR_MORE_DATA);
3941 ret = FALSE;
3943 else
3945 *pcbStructInfo = bytesNeeded;
3946 /* MS used values one greater than the asn1 ones.. sigh */
3947 entry->dwAltNameChoice = (pbEncoded[0] & 0x7f) + 1;
3948 switch (pbEncoded[0] & ASN_TYPE_MASK)
3950 case 1: /* rfc822Name */
3951 case 2: /* dNSName */
3952 case 6: /* uniformResourceIdentifier */
3954 DWORD i;
3956 for (i = 0; i < dataLen; i++)
3957 entry->u.pwszURL[i] =
3958 (WCHAR)pbEncoded[1 + lenBytes + i];
3959 entry->u.pwszURL[i] = 0;
3960 TRACE("URL is %p (%s)\n", entry->u.pwszURL,
3961 debugstr_w(entry->u.pwszURL));
3962 break;
3964 case 7: /* iPAddress */
3965 /* The next data pointer is in the pwszURL spot, that is,
3966 * the first 4 bytes. Need to move it to the next spot.
3968 entry->u.IPAddress.pbData = (LPBYTE)entry->u.pwszURL;
3969 entry->u.IPAddress.cbData = dataLen;
3970 memcpy(entry->u.IPAddress.pbData, pbEncoded + 1 + lenBytes,
3971 dataLen);
3972 break;
3977 return ret;
3980 static BOOL WINAPI CRYPT_AsnDecodeAltNameInternal(DWORD dwCertEncodingType,
3981 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
3982 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
3984 BOOL ret = TRUE;
3985 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
3986 CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE,
3987 offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) };
3988 PCERT_ALT_NAME_INFO info = (PCERT_ALT_NAME_INFO)pvStructInfo;
3990 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
3991 pDecodePara, pvStructInfo, *pcbStructInfo);
3993 if (info)
3994 TRACE("info->rgAltEntry is %p\n", info->rgAltEntry);
3995 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
3996 pDecodePara, pvStructInfo, pcbStructInfo, info ? info->rgAltEntry : NULL);
3997 return ret;
4000 static BOOL WINAPI CRYPT_AsnDecodeAltName(DWORD dwCertEncodingType,
4001 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4002 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4004 BOOL ret = TRUE;
4006 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4007 pDecodePara, pvStructInfo, *pcbStructInfo);
4009 __TRY
4011 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
4012 CRYPT_AsnDecodeAltNameEntry, sizeof(CERT_ALT_NAME_ENTRY), TRUE,
4013 offsetof(CERT_ALT_NAME_ENTRY, u.pwszURL) };
4015 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
4016 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4018 __EXCEPT_PAGE_FAULT
4020 SetLastError(STATUS_ACCESS_VIOLATION);
4021 ret = FALSE;
4023 __ENDTRY
4024 return ret;
4027 struct PATH_LEN_CONSTRAINT
4029 BOOL fPathLenConstraint;
4030 DWORD dwPathLenConstraint;
4033 static BOOL WINAPI CRYPT_AsnDecodePathLenConstraint(DWORD dwCertEncodingType,
4034 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4035 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4037 BOOL ret = TRUE;
4039 TRACE("%p, %ld, %08lx, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4040 pvStructInfo, *pcbStructInfo);
4042 if (cbEncoded)
4044 if (pbEncoded[0] == ASN_INTEGER)
4046 DWORD bytesNeeded = sizeof(struct PATH_LEN_CONSTRAINT);
4048 if (!pvStructInfo)
4049 *pcbStructInfo = bytesNeeded;
4050 else if (*pcbStructInfo < bytesNeeded)
4052 SetLastError(ERROR_MORE_DATA);
4053 *pcbStructInfo = bytesNeeded;
4054 ret = FALSE;
4056 else
4058 struct PATH_LEN_CONSTRAINT *constraint =
4059 (struct PATH_LEN_CONSTRAINT *)pvStructInfo;
4060 DWORD size = sizeof(constraint->dwPathLenConstraint);
4062 ret = CRYPT_AsnDecodeInt(dwCertEncodingType, X509_INTEGER,
4063 pbEncoded, cbEncoded, 0, NULL,
4064 &constraint->dwPathLenConstraint, &size);
4065 if (ret)
4066 constraint->fPathLenConstraint = TRUE;
4067 TRACE("got an int, dwPathLenConstraint is %ld\n",
4068 constraint->dwPathLenConstraint);
4071 else
4073 SetLastError(CRYPT_E_ASN1_CORRUPT);
4074 ret = FALSE;
4077 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4078 return ret;
4081 static BOOL WINAPI CRYPT_AsnDecodeSubtreeConstraints(DWORD dwCertEncodingType,
4082 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4083 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4085 BOOL ret;
4086 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
4087 CRYPT_AsnDecodeCopyBytes, sizeof(CERT_NAME_BLOB), TRUE,
4088 offsetof(CERT_NAME_BLOB, pbData) };
4089 struct GenericArray *entries = (struct GenericArray *)pvStructInfo;
4091 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4092 pDecodePara, pvStructInfo, *pcbStructInfo);
4094 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
4095 pDecodePara, pvStructInfo, pcbStructInfo,
4096 entries ? entries->rgItems : NULL);
4097 TRACE("Returning %d (%08lx)\n", ret, GetLastError());
4098 return ret;
4101 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints(DWORD dwCertEncodingType,
4102 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4103 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4105 BOOL ret;
4107 __TRY
4109 struct AsnDecodeSequenceItem items[] = {
4110 { ASN_BITSTRING, offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType),
4111 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), FALSE, TRUE,
4112 offsetof(CERT_BASIC_CONSTRAINTS_INFO, SubjectType.pbData), 0 },
4113 { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS_INFO,
4114 fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint,
4115 sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 },
4116 { ASN_SEQUENCEOF, offsetof(CERT_BASIC_CONSTRAINTS_INFO,
4117 cSubtreesConstraint), CRYPT_AsnDecodeSubtreeConstraints,
4118 sizeof(struct GenericArray), TRUE, TRUE,
4119 offsetof(CERT_BASIC_CONSTRAINTS_INFO, rgSubtreesConstraint), 0 },
4122 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4123 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4124 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4126 __EXCEPT_PAGE_FAULT
4128 SetLastError(STATUS_ACCESS_VIOLATION);
4129 ret = FALSE;
4131 __ENDTRY
4132 return ret;
4135 static BOOL WINAPI CRYPT_AsnDecodeBasicConstraints2(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_BOOL, offsetof(CERT_BASIC_CONSTRAINTS2_INFO, fCA),
4145 CRYPT_AsnDecodeBool, sizeof(BOOL), TRUE, FALSE, 0, 0 },
4146 { ASN_INTEGER, offsetof(CERT_BASIC_CONSTRAINTS2_INFO,
4147 fPathLenConstraint), CRYPT_AsnDecodePathLenConstraint,
4148 sizeof(struct PATH_LEN_CONSTRAINT), TRUE, FALSE, 0, 0 },
4151 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4152 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded, dwFlags,
4153 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
4155 __EXCEPT_PAGE_FAULT
4157 SetLastError(STATUS_ACCESS_VIOLATION);
4158 ret = FALSE;
4160 __ENDTRY
4161 return ret;
4164 #define RSA1_MAGIC 0x31415352
4166 struct DECODED_RSA_PUB_KEY
4168 DWORD pubexp;
4169 CRYPT_INTEGER_BLOB modulus;
4172 static BOOL WINAPI CRYPT_AsnDecodeRsaPubKey(DWORD dwCertEncodingType,
4173 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4174 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4176 BOOL ret;
4178 __TRY
4180 struct AsnDecodeSequenceItem items[] = {
4181 { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, modulus),
4182 CRYPT_AsnDecodeUnsignedIntegerInternal, sizeof(CRYPT_INTEGER_BLOB),
4183 FALSE, TRUE, offsetof(struct DECODED_RSA_PUB_KEY, modulus.pbData),
4184 0 },
4185 { ASN_INTEGER, offsetof(struct DECODED_RSA_PUB_KEY, pubexp),
4186 CRYPT_AsnDecodeInt, sizeof(DWORD), FALSE, FALSE, 0, 0 },
4188 struct DECODED_RSA_PUB_KEY *decodedKey = NULL;
4189 DWORD size = 0;
4191 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
4192 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
4193 CRYPT_DECODE_ALLOC_FLAG, NULL, &decodedKey, &size, NULL);
4194 if (ret)
4196 DWORD bytesNeeded = sizeof(BLOBHEADER) + sizeof(RSAPUBKEY) +
4197 decodedKey->modulus.cbData;
4199 if (!pvStructInfo)
4201 *pcbStructInfo = bytesNeeded;
4202 ret = TRUE;
4204 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4205 pvStructInfo, pcbStructInfo, bytesNeeded)))
4207 BLOBHEADER *hdr;
4208 RSAPUBKEY *rsaPubKey;
4210 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4211 pvStructInfo = *(BYTE **)pvStructInfo;
4212 hdr = (BLOBHEADER *)pvStructInfo;
4213 hdr->bType = PUBLICKEYBLOB;
4214 hdr->bVersion = CUR_BLOB_VERSION;
4215 hdr->reserved = 0;
4216 hdr->aiKeyAlg = CALG_RSA_KEYX;
4217 rsaPubKey = (RSAPUBKEY *)((BYTE *)pvStructInfo +
4218 sizeof(BLOBHEADER));
4219 rsaPubKey->magic = RSA1_MAGIC;
4220 rsaPubKey->pubexp = decodedKey->pubexp;
4221 rsaPubKey->bitlen = decodedKey->modulus.cbData * 8;
4222 memcpy((BYTE *)pvStructInfo + sizeof(BLOBHEADER) +
4223 sizeof(RSAPUBKEY), decodedKey->modulus.pbData,
4224 decodedKey->modulus.cbData);
4226 LocalFree(decodedKey);
4229 __EXCEPT_PAGE_FAULT
4231 SetLastError(STATUS_ACCESS_VIOLATION);
4232 ret = FALSE;
4234 __ENDTRY
4235 return ret;
4238 static BOOL WINAPI CRYPT_AsnDecodeOctetsInternal(DWORD dwCertEncodingType,
4239 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4240 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4242 BOOL ret;
4243 DWORD bytesNeeded, dataLen;
4245 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4246 pDecodePara, pvStructInfo, *pcbStructInfo);
4248 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4250 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4251 bytesNeeded = sizeof(CRYPT_DATA_BLOB);
4252 else
4253 bytesNeeded = dataLen + sizeof(CRYPT_DATA_BLOB);
4254 if (!pvStructInfo)
4255 *pcbStructInfo = bytesNeeded;
4256 else if (*pcbStructInfo < bytesNeeded)
4258 SetLastError(ERROR_MORE_DATA);
4259 *pcbStructInfo = bytesNeeded;
4260 ret = FALSE;
4262 else
4264 CRYPT_DATA_BLOB *blob;
4265 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4267 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4268 blob->cbData = dataLen;
4269 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4270 blob->pbData = (BYTE *)pbEncoded + 1 + lenBytes;
4271 else
4273 assert(blob->pbData);
4274 if (blob->cbData)
4275 memcpy(blob->pbData, pbEncoded + 1 + lenBytes,
4276 blob->cbData);
4280 return ret;
4283 static BOOL WINAPI CRYPT_AsnDecodeOctets(DWORD dwCertEncodingType,
4284 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4285 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4287 BOOL ret;
4289 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
4290 pDecodePara, pvStructInfo, *pcbStructInfo);
4292 __TRY
4294 DWORD bytesNeeded;
4296 if (!cbEncoded)
4298 SetLastError(CRYPT_E_ASN1_CORRUPT);
4299 ret = FALSE;
4301 else if (pbEncoded[0] != ASN_OCTETSTRING)
4303 SetLastError(CRYPT_E_ASN1_BADTAG);
4304 ret = FALSE;
4306 else if ((ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4307 lpszStructType, pbEncoded, cbEncoded,
4308 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4310 if (!pvStructInfo)
4311 *pcbStructInfo = bytesNeeded;
4312 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4313 pvStructInfo, pcbStructInfo, bytesNeeded)))
4315 CRYPT_DATA_BLOB *blob;
4317 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4318 pvStructInfo = *(BYTE **)pvStructInfo;
4319 blob = (CRYPT_DATA_BLOB *)pvStructInfo;
4320 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_DATA_BLOB);
4321 ret = CRYPT_AsnDecodeOctetsInternal(dwCertEncodingType,
4322 lpszStructType, pbEncoded, cbEncoded,
4323 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4324 &bytesNeeded);
4328 __EXCEPT_PAGE_FAULT
4330 SetLastError(STATUS_ACCESS_VIOLATION);
4331 ret = FALSE;
4333 __ENDTRY
4334 return ret;
4337 static BOOL WINAPI CRYPT_AsnDecodeBitsInternal(DWORD dwCertEncodingType,
4338 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4339 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4341 BOOL ret;
4343 TRACE("(%p, %ld, 0x%08lx, %p, %p, %ld)\n", pbEncoded, cbEncoded, dwFlags,
4344 pDecodePara, pvStructInfo, *pcbStructInfo);
4346 if (pbEncoded[0] == ASN_BITSTRING)
4348 DWORD bytesNeeded, dataLen;
4350 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4352 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4353 bytesNeeded = sizeof(CRYPT_BIT_BLOB);
4354 else
4355 bytesNeeded = dataLen - 1 + sizeof(CRYPT_BIT_BLOB);
4356 if (!pvStructInfo)
4357 *pcbStructInfo = bytesNeeded;
4358 else if (*pcbStructInfo < bytesNeeded)
4360 *pcbStructInfo = bytesNeeded;
4361 SetLastError(ERROR_MORE_DATA);
4362 ret = FALSE;
4364 else
4366 CRYPT_BIT_BLOB *blob;
4368 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4369 blob->cbData = dataLen - 1;
4370 blob->cUnusedBits = *(pbEncoded + 1 +
4371 GET_LEN_BYTES(pbEncoded[1]));
4372 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
4374 blob->pbData = (BYTE *)pbEncoded + 2 +
4375 GET_LEN_BYTES(pbEncoded[1]);
4377 else
4379 assert(blob->pbData);
4380 if (blob->cbData)
4382 BYTE mask = 0xff << blob->cUnusedBits;
4384 memcpy(blob->pbData, pbEncoded + 2 +
4385 GET_LEN_BYTES(pbEncoded[1]), blob->cbData);
4386 blob->pbData[blob->cbData - 1] &= mask;
4392 else
4394 SetLastError(CRYPT_E_ASN1_BADTAG);
4395 ret = FALSE;
4397 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4398 return ret;
4401 static BOOL WINAPI CRYPT_AsnDecodeBits(DWORD dwCertEncodingType,
4402 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4403 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4405 BOOL ret;
4407 TRACE("(%p, %ld, 0x%08lx, %p, %p, %p)\n", pbEncoded, cbEncoded, dwFlags,
4408 pDecodePara, pvStructInfo, pcbStructInfo);
4410 __TRY
4412 DWORD bytesNeeded;
4414 if ((ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4415 lpszStructType, pbEncoded, cbEncoded,
4416 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4418 if (!pvStructInfo)
4419 *pcbStructInfo = bytesNeeded;
4420 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4421 pvStructInfo, pcbStructInfo, bytesNeeded)))
4423 CRYPT_BIT_BLOB *blob;
4425 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4426 pvStructInfo = *(BYTE **)pvStructInfo;
4427 blob = (CRYPT_BIT_BLOB *)pvStructInfo;
4428 blob->pbData = (BYTE *)pvStructInfo + sizeof(CRYPT_BIT_BLOB);
4429 ret = CRYPT_AsnDecodeBitsInternal(dwCertEncodingType,
4430 lpszStructType, pbEncoded, cbEncoded,
4431 dwFlags & ~CRYPT_DECODE_ALLOC_FLAG, NULL, pvStructInfo,
4432 &bytesNeeded);
4436 __EXCEPT_PAGE_FAULT
4438 SetLastError(STATUS_ACCESS_VIOLATION);
4439 ret = FALSE;
4441 __ENDTRY
4442 TRACE("returning %d (%08lx)\n", ret, GetLastError());
4443 return ret;
4446 static BOOL WINAPI CRYPT_AsnDecodeInt(DWORD dwCertEncodingType,
4447 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4448 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4450 BOOL ret;
4452 if (!pvStructInfo)
4454 *pcbStructInfo = sizeof(int);
4455 return TRUE;
4457 __TRY
4459 BYTE buf[sizeof(CRYPT_INTEGER_BLOB) + sizeof(int)];
4460 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)buf;
4461 DWORD size = sizeof(buf);
4463 blob->pbData = buf + sizeof(CRYPT_INTEGER_BLOB);
4464 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4465 X509_MULTI_BYTE_INTEGER, pbEncoded, cbEncoded, 0, NULL, &buf, &size);
4466 if (ret)
4468 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4469 pvStructInfo, pcbStructInfo, sizeof(int))))
4471 int val, i;
4473 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4474 pvStructInfo = *(BYTE **)pvStructInfo;
4475 if (blob->pbData[blob->cbData - 1] & 0x80)
4477 /* initialize to a negative value to sign-extend */
4478 val = -1;
4480 else
4481 val = 0;
4482 for (i = 0; i < blob->cbData; i++)
4484 val <<= 8;
4485 val |= blob->pbData[blob->cbData - i - 1];
4487 memcpy(pvStructInfo, &val, sizeof(int));
4490 else if (GetLastError() == ERROR_MORE_DATA)
4491 SetLastError(CRYPT_E_ASN1_LARGE);
4493 __EXCEPT_PAGE_FAULT
4495 SetLastError(STATUS_ACCESS_VIOLATION);
4496 ret = FALSE;
4498 __ENDTRY
4499 return ret;
4502 static BOOL WINAPI CRYPT_AsnDecodeIntegerInternal(DWORD dwCertEncodingType,
4503 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4504 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4506 BOOL ret;
4508 if (pbEncoded[0] == ASN_INTEGER)
4510 DWORD bytesNeeded, dataLen;
4512 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4514 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4516 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4517 if (!pvStructInfo)
4518 *pcbStructInfo = bytesNeeded;
4519 else if (*pcbStructInfo < bytesNeeded)
4521 *pcbStructInfo = bytesNeeded;
4522 SetLastError(ERROR_MORE_DATA);
4523 ret = FALSE;
4525 else
4527 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4529 blob->cbData = dataLen;
4530 assert(blob->pbData);
4531 if (blob->cbData)
4533 DWORD i;
4535 for (i = 0; i < blob->cbData; i++)
4537 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4538 dataLen - i - 1);
4544 else
4546 SetLastError(CRYPT_E_ASN1_BADTAG);
4547 ret = FALSE;
4549 return ret;
4552 static BOOL WINAPI CRYPT_AsnDecodeInteger(DWORD dwCertEncodingType,
4553 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4554 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4556 BOOL ret;
4558 __TRY
4560 DWORD bytesNeeded;
4562 if ((ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4563 lpszStructType, pbEncoded, cbEncoded,
4564 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4566 if (!pvStructInfo)
4567 *pcbStructInfo = bytesNeeded;
4568 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4569 pvStructInfo, pcbStructInfo, bytesNeeded)))
4571 CRYPT_INTEGER_BLOB *blob;
4573 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4574 pvStructInfo = *(BYTE **)pvStructInfo;
4575 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4576 blob->pbData = (BYTE *)pvStructInfo +
4577 sizeof(CRYPT_INTEGER_BLOB);
4578 ret = CRYPT_AsnDecodeIntegerInternal(dwCertEncodingType,
4579 lpszStructType, pbEncoded, cbEncoded,
4580 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4581 &bytesNeeded);
4585 __EXCEPT_PAGE_FAULT
4587 SetLastError(STATUS_ACCESS_VIOLATION);
4588 ret = FALSE;
4590 __ENDTRY
4591 return ret;
4594 static BOOL WINAPI CRYPT_AsnDecodeUnsignedIntegerInternal(
4595 DWORD dwCertEncodingType, LPCSTR lpszStructType, const BYTE *pbEncoded,
4596 DWORD cbEncoded, DWORD dwFlags, PCRYPT_DECODE_PARA pDecodePara,
4597 void *pvStructInfo, DWORD *pcbStructInfo)
4599 BOOL ret;
4601 if (pbEncoded[0] == ASN_INTEGER)
4603 DWORD bytesNeeded, dataLen;
4605 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
4607 BYTE lenBytes = GET_LEN_BYTES(pbEncoded[1]);
4609 bytesNeeded = dataLen + sizeof(CRYPT_INTEGER_BLOB);
4610 if (!pvStructInfo)
4611 *pcbStructInfo = bytesNeeded;
4612 else if (*pcbStructInfo < bytesNeeded)
4614 *pcbStructInfo = bytesNeeded;
4615 SetLastError(ERROR_MORE_DATA);
4616 ret = FALSE;
4618 else
4620 CRYPT_INTEGER_BLOB *blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4622 blob->cbData = dataLen;
4623 assert(blob->pbData);
4624 /* remove leading zero byte if it exists */
4625 if (blob->cbData && *(pbEncoded + 1 + lenBytes) == 0)
4627 blob->cbData--;
4628 blob->pbData++;
4630 if (blob->cbData)
4632 DWORD i;
4634 for (i = 0; i < blob->cbData; i++)
4636 blob->pbData[i] = *(pbEncoded + 1 + lenBytes +
4637 dataLen - i - 1);
4643 else
4645 SetLastError(CRYPT_E_ASN1_BADTAG);
4646 ret = FALSE;
4648 return ret;
4651 static BOOL WINAPI CRYPT_AsnDecodeUnsignedInteger(DWORD dwCertEncodingType,
4652 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4653 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4655 BOOL ret;
4657 __TRY
4659 DWORD bytesNeeded;
4661 if ((ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType,
4662 lpszStructType, pbEncoded, cbEncoded,
4663 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, NULL, &bytesNeeded)))
4665 if (!pvStructInfo)
4666 *pcbStructInfo = bytesNeeded;
4667 else if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4668 pvStructInfo, pcbStructInfo, bytesNeeded)))
4670 CRYPT_INTEGER_BLOB *blob;
4672 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4673 pvStructInfo = *(BYTE **)pvStructInfo;
4674 blob = (CRYPT_INTEGER_BLOB *)pvStructInfo;
4675 blob->pbData = (BYTE *)pvStructInfo +
4676 sizeof(CRYPT_INTEGER_BLOB);
4677 ret = CRYPT_AsnDecodeUnsignedIntegerInternal(dwCertEncodingType,
4678 lpszStructType, pbEncoded, cbEncoded,
4679 dwFlags & ~CRYPT_ENCODE_ALLOC_FLAG, NULL, pvStructInfo,
4680 &bytesNeeded);
4684 __EXCEPT_PAGE_FAULT
4686 SetLastError(STATUS_ACCESS_VIOLATION);
4687 ret = FALSE;
4689 __ENDTRY
4690 return ret;
4693 static BOOL WINAPI CRYPT_AsnDecodeEnumerated(DWORD dwCertEncodingType,
4694 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4695 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4697 BOOL ret;
4699 if (!pvStructInfo)
4701 *pcbStructInfo = sizeof(int);
4702 return TRUE;
4704 __TRY
4706 if (pbEncoded[0] == ASN_ENUMERATED)
4708 unsigned int val = 0, i;
4710 if (cbEncoded <= 1)
4712 SetLastError(CRYPT_E_ASN1_EOD);
4713 ret = FALSE;
4715 else if (pbEncoded[1] == 0)
4717 SetLastError(CRYPT_E_ASN1_CORRUPT);
4718 ret = FALSE;
4720 else
4722 /* A little strange looking, but we have to accept a sign byte:
4723 * 0xffffffff gets encoded as 0a 05 00 ff ff ff ff. Also,
4724 * assuming a small length is okay here, it has to be in short
4725 * form.
4727 if (pbEncoded[1] > sizeof(unsigned int) + 1)
4729 SetLastError(CRYPT_E_ASN1_LARGE);
4730 return FALSE;
4732 for (i = 0; i < pbEncoded[1]; i++)
4734 val <<= 8;
4735 val |= pbEncoded[2 + i];
4737 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
4738 pvStructInfo, pcbStructInfo, sizeof(unsigned int))))
4740 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4741 pvStructInfo = *(BYTE **)pvStructInfo;
4742 memcpy(pvStructInfo, &val, sizeof(unsigned int));
4746 else
4748 SetLastError(CRYPT_E_ASN1_BADTAG);
4749 ret = FALSE;
4752 __EXCEPT_PAGE_FAULT
4754 SetLastError(STATUS_ACCESS_VIOLATION);
4755 ret = FALSE;
4757 __ENDTRY
4758 return ret;
4761 /* Modifies word, pbEncoded, and len, and magically sets a value ret to FALSE
4762 * if it fails.
4764 #define CRYPT_TIME_GET_DIGITS(pbEncoded, len, numDigits, word) \
4765 do { \
4766 BYTE i; \
4768 (word) = 0; \
4769 for (i = 0; (len) > 0 && i < (numDigits); i++, (len)--) \
4771 if (!isdigit(*(pbEncoded))) \
4773 SetLastError(CRYPT_E_ASN1_CORRUPT); \
4774 ret = FALSE; \
4776 else \
4778 (word) *= 10; \
4779 (word) += *(pbEncoded)++ - '0'; \
4782 } while (0)
4784 static BOOL CRYPT_AsnDecodeTimeZone(const BYTE *pbEncoded, DWORD len,
4785 SYSTEMTIME *sysTime)
4787 BOOL ret;
4789 __TRY
4791 ret = TRUE;
4792 if (len >= 3 && (*pbEncoded == '+' || *pbEncoded == '-'))
4794 WORD hours, minutes = 0;
4795 BYTE sign = *pbEncoded++;
4797 len--;
4798 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, hours);
4799 if (ret && hours >= 24)
4801 SetLastError(CRYPT_E_ASN1_CORRUPT);
4802 ret = FALSE;
4804 else if (len >= 2)
4806 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, minutes);
4807 if (ret && minutes >= 60)
4809 SetLastError(CRYPT_E_ASN1_CORRUPT);
4810 ret = FALSE;
4813 if (ret)
4815 if (sign == '+')
4817 sysTime->wHour += hours;
4818 sysTime->wMinute += minutes;
4820 else
4822 if (hours > sysTime->wHour)
4824 sysTime->wDay--;
4825 sysTime->wHour = 24 - (hours - sysTime->wHour);
4827 else
4828 sysTime->wHour -= hours;
4829 if (minutes > sysTime->wMinute)
4831 sysTime->wHour--;
4832 sysTime->wMinute = 60 - (minutes - sysTime->wMinute);
4834 else
4835 sysTime->wMinute -= minutes;
4840 __EXCEPT_PAGE_FAULT
4842 SetLastError(STATUS_ACCESS_VIOLATION);
4843 ret = FALSE;
4845 __ENDTRY
4846 return ret;
4849 #define MIN_ENCODED_TIME_LENGTH 10
4851 static BOOL WINAPI CRYPT_AsnDecodeUtcTime(DWORD dwCertEncodingType,
4852 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4853 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4855 BOOL ret;
4857 if (!pvStructInfo)
4859 *pcbStructInfo = sizeof(FILETIME);
4860 return TRUE;
4862 __TRY
4864 ret = TRUE;
4865 if (pbEncoded[0] == ASN_UTCTIME)
4867 if (cbEncoded <= 1)
4869 SetLastError(CRYPT_E_ASN1_EOD);
4870 ret = FALSE;
4872 else if (pbEncoded[1] > 0x7f)
4874 /* long-form date strings really can't be valid */
4875 SetLastError(CRYPT_E_ASN1_CORRUPT);
4876 ret = FALSE;
4878 else
4880 SYSTEMTIME sysTime = { 0 };
4881 BYTE len = pbEncoded[1];
4883 if (len < MIN_ENCODED_TIME_LENGTH)
4885 SetLastError(CRYPT_E_ASN1_CORRUPT);
4886 ret = FALSE;
4888 else
4890 pbEncoded += 2;
4891 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wYear);
4892 if (sysTime.wYear >= 50)
4893 sysTime.wYear += 1900;
4894 else
4895 sysTime.wYear += 2000;
4896 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
4897 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
4898 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
4899 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMinute);
4900 if (ret && len > 0)
4902 if (len >= 2 && isdigit(*pbEncoded) &&
4903 isdigit(*(pbEncoded + 1)))
4904 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4905 sysTime.wSecond);
4906 else if (isdigit(*pbEncoded))
4907 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 1,
4908 sysTime.wSecond);
4909 if (ret)
4910 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
4911 &sysTime);
4913 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
4914 pDecodePara, pvStructInfo, pcbStructInfo,
4915 sizeof(FILETIME))))
4917 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
4918 pvStructInfo = *(BYTE **)pvStructInfo;
4919 ret = SystemTimeToFileTime(&sysTime,
4920 (FILETIME *)pvStructInfo);
4925 else
4927 SetLastError(CRYPT_E_ASN1_BADTAG);
4928 ret = FALSE;
4931 __EXCEPT_PAGE_FAULT
4933 SetLastError(STATUS_ACCESS_VIOLATION);
4934 ret = FALSE;
4936 __ENDTRY
4937 return ret;
4940 static BOOL WINAPI CRYPT_AsnDecodeGeneralizedTime(DWORD dwCertEncodingType,
4941 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
4942 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
4944 BOOL ret;
4946 if (!pvStructInfo)
4948 *pcbStructInfo = sizeof(FILETIME);
4949 return TRUE;
4951 __TRY
4953 ret = TRUE;
4954 if (pbEncoded[0] == ASN_GENERALTIME)
4956 if (cbEncoded <= 1)
4958 SetLastError(CRYPT_E_ASN1_EOD);
4959 ret = FALSE;
4961 else if (pbEncoded[1] > 0x7f)
4963 /* long-form date strings really can't be valid */
4964 SetLastError(CRYPT_E_ASN1_CORRUPT);
4965 ret = FALSE;
4967 else
4969 BYTE len = pbEncoded[1];
4971 if (len < MIN_ENCODED_TIME_LENGTH)
4973 SetLastError(CRYPT_E_ASN1_CORRUPT);
4974 ret = FALSE;
4976 else
4978 SYSTEMTIME sysTime = { 0 };
4980 pbEncoded += 2;
4981 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 4, sysTime.wYear);
4982 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wMonth);
4983 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wDay);
4984 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2, sysTime.wHour);
4985 if (ret && len > 0)
4987 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4988 sysTime.wMinute);
4989 if (ret && len > 0)
4990 CRYPT_TIME_GET_DIGITS(pbEncoded, len, 2,
4991 sysTime.wSecond);
4992 if (ret && len > 0 && (*pbEncoded == '.' ||
4993 *pbEncoded == ','))
4995 BYTE digits;
4997 pbEncoded++;
4998 len--;
4999 /* workaround macro weirdness */
5000 digits = min(len, 3);
5001 CRYPT_TIME_GET_DIGITS(pbEncoded, len, digits,
5002 sysTime.wMilliseconds);
5004 if (ret)
5005 ret = CRYPT_AsnDecodeTimeZone(pbEncoded, len,
5006 &sysTime);
5008 if (ret && (ret = CRYPT_DecodeEnsureSpace(dwFlags,
5009 pDecodePara, pvStructInfo, pcbStructInfo,
5010 sizeof(FILETIME))))
5012 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5013 pvStructInfo = *(BYTE **)pvStructInfo;
5014 ret = SystemTimeToFileTime(&sysTime,
5015 (FILETIME *)pvStructInfo);
5020 else
5022 SetLastError(CRYPT_E_ASN1_BADTAG);
5023 ret = FALSE;
5026 __EXCEPT_PAGE_FAULT
5028 SetLastError(STATUS_ACCESS_VIOLATION);
5029 ret = FALSE;
5031 __ENDTRY
5032 return ret;
5035 static BOOL WINAPI CRYPT_AsnDecodeChoiceOfTime(DWORD dwCertEncodingType,
5036 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5037 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5039 BOOL ret;
5041 __TRY
5043 if (pbEncoded[0] == ASN_UTCTIME)
5044 ret = CRYPT_AsnDecodeUtcTime(dwCertEncodingType, lpszStructType,
5045 pbEncoded, cbEncoded, dwFlags, pDecodePara, pvStructInfo,
5046 pcbStructInfo);
5047 else if (pbEncoded[0] == ASN_GENERALTIME)
5048 ret = CRYPT_AsnDecodeGeneralizedTime(dwCertEncodingType,
5049 lpszStructType, pbEncoded, cbEncoded, dwFlags, pDecodePara,
5050 pvStructInfo, pcbStructInfo);
5051 else
5053 SetLastError(CRYPT_E_ASN1_BADTAG);
5054 ret = FALSE;
5057 __EXCEPT_PAGE_FAULT
5059 SetLastError(STATUS_ACCESS_VIOLATION);
5060 ret = FALSE;
5062 __ENDTRY
5063 return ret;
5066 static BOOL WINAPI CRYPT_AsnDecodeSequenceOfAny(DWORD dwCertEncodingType,
5067 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5068 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5070 BOOL ret = TRUE;
5072 __TRY
5074 if (pbEncoded[0] == ASN_SEQUENCEOF)
5076 DWORD bytesNeeded, dataLen, remainingLen, cValue;
5078 if ((ret = CRYPT_GetLen(pbEncoded, cbEncoded, &dataLen)))
5080 BYTE lenBytes;
5081 const BYTE *ptr;
5083 lenBytes = GET_LEN_BYTES(pbEncoded[1]);
5084 bytesNeeded = sizeof(CRYPT_SEQUENCE_OF_ANY);
5085 cValue = 0;
5086 ptr = pbEncoded + 1 + lenBytes;
5087 remainingLen = dataLen;
5088 while (ret && remainingLen)
5090 DWORD nextLen;
5092 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5093 if (ret)
5095 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5097 remainingLen -= 1 + nextLenBytes + nextLen;
5098 ptr += 1 + nextLenBytes + nextLen;
5099 bytesNeeded += sizeof(CRYPT_DER_BLOB);
5100 if (!(dwFlags & CRYPT_DECODE_NOCOPY_FLAG))
5101 bytesNeeded += 1 + nextLenBytes + nextLen;
5102 cValue++;
5105 if (ret)
5107 CRYPT_SEQUENCE_OF_ANY *seq;
5108 BYTE *nextPtr;
5109 DWORD i;
5111 if ((ret = CRYPT_DecodeEnsureSpace(dwFlags, pDecodePara,
5112 pvStructInfo, pcbStructInfo, bytesNeeded)))
5114 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG)
5115 pvStructInfo = *(BYTE **)pvStructInfo;
5116 seq = (CRYPT_SEQUENCE_OF_ANY *)pvStructInfo;
5117 seq->cValue = cValue;
5118 seq->rgValue = (CRYPT_DER_BLOB *)((BYTE *)seq +
5119 sizeof(*seq));
5120 nextPtr = (BYTE *)seq->rgValue +
5121 cValue * sizeof(CRYPT_DER_BLOB);
5122 ptr = pbEncoded + 1 + lenBytes;
5123 remainingLen = dataLen;
5124 i = 0;
5125 while (ret && remainingLen)
5127 DWORD nextLen;
5129 ret = CRYPT_GetLen(ptr, remainingLen, &nextLen);
5130 if (ret)
5132 DWORD nextLenBytes = GET_LEN_BYTES(ptr[1]);
5134 seq->rgValue[i].cbData = 1 + nextLenBytes +
5135 nextLen;
5136 if (dwFlags & CRYPT_DECODE_NOCOPY_FLAG)
5137 seq->rgValue[i].pbData = (BYTE *)ptr;
5138 else
5140 seq->rgValue[i].pbData = nextPtr;
5141 memcpy(nextPtr, ptr, 1 + nextLenBytes +
5142 nextLen);
5143 nextPtr += 1 + nextLenBytes + nextLen;
5145 remainingLen -= 1 + nextLenBytes + nextLen;
5146 ptr += 1 + nextLenBytes + nextLen;
5147 i++;
5154 else
5156 SetLastError(CRYPT_E_ASN1_BADTAG);
5157 return FALSE;
5160 __EXCEPT_PAGE_FAULT
5162 SetLastError(STATUS_ACCESS_VIOLATION);
5163 ret = FALSE;
5165 __ENDTRY
5166 return ret;
5169 static BOOL WINAPI CRYPT_AsnDecodeDistPoint(DWORD dwCertEncodingType,
5170 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5171 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5173 struct AsnDecodeSequenceItem items[] = {
5174 { ASN_CONTEXT | ASN_CONSTRUCTOR | 0, offsetof(CRL_DIST_POINT,
5175 DistPointName), CRYPT_AsnDecodeAltNameInternal,
5176 sizeof(CRL_DIST_POINT_NAME), TRUE, TRUE, offsetof(CRL_DIST_POINT,
5177 DistPointName.u.FullName.rgAltEntry), 0 },
5178 { ASN_CONTEXT | 1, offsetof(CRL_DIST_POINT, ReasonFlags),
5179 CRYPT_AsnDecodeBitsInternal, sizeof(CRYPT_BIT_BLOB), TRUE, TRUE,
5180 offsetof(CRL_DIST_POINT, ReasonFlags.pbData), 0 },
5181 { ASN_CONTEXT | ASN_CONSTRUCTOR | 2, offsetof(CRL_DIST_POINT, CRLIssuer),
5182 CRYPT_AsnDecodeAltNameInternal, sizeof(CERT_ALT_NAME_INFO), TRUE, TRUE,
5183 offsetof(CRL_DIST_POINT, CRLIssuer.rgAltEntry), 0 },
5185 BOOL ret;
5187 ret = CRYPT_AsnDecodeSequence(dwCertEncodingType, items,
5188 sizeof(items) / sizeof(items[0]), pbEncoded, cbEncoded,
5189 dwFlags, pDecodePara, pvStructInfo, pcbStructInfo, NULL);
5190 return ret;
5193 static BOOL WINAPI CRYPT_AsnDecodeCRLDistPoints(DWORD dwCertEncodingType,
5194 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5195 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5197 BOOL ret;
5199 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
5200 pDecodePara, pvStructInfo, *pcbStructInfo);
5202 __TRY
5204 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
5205 CRYPT_AsnDecodeDistPoint, sizeof(CRL_DIST_POINT), TRUE,
5206 offsetof(CRL_DIST_POINT, DistPointName.u.FullName.rgAltEntry) };
5208 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
5209 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
5211 __EXCEPT_PAGE_FAULT
5213 SetLastError(STATUS_ACCESS_VIOLATION);
5214 ret = FALSE;
5216 __ENDTRY
5217 return ret;
5220 static BOOL WINAPI CRYPT_AsnDecodeEnhancedKeyUsage(DWORD dwCertEncodingType,
5221 LPCSTR lpszStructType, const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5222 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5224 BOOL ret;
5226 TRACE("%p, %ld, %08lx, %p, %p, %ld\n", pbEncoded, cbEncoded, dwFlags,
5227 pDecodePara, pvStructInfo, *pcbStructInfo);
5229 __TRY
5231 struct AsnArrayDescriptor arrayDesc = { ASN_SEQUENCEOF,
5232 CRYPT_AsnDecodeOidInternal, sizeof(LPSTR), TRUE, 0 };
5234 ret = CRYPT_AsnDecodeArray(&arrayDesc, pbEncoded, cbEncoded, dwFlags,
5235 pDecodePara, pvStructInfo, pcbStructInfo, NULL);
5237 __EXCEPT_PAGE_FAULT
5239 SetLastError(STATUS_ACCESS_VIOLATION);
5240 ret = FALSE;
5242 __ENDTRY
5243 return ret;
5246 BOOL WINAPI CryptDecodeObjectEx(DWORD dwCertEncodingType, LPCSTR lpszStructType,
5247 const BYTE *pbEncoded, DWORD cbEncoded, DWORD dwFlags,
5248 PCRYPT_DECODE_PARA pDecodePara, void *pvStructInfo, DWORD *pcbStructInfo)
5250 static HCRYPTOIDFUNCSET set = NULL;
5251 BOOL ret = FALSE;
5252 CryptDecodeObjectExFunc decodeFunc = NULL;
5253 HCRYPTOIDFUNCADDR hFunc = NULL;
5255 TRACE("(0x%08lx, %s, %p, %ld, 0x%08lx, %p, %p, %p)\n",
5256 dwCertEncodingType, debugstr_a(lpszStructType), pbEncoded,
5257 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5259 if (!pvStructInfo && !pcbStructInfo)
5261 SetLastError(ERROR_INVALID_PARAMETER);
5262 return FALSE;
5264 if ((dwCertEncodingType & CERT_ENCODING_TYPE_MASK) != X509_ASN_ENCODING
5265 && (dwCertEncodingType & CMSG_ENCODING_TYPE_MASK) != PKCS_7_ASN_ENCODING)
5267 SetLastError(ERROR_FILE_NOT_FOUND);
5268 return FALSE;
5270 if (!cbEncoded)
5272 SetLastError(CRYPT_E_ASN1_EOD);
5273 return FALSE;
5275 if (cbEncoded > MAX_ENCODED_LEN)
5277 SetLastError(CRYPT_E_ASN1_LARGE);
5278 return FALSE;
5281 SetLastError(NOERROR);
5282 if (dwFlags & CRYPT_DECODE_ALLOC_FLAG && pvStructInfo)
5283 *(BYTE **)pvStructInfo = NULL;
5284 if (!HIWORD(lpszStructType))
5286 switch (LOWORD(lpszStructType))
5288 case (WORD)X509_CERT:
5289 decodeFunc = CRYPT_AsnDecodeCert;
5290 break;
5291 case (WORD)X509_CERT_TO_BE_SIGNED:
5292 decodeFunc = CRYPT_AsnDecodeCertInfo;
5293 break;
5294 case (WORD)X509_CERT_CRL_TO_BE_SIGNED:
5295 decodeFunc = CRYPT_AsnDecodeCRLInfo;
5296 break;
5297 case (WORD)X509_EXTENSIONS:
5298 decodeFunc = CRYPT_AsnDecodeExtensions;
5299 break;
5300 case (WORD)X509_NAME:
5301 decodeFunc = CRYPT_AsnDecodeName;
5302 break;
5303 case (WORD)X509_PUBLIC_KEY_INFO:
5304 decodeFunc = CRYPT_AsnDecodePubKeyInfo;
5305 break;
5306 case (WORD)X509_ALTERNATE_NAME:
5307 decodeFunc = CRYPT_AsnDecodeAltName;
5308 break;
5309 case (WORD)X509_BASIC_CONSTRAINTS:
5310 decodeFunc = CRYPT_AsnDecodeBasicConstraints;
5311 break;
5312 case (WORD)X509_BASIC_CONSTRAINTS2:
5313 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5314 break;
5315 case (WORD)RSA_CSP_PUBLICKEYBLOB:
5316 decodeFunc = CRYPT_AsnDecodeRsaPubKey;
5317 break;
5318 case (WORD)X509_OCTET_STRING:
5319 decodeFunc = CRYPT_AsnDecodeOctets;
5320 break;
5321 case (WORD)X509_BITS:
5322 case (WORD)X509_KEY_USAGE:
5323 decodeFunc = CRYPT_AsnDecodeBits;
5324 break;
5325 case (WORD)X509_INTEGER:
5326 decodeFunc = CRYPT_AsnDecodeInt;
5327 break;
5328 case (WORD)X509_MULTI_BYTE_INTEGER:
5329 decodeFunc = CRYPT_AsnDecodeInteger;
5330 break;
5331 case (WORD)X509_MULTI_BYTE_UINT:
5332 decodeFunc = CRYPT_AsnDecodeUnsignedInteger;
5333 break;
5334 case (WORD)X509_ENUMERATED:
5335 decodeFunc = CRYPT_AsnDecodeEnumerated;
5336 break;
5337 case (WORD)X509_CHOICE_OF_TIME:
5338 decodeFunc = CRYPT_AsnDecodeChoiceOfTime;
5339 break;
5340 case (WORD)X509_SEQUENCE_OF_ANY:
5341 decodeFunc = CRYPT_AsnDecodeSequenceOfAny;
5342 break;
5343 case (WORD)PKCS_UTC_TIME:
5344 decodeFunc = CRYPT_AsnDecodeUtcTime;
5345 break;
5346 case (WORD)X509_CRL_DIST_POINTS:
5347 decodeFunc = CRYPT_AsnDecodeCRLDistPoints;
5348 break;
5349 case (WORD)X509_ENHANCED_KEY_USAGE:
5350 decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage;
5351 break;
5352 default:
5353 FIXME("%d: unimplemented\n", LOWORD(lpszStructType));
5356 else if (!strcmp(lpszStructType, szOID_CERT_EXTENSIONS))
5357 decodeFunc = CRYPT_AsnDecodeExtensions;
5358 else if (!strcmp(lpszStructType, szOID_RSA_signingTime))
5359 decodeFunc = CRYPT_AsnDecodeUtcTime;
5360 else if (!strcmp(lpszStructType, szOID_CRL_REASON_CODE))
5361 decodeFunc = CRYPT_AsnDecodeEnumerated;
5362 else if (!strcmp(lpszStructType, szOID_KEY_USAGE))
5363 decodeFunc = CRYPT_AsnDecodeBits;
5364 else if (!strcmp(lpszStructType, szOID_SUBJECT_KEY_IDENTIFIER))
5365 decodeFunc = CRYPT_AsnDecodeOctets;
5366 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS))
5367 decodeFunc = CRYPT_AsnDecodeBasicConstraints;
5368 else if (!strcmp(lpszStructType, szOID_BASIC_CONSTRAINTS2))
5369 decodeFunc = CRYPT_AsnDecodeBasicConstraints2;
5370 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME))
5371 decodeFunc = CRYPT_AsnDecodeAltName;
5372 else if (!strcmp(lpszStructType, szOID_ISSUER_ALT_NAME2))
5373 decodeFunc = CRYPT_AsnDecodeAltName;
5374 else if (!strcmp(lpszStructType, szOID_NEXT_UPDATE_LOCATION))
5375 decodeFunc = CRYPT_AsnDecodeAltName;
5376 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME))
5377 decodeFunc = CRYPT_AsnDecodeAltName;
5378 else if (!strcmp(lpszStructType, szOID_SUBJECT_ALT_NAME2))
5379 decodeFunc = CRYPT_AsnDecodeAltName;
5380 else if (!strcmp(lpszStructType, szOID_CRL_DIST_POINTS))
5381 decodeFunc = CRYPT_AsnDecodeCRLDistPoints;
5382 else if (!strcmp(lpszStructType, szOID_ENHANCED_KEY_USAGE))
5383 decodeFunc = CRYPT_AsnDecodeEnhancedKeyUsage;
5384 else
5385 TRACE("OID %s not found or unimplemented, looking for DLL\n",
5386 debugstr_a(lpszStructType));
5387 if (!decodeFunc)
5389 if (!set)
5390 set = CryptInitOIDFunctionSet(CRYPT_OID_DECODE_OBJECT_EX_FUNC, 0);
5391 CryptGetOIDFunctionAddress(set, dwCertEncodingType, lpszStructType, 0,
5392 (void **)&decodeFunc, &hFunc);
5394 if (decodeFunc)
5395 ret = decodeFunc(dwCertEncodingType, lpszStructType, pbEncoded,
5396 cbEncoded, dwFlags, pDecodePara, pvStructInfo, pcbStructInfo);
5397 else
5398 SetLastError(ERROR_FILE_NOT_FOUND);
5399 if (hFunc)
5400 CryptFreeOIDFunctionAddress(hFunc, 0);
5401 return ret;
5404 BOOL WINAPI CryptExportPublicKeyInfo(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
5405 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5407 return CryptExportPublicKeyInfoEx(hCryptProv, dwKeySpec, dwCertEncodingType,
5408 NULL, 0, NULL, pInfo, pcbInfo);
5411 static BOOL WINAPI CRYPT_ExportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5412 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
5413 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5415 BOOL ret;
5416 HCRYPTKEY key;
5418 TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
5419 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
5420 pInfo, pcbInfo);
5422 if (!pszPublicKeyObjId)
5423 pszPublicKeyObjId = szOID_RSA_RSA;
5424 if ((ret = CryptGetUserKey(hCryptProv, dwKeySpec, &key)))
5426 DWORD keySize = 0;
5428 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, NULL, &keySize);
5429 if (ret)
5431 LPBYTE pubKey = CryptMemAlloc(keySize);
5433 if (pubKey)
5435 ret = CryptExportKey(key, 0, PUBLICKEYBLOB, 0, pubKey,
5436 &keySize);
5437 if (ret)
5439 DWORD encodedLen = 0;
5441 ret = CryptEncodeObject(dwCertEncodingType,
5442 RSA_CSP_PUBLICKEYBLOB, pubKey, NULL, &encodedLen);
5443 if (ret)
5445 DWORD sizeNeeded = sizeof(CERT_PUBLIC_KEY_INFO) +
5446 strlen(pszPublicKeyObjId) + 1 + encodedLen;
5448 if (!pInfo)
5449 *pcbInfo = sizeNeeded;
5450 else if (*pcbInfo < sizeNeeded)
5452 SetLastError(ERROR_MORE_DATA);
5453 *pcbInfo = sizeNeeded;
5454 ret = FALSE;
5456 else
5458 pInfo->Algorithm.pszObjId = (char *)pInfo +
5459 sizeof(CERT_PUBLIC_KEY_INFO);
5460 lstrcpyA(pInfo->Algorithm.pszObjId,
5461 pszPublicKeyObjId);
5462 pInfo->Algorithm.Parameters.cbData = 0;
5463 pInfo->Algorithm.Parameters.pbData = NULL;
5464 pInfo->PublicKey.pbData =
5465 (BYTE *)pInfo->Algorithm.pszObjId
5466 + lstrlenA(pInfo->Algorithm.pszObjId) + 1;
5467 pInfo->PublicKey.cbData = encodedLen;
5468 pInfo->PublicKey.cUnusedBits = 0;
5469 ret = CryptEncodeObject(dwCertEncodingType,
5470 RSA_CSP_PUBLICKEYBLOB, pubKey,
5471 pInfo->PublicKey.pbData, &pInfo->PublicKey.cbData);
5475 CryptMemFree(pubKey);
5477 else
5478 ret = FALSE;
5480 CryptDestroyKey(key);
5482 return ret;
5485 typedef BOOL (WINAPI *ExportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
5486 DWORD dwKeySpec, DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId,
5487 DWORD dwFlags, void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo);
5489 BOOL WINAPI CryptExportPublicKeyInfoEx(HCRYPTPROV hCryptProv, DWORD dwKeySpec,
5490 DWORD dwCertEncodingType, LPSTR pszPublicKeyObjId, DWORD dwFlags,
5491 void *pvAuxInfo, PCERT_PUBLIC_KEY_INFO pInfo, DWORD *pcbInfo)
5493 static HCRYPTOIDFUNCSET set = NULL;
5494 BOOL ret;
5495 ExportPublicKeyInfoExFunc exportFunc = NULL;
5496 HCRYPTOIDFUNCADDR hFunc = NULL;
5498 TRACE("(%ld, %ld, %08lx, %s, %08lx, %p, %p, %p)\n", hCryptProv, dwKeySpec,
5499 dwCertEncodingType, debugstr_a(pszPublicKeyObjId), dwFlags, pvAuxInfo,
5500 pInfo, pcbInfo);
5502 if (!hCryptProv)
5504 SetLastError(ERROR_INVALID_PARAMETER);
5505 return FALSE;
5508 if (pszPublicKeyObjId)
5510 if (!set)
5511 set = CryptInitOIDFunctionSet(CRYPT_OID_EXPORT_PUBLIC_KEY_INFO_FUNC,
5513 CryptGetOIDFunctionAddress(set, dwCertEncodingType, pszPublicKeyObjId,
5514 0, (void **)&exportFunc, &hFunc);
5516 if (!exportFunc)
5517 exportFunc = CRYPT_ExportRsaPublicKeyInfoEx;
5518 ret = exportFunc(hCryptProv, dwKeySpec, dwCertEncodingType,
5519 pszPublicKeyObjId, dwFlags, pvAuxInfo, pInfo, pcbInfo);
5520 if (hFunc)
5521 CryptFreeOIDFunctionAddress(hFunc, 0);
5522 return ret;
5525 BOOL WINAPI CryptImportPublicKeyInfo(HCRYPTPROV hCryptProv,
5526 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, HCRYPTKEY *phKey)
5528 return CryptImportPublicKeyInfoEx(hCryptProv, dwCertEncodingType, pInfo,
5529 0, 0, NULL, phKey);
5532 static BOOL WINAPI CRYPT_ImportRsaPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5533 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5534 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
5536 BOOL ret;
5537 DWORD pubKeySize = 0;
5539 TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
5540 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
5542 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
5543 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, NULL, &pubKeySize);
5544 if (ret)
5546 LPBYTE pubKey = CryptMemAlloc(pubKeySize);
5548 if (pubKey)
5550 ret = CryptDecodeObject(dwCertEncodingType, RSA_CSP_PUBLICKEYBLOB,
5551 pInfo->PublicKey.pbData, pInfo->PublicKey.cbData, 0, pubKey,
5552 &pubKeySize);
5553 if (ret)
5554 ret = CryptImportKey(hCryptProv, pubKey, pubKeySize, 0, 0,
5555 phKey);
5556 CryptMemFree(pubKey);
5558 else
5559 ret = FALSE;
5561 return ret;
5564 typedef BOOL (WINAPI *ImportPublicKeyInfoExFunc)(HCRYPTPROV hCryptProv,
5565 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5566 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey);
5568 BOOL WINAPI CryptImportPublicKeyInfoEx(HCRYPTPROV hCryptProv,
5569 DWORD dwCertEncodingType, PCERT_PUBLIC_KEY_INFO pInfo, ALG_ID aiKeyAlg,
5570 DWORD dwFlags, void *pvAuxInfo, HCRYPTKEY *phKey)
5572 static HCRYPTOIDFUNCSET set = NULL;
5573 BOOL ret;
5574 ImportPublicKeyInfoExFunc importFunc = NULL;
5575 HCRYPTOIDFUNCADDR hFunc = NULL;
5577 TRACE("(%ld, %ld, %p, %d, %08lx, %p, %p)\n", hCryptProv,
5578 dwCertEncodingType, pInfo, aiKeyAlg, dwFlags, pvAuxInfo, phKey);
5580 if (!set)
5581 set = CryptInitOIDFunctionSet(CRYPT_OID_IMPORT_PUBLIC_KEY_INFO_FUNC, 0);
5582 CryptGetOIDFunctionAddress(set, dwCertEncodingType,
5583 pInfo->Algorithm.pszObjId, 0, (void **)&importFunc, &hFunc);
5584 if (!importFunc)
5585 importFunc = CRYPT_ImportRsaPublicKeyInfoEx;
5586 ret = importFunc(hCryptProv, dwCertEncodingType, pInfo, aiKeyAlg, dwFlags,
5587 pvAuxInfo, phKey);
5588 if (hFunc)
5589 CryptFreeOIDFunctionAddress(hFunc, 0);
5590 return ret;